Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
<CompressionEnabled>false</CompressionEnabled>
|
<CompressionEnabled>false</CompressionEnabled>
|
||||||
<StaticWebAssetsFingerprintContent>false</StaticWebAssetsFingerprintContent>
|
<StaticWebAssetsFingerprintContent>false</StaticWebAssetsFingerprintContent>
|
||||||
<BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException>
|
<BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException>
|
||||||
|
<RequiresAspNetWebAssets>true</RequiresAspNetWebAssets>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ else
|
|||||||
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
new Stylesheet(ModulePath() + "[Owner].Module.[Module]/Module.css"),
|
new Stylesheet(ModulePath() + "Module.css"),
|
||||||
new Script(ModulePath() + "[Owner].Module.[Module]/Module.js")
|
new Script(ModulePath() + "Module.js")
|
||||||
};
|
};
|
||||||
|
|
||||||
List<[Module]> _[Module]s;
|
List<[Module]> _[Module]s;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@namespace Oqtane.Modules.Admin.ModuleDefinitions
|
@namespace Oqtane.Modules.Admin.ModuleDefinitions
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@using System.Text.RegularExpressions
|
@using System.Text.RegularExpressions
|
||||||
|
@using System.Reflection
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IModuleDefinitionService ModuleDefinitionService
|
@inject IModuleDefinitionService ModuleDefinitionService
|
||||||
@inject IModuleService ModuleService
|
@inject IModuleService ModuleService
|
||||||
@@ -84,7 +85,7 @@
|
|||||||
private List<Template> _templates;
|
private List<Template> _templates;
|
||||||
private string _template = "-";
|
private string _template = "-";
|
||||||
private string _minversion = "2.0.0";
|
private string _minversion = "2.0.0";
|
||||||
private string _type = "External";
|
private string _type = "";
|
||||||
private string[] _versions;
|
private string[] _versions;
|
||||||
private string _reference = "local";
|
private string _reference = "local";
|
||||||
private string _location = string.Empty;
|
private string _location = string.Empty;
|
||||||
@@ -97,6 +98,16 @@
|
|||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Info.Module.Development"], MessageType.Info);
|
AddModuleMessage(Localizer["Info.Module.Development"], MessageType.Info);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var entryAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
|
||||||
|
if (entryAssemblyName.EndsWith(".Oqtane"))
|
||||||
|
{
|
||||||
|
// Oqtane Application assemblies end with .Server.Oqtane or .Client.Oqtane
|
||||||
|
string[] segments = entryAssemblyName.Split('.');
|
||||||
|
_owner = string.Join(".", segments, 0, segments.Length - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
@@ -127,11 +138,18 @@
|
|||||||
if (string.IsNullOrEmpty(_description)) _description = _module;
|
if (string.IsNullOrEmpty(_description)) _description = _module;
|
||||||
if (IsValidXML(_description))
|
if (IsValidXML(_description))
|
||||||
{
|
{
|
||||||
|
if (_type == "Internal")
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Success.Module.Create.Internal"], MessageType.Success);
|
||||||
|
}
|
||||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||||
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference, ModuleDefinitionName = template.Namespace };
|
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference, ModuleDefinitionName = template.Namespace };
|
||||||
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
||||||
GetLocation();
|
if (_type == "External")
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Module.Create"], NavigateUrl("admin/system")), MessageType.Success);
|
{
|
||||||
|
GetLocation();
|
||||||
|
AddModuleMessage(string.Format(Localizer["Success.Module.Create.External"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -178,7 +196,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_minversion = "2.0.0";
|
_minversion = "2.0.0";
|
||||||
_type = "External";
|
_type = "";
|
||||||
}
|
}
|
||||||
GetLocation();
|
GetLocation();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@namespace Oqtane.Modules.Admin.Themes
|
@namespace Oqtane.Modules.Admin.Themes
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@using System.Text.RegularExpressions
|
@using System.Text.RegularExpressions
|
||||||
|
@using System.Reflection
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
@inject IModuleService ModuleService
|
@inject IModuleService ModuleService
|
||||||
@@ -75,7 +76,7 @@
|
|||||||
private List<Template> _templates;
|
private List<Template> _templates;
|
||||||
private string _template = "-";
|
private string _template = "-";
|
||||||
private string _minversion = "2.0.0";
|
private string _minversion = "2.0.0";
|
||||||
private string _type = "External";
|
private string _type = "";
|
||||||
private string[] _versions;
|
private string[] _versions;
|
||||||
private string _reference = "local";
|
private string _reference = "local";
|
||||||
private string _location = string.Empty;
|
private string _location = string.Empty;
|
||||||
@@ -88,9 +89,19 @@
|
|||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Info.Theme.CreatorIntent"], MessageType.Info);
|
AddModuleMessage(Localizer["Info.Theme.CreatorIntent"], MessageType.Info);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var entryAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
|
||||||
|
if (entryAssemblyName.EndsWith(".Oqtane"))
|
||||||
|
{
|
||||||
|
// Oqtane Application assemblies end with .Server.Oqtane or .Client.Oqtane
|
||||||
|
string[] segments = entryAssemblyName.Split('.');
|
||||||
|
_owner = string.Join(".", segments, 0, segments.Length - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -109,11 +120,18 @@
|
|||||||
{
|
{
|
||||||
if (IsValid(_owner) && IsValid(_theme) && _owner != _theme && _template != "-")
|
if (IsValid(_owner) && IsValid(_theme) && _owner != _theme && _template != "-")
|
||||||
{
|
{
|
||||||
|
if (_type == "Internal")
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Success.Theme.Create.Internal"], MessageType.Success);
|
||||||
|
}
|
||||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||||
var theme = new Theme { Owner = _owner, Name = _theme, Template = _template, Version = _reference, ThemeName = template.Namespace };
|
var theme = new Theme { Owner = _owner, Name = _theme, Template = _template, Version = _reference, ThemeName = template.Namespace };
|
||||||
theme = await ThemeService.CreateThemeAsync(theme);
|
theme = await ThemeService.CreateThemeAsync(theme);
|
||||||
GetLocation();
|
if (_type == "External")
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Create"], NavigateUrl("admin/system")), MessageType.Success);
|
{
|
||||||
|
GetLocation();
|
||||||
|
AddModuleMessage(string.Format(Localizer["Success.Theme.Create.External"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -144,7 +162,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_minversion = "2.0.0";
|
_minversion = "2.0.0";
|
||||||
_type = "External";
|
_type = "";
|
||||||
}
|
}
|
||||||
GetLocation();
|
GetLocation();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@
|
|||||||
<value>You Must Provide A Valid Description (ie. No Punctuation)</value>
|
<value>You Must Provide A Valid Description (ie. No Punctuation)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="OwnerName.HelpText" xml:space="preserve">
|
<data name="OwnerName.HelpText" xml:space="preserve">
|
||||||
<value>Enter the name of the organization who is developing this module. It should not contain spaces or punctuation or contain the word "oqtane".</value>
|
<value>Enter the name of the organization who is developing this module. It should not contain spaces or punctuation or contain the word "oqtane". If you are using an Internal template then make sure the owner matches the name of the project.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModuleName.HelpText" xml:space="preserve">
|
<data name="ModuleName.HelpText" xml:space="preserve">
|
||||||
<value>Enter a name for this module. It should not contain spaces or punctuation or contain the word "oqtane".</value>
|
<value>Enter a name for this module. It should not contain spaces or punctuation or contain the word "oqtane".</value>
|
||||||
@@ -168,7 +168,10 @@
|
|||||||
<data name="Location.Text" xml:space="preserve">
|
<data name="Location.Text" xml:space="preserve">
|
||||||
<value>Location: </value>
|
<value>Location: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Module.Create" xml:space="preserve">
|
<data name="Success.Module.Create.Internal" xml:space="preserve">
|
||||||
|
<value>The Source Code For Your Module Has Been Created In Your Solution And Must Be Compiled In Order To Make It Functional</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Module.Create.External" xml:space="preserve">
|
||||||
<value>The Source Code For Your Module Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href={0}>Restart</a> Your Application To Activate The Module.</value>
|
<value>The Source Code For Your Module Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href={0}>Restart</a> Your Application To Activate The Module.</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -141,14 +141,17 @@
|
|||||||
<data name="Info.Theme.CreatorIntent" xml:space="preserve">
|
<data name="Info.Theme.CreatorIntent" xml:space="preserve">
|
||||||
<value>Please Note That The Theme Creator Is Only Intended To Be Used In A Development Environment</value>
|
<value>Please Note That The Theme Creator Is Only Intended To Be Used In A Development Environment</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Theme.Create" xml:space="preserve">
|
<data name="Success.Theme.Create.Internal" xml:space="preserve">
|
||||||
<value>The Source Code For Your Theme Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href={0}>Restart</a> Your Application To Activate The Module.</value>
|
<value>The Source Code For Your Theme Has Been Created In Your Solution And Must Be Compiled In Order To Make It Functional</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Theme.Create.External" xml:space="preserve">
|
||||||
|
<value>The Source Code For Your Theme Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href={0}>Restart</a> Your Application To Activate The Theme.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Required.ValidName" xml:space="preserve">
|
<data name="Message.Required.ValidName" xml:space="preserve">
|
||||||
<value>You Must Provide A Valid Owner Name And Theme Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template</value>
|
<value>You Must Provide A Valid Owner Name And Theme Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="OwnerName.HelpText" xml:space="preserve">
|
<data name="OwnerName.HelpText" xml:space="preserve">
|
||||||
<value>Enter the name of the organization who is developing this theme. It should not contain spaces or punctuation.</value>
|
<value>Enter the name of the organization who is developing this theme. It should not contain spaces or punctuation or contain the word "oqtane". If you are using an Internal template then make sure the owner matches the name of the project.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ThemeName.HelpText" xml:space="preserve">
|
<data name="ThemeName.HelpText" xml:space="preserve">
|
||||||
<value>Enter a name for this theme. It should not contain spaces or punctuation.</value>
|
<value>Enter a name for this theme. It should not contain spaces or punctuation.</value>
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ namespace Oqtane.UI
|
|||||||
public bool Refresh { get; set; }
|
public bool Refresh { get; set; }
|
||||||
public bool AllowCookies { get; set; }
|
public bool AllowCookies { get; set; }
|
||||||
|
|
||||||
|
public int? StatusCode { get; set; }
|
||||||
|
|
||||||
public List<Page> Pages
|
public List<Page> Pages
|
||||||
{
|
{
|
||||||
get { return Site?.Pages; }
|
get { return Site?.Pages; }
|
||||||
@@ -63,7 +65,8 @@ namespace Oqtane.UI
|
|||||||
IsInternalNavigation = IsInternalNavigation,
|
IsInternalNavigation = IsInternalNavigation,
|
||||||
RenderId = RenderId,
|
RenderId = RenderId,
|
||||||
Refresh = Refresh,
|
Refresh = Refresh,
|
||||||
AllowCookies = AllowCookies
|
AllowCookies = AllowCookies,
|
||||||
|
StatusCode = StatusCode
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,9 @@
|
|||||||
|
|
||||||
// verify user is authenticated for current site
|
// verify user is authenticated for current site
|
||||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||||
if (authState.User.Identity.IsAuthenticated && authState.User.Claims.Any(item => item.Type == Constants.SiteKeyClaimType && item.Value == SiteState.Alias.SiteKey))
|
if (authState.User.Identity.IsAuthenticated
|
||||||
|
&& authState.User.Claims.Any(item => item.Type == Constants.SiteKeyClaimType && item.Value == SiteState.Alias.SiteKey)
|
||||||
|
&& PageState.StatusCode != (int)HttpStatusCode.NotFound)
|
||||||
{
|
{
|
||||||
// get user
|
// get user
|
||||||
var userid = int.Parse(authState.User.Claims.First(item => item.Type == ClaimTypes.NameIdentifier).Value);
|
var userid = int.Parse(authState.User.Claims.First(item => item.Type == ClaimTypes.NameIdentifier).Value);
|
||||||
@@ -337,6 +339,7 @@
|
|||||||
IsInternalNavigation = _isInternalNavigation,
|
IsInternalNavigation = _isInternalNavigation,
|
||||||
RenderId = renderid,
|
RenderId = renderid,
|
||||||
Refresh = false,
|
Refresh = false,
|
||||||
|
StatusCode = PageState?.StatusCode,
|
||||||
AllowCookies = _allowCookies.GetValueOrDefault(true)
|
AllowCookies = _allowCookies.GetValueOrDefault(true)
|
||||||
};
|
};
|
||||||
OnStateChange?.Invoke(_pagestate);
|
OnStateChange?.Invoke(_pagestate);
|
||||||
|
|||||||
Binary file not shown.
@@ -1,4 +1,5 @@
|
|||||||
dotnet build -c Release ..\Oqtane.slnx
|
dotnet build -c Release ..\Oqtane.slnx
|
||||||
|
FixProps.exe
|
||||||
nuget.exe pack Oqtane.Client.nuspec
|
nuget.exe pack Oqtane.Client.nuspec
|
||||||
nuget.exe pack Oqtane.Server.nuspec
|
nuget.exe pack Oqtane.Server.nuspec
|
||||||
nuget.exe pack Oqtane.Shared.nuspec
|
nuget.exe pack Oqtane.Shared.nuspec
|
||||||
|
|||||||
@@ -170,6 +170,7 @@
|
|||||||
if (page == null || page.IsDeleted)
|
if (page == null || page.IsDeleted)
|
||||||
{
|
{
|
||||||
HandlePageNotFound(site, page, route);
|
HandlePageNotFound(site, page, route);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -248,6 +249,7 @@
|
|||||||
IsInternalNavigation = false,
|
IsInternalNavigation = false,
|
||||||
RenderId = Guid.NewGuid(),
|
RenderId = Guid.NewGuid(),
|
||||||
Refresh = true,
|
Refresh = true,
|
||||||
|
StatusCode = Context.Response.StatusCode,
|
||||||
AllowCookies = _allowCookies
|
AllowCookies = _allowCookies
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -300,8 +302,16 @@
|
|||||||
{
|
{
|
||||||
if (route.PagePath != "404")
|
if (route.PagePath != "404")
|
||||||
{
|
{
|
||||||
// redirect to 404 page
|
// handle not found request in static mode
|
||||||
NavigationManager.NavigateTo(route.SiteUrl + "/404", true);
|
if(_renderMode == RenderModes.Static)
|
||||||
|
{
|
||||||
|
NavigationManager.NotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// redirect to 404 page
|
||||||
|
NavigationManager.NavigateTo(route.SiteUrl + "/404", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Oqtane.Models;
|
|
||||||
using Oqtane.Shared;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Oqtane.Enums;
|
using Oqtane.Enums;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
|
using Oqtane.Models;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Security;
|
using Oqtane.Security;
|
||||||
using System;
|
using Oqtane.Shared;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
@@ -132,9 +132,8 @@ namespace Oqtane.Controllers
|
|||||||
if (moduleDefinition.Template.ToLower().Contains("internal"))
|
if (moduleDefinition.Template.ToLower().Contains("internal"))
|
||||||
{
|
{
|
||||||
rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString());
|
rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString());
|
||||||
var assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
|
moduleDefinition.ServerManagerType = moduleDefinition.ModuleDefinitionName + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + ".Server.Oqtane";
|
||||||
moduleDefinition.ServerManagerType = moduleDefinition.ModuleDefinitionName + ".Manager." + moduleDefinition.Name + "Manager, " + assemblyName;
|
moduleDefinition.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName + ", " + moduleDefinition.Owner + ".Client.Oqtane";
|
||||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName + ", " + assemblyName.Replace(".Server", ".Client");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -271,9 +270,10 @@ namespace Oqtane.Controllers
|
|||||||
foreach (string directory in Directory.GetDirectories(templatePath))
|
foreach (string directory in Directory.GetDirectories(templatePath))
|
||||||
{
|
{
|
||||||
string name = directory.Replace(templatePath, "");
|
string name = directory.Replace(templatePath, "");
|
||||||
if (System.IO.File.Exists(Path.Combine(directory, "template.json")))
|
var manifest = Directory.GetFiles(directory, "*.json");
|
||||||
|
if (manifest.Any())
|
||||||
{
|
{
|
||||||
var template = JsonSerializer.Deserialize<Template>(System.IO.File.ReadAllText(Path.Combine(directory, "template.json")));
|
var template = JsonSerializer.Deserialize<Template>(System.IO.File.ReadAllText(manifest[0]));
|
||||||
template.Name = name;
|
template.Name = name;
|
||||||
template.Location = "";
|
template.Location = "";
|
||||||
if (template.Type.ToLower() != "internal")
|
if (template.Type.ToLower() != "internal")
|
||||||
|
|||||||
@@ -183,9 +183,10 @@ namespace Oqtane.Controllers
|
|||||||
foreach (string directory in Directory.GetDirectories(templatePath))
|
foreach (string directory in Directory.GetDirectories(templatePath))
|
||||||
{
|
{
|
||||||
string name = directory.Replace(templatePath, "");
|
string name = directory.Replace(templatePath, "");
|
||||||
if (System.IO.File.Exists(Path.Combine(directory, "template.json")))
|
var manifest = Directory.GetFiles(directory, "*.json");
|
||||||
|
if (manifest.Any())
|
||||||
{
|
{
|
||||||
var template = JsonSerializer.Deserialize<Template>(System.IO.File.ReadAllText(Path.Combine(directory, "template.json")));
|
var template = JsonSerializer.Deserialize<Template>(System.IO.File.ReadAllText(manifest[0]));
|
||||||
template.Name = name;
|
template.Name = name;
|
||||||
template.Location = "";
|
template.Location = "";
|
||||||
if (template.Type.ToLower() != "internal")
|
if (template.Type.ToLower() != "internal")
|
||||||
@@ -226,8 +227,7 @@ namespace Oqtane.Controllers
|
|||||||
if (theme.Template.ToLower().Contains("internal"))
|
if (theme.Template.ToLower().Contains("internal"))
|
||||||
{
|
{
|
||||||
rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString());
|
rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString());
|
||||||
var assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
|
theme.ThemeName = theme.ThemeName + ", " + theme.Owner + ".Client.Oqtane";
|
||||||
theme.ThemeName = theme.ThemeName + ", " + assemblyName.Replace(".Server", ".Client");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Diagnostics;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@@ -65,6 +68,7 @@ namespace Oqtane.Extensions
|
|||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
app.UseAntiforgery();
|
app.UseAntiforgery();
|
||||||
|
app.UseNotFoundResponse();
|
||||||
|
|
||||||
// execute any IServerStartup logic
|
// execute any IServerStartup logic
|
||||||
app.ConfigureOqtaneAssemblies(environment);
|
app.ConfigureOqtaneAssemblies(environment);
|
||||||
@@ -146,5 +150,66 @@ namespace Oqtane.Extensions
|
|||||||
|
|
||||||
public static IApplicationBuilder UseExceptionMiddleWare(this IApplicationBuilder builder)
|
public static IApplicationBuilder UseExceptionMiddleWare(this IApplicationBuilder builder)
|
||||||
=> builder.UseMiddleware<ExceptionMiddleware>();
|
=> builder.UseMiddleware<ExceptionMiddleware>();
|
||||||
|
|
||||||
|
public static IApplicationBuilder UseNotFoundResponse(this IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
const string notFoundRoute = "/404";
|
||||||
|
app.UseStatusCodePagesWithReExecute(notFoundRoute, createScopeForStatusCodePages: true);
|
||||||
|
|
||||||
|
app.Use(async (context, next) =>
|
||||||
|
{
|
||||||
|
var path = context.Request.Path.Value ?? string.Empty;
|
||||||
|
if (string.IsNullOrEmpty(path) || ShouldSkipStatusCodeReExecution(path))
|
||||||
|
{
|
||||||
|
var feature = context.Features.Get<IStatusCodePagesFeature>();
|
||||||
|
feature?.Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.Use(async (context, next) =>
|
||||||
|
{
|
||||||
|
var feature = context.Features.Get<IStatusCodeReExecuteFeature>();
|
||||||
|
var handled = false;
|
||||||
|
if (feature != null
|
||||||
|
&& context.Response.StatusCode == (int)HttpStatusCode.NotFound
|
||||||
|
&& notFoundRoute.Equals(context.Request.Path.Value, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var alias = context.GetAlias();
|
||||||
|
if (!string.IsNullOrEmpty(alias?.Path))
|
||||||
|
{
|
||||||
|
var originalPath = context.Request.Path;
|
||||||
|
context.Request.Path = new PathString($"/{alias.Path}{notFoundRoute}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handled = true;
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
context.Request.Path = originalPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handled)
|
||||||
|
{
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ShouldSkipStatusCodeReExecution(string path)
|
||||||
|
{
|
||||||
|
return Constants.ReservedRoutes.Any(item => path.Contains("/" + item + "/")) || HasStaticFileExtension(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HasStaticFileExtension(string path)
|
||||||
|
{
|
||||||
|
return !string.IsNullOrEmpty(Path.GetExtension(path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,24 +99,6 @@ namespace Oqtane.Infrastructure
|
|||||||
|
|
||||||
private void Upgrade_2_0_2(Tenant tenant, IServiceScope scope)
|
private void Upgrade_2_0_2(Tenant tenant, IServiceScope scope)
|
||||||
{
|
{
|
||||||
if (tenant.Name == TenantNames.Master)
|
|
||||||
{
|
|
||||||
// remove Internal module template files as they are no longer supported
|
|
||||||
var internalTemplatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", "Internal", Path.DirectorySeparatorChar.ToString());
|
|
||||||
if (Directory.Exists(internalTemplatePath))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Directory.Delete(internalTemplatePath, true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// error deleting directory
|
|
||||||
_filelogger.LogError(Utilities.LogMessage(this, $"Oqtane Error: Error In 2.0.2 Upgrade Logic - {ex}"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize SiteGuid
|
// initialize SiteGuid
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
33
README.md
33
README.md
@@ -12,7 +12,7 @@ Oqtane is being developed based on some fundamental principles which are outline
|
|||||||
|
|
||||||
# Latest Release
|
# Latest Release
|
||||||
|
|
||||||
[6.2.1](https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1) was released on September 29, 2025 and is a maintenance release including 65 pull requests by 6 different contributors, pushing the total number of project commits all-time over 7100. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
|
[10.0.0](https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.0) was released on November 14, 2025 and is a major release including 77 pull requests by 6 different contributors, pushing the total number of project commits all-time over 7300. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
|
||||||
|
|
||||||
# Try It Now!
|
# Try It Now!
|
||||||
|
|
||||||
@@ -22,11 +22,15 @@ Microsoft's Public Cloud (requires an Azure account)
|
|||||||
A free ASP.NET hosting account. No hidden fees. No credit card required.
|
A free ASP.NET hosting account. No hidden fees. No credit card required.
|
||||||
[](https://www.monsterasp.net/)
|
[](https://www.monsterasp.net/)
|
||||||
|
|
||||||
# Getting Started (Version 6.2+)
|
# Getting Started (Version 10.0.0+)
|
||||||
|
|
||||||
**Installing using the Oqtane Application Template:**
|
**Installing using the Oqtane Application Template:**
|
||||||
|
|
||||||
(Note that "MyCompany.MyProject" can be replaced with your own unique company and project name)
|
If you have an older version of the Oqtane Application Template installed and want to use the latest, use the following .NET CLI command to uninstall the old version:
|
||||||
|
```
|
||||||
|
dotnet new uninstall Oqtane.Application.Template
|
||||||
|
```
|
||||||
|
To install the Oqtane Application Template and create a new project, use the following .NET CLI commands (note that "MyCompany.MyProject" can be replaced with your own unique company and project name):
|
||||||
|
|
||||||
```
|
```
|
||||||
dotnet new install Oqtane.Application.Template
|
dotnet new install Oqtane.Application.Template
|
||||||
@@ -38,19 +42,20 @@ dotnet run
|
|||||||
```
|
```
|
||||||
|
|
||||||
- Browse to the Url specified to run the application (an Installation Wizard screen will be displayed the first time you run the application)
|
- Browse to the Url specified to run the application (an Installation Wizard screen will be displayed the first time you run the application)
|
||||||
- To develop/debug the application in an IDE, open the *.sln file in the root folder and hit F5
|
- To develop/debug the application in an IDE, open the *.slnx file in the root folder and hit F5
|
||||||
|
|
||||||
**Installing using source code from the Dev/Master branch:**
|
**Installing using source code from the Dev/Master branch:**
|
||||||
|
|
||||||
- Install Latest **[.NET 9.0 SDK](https://dotnet.microsoft.com/en-us/download)**.
|
- Install Latest **[.NET 10.0 SDK](https://dotnet.microsoft.com/en-us/download)**.
|
||||||
|
|
||||||
- Install the latest edition (v17.12 or higher) of [Visual Studio 2022](https://visualstudio.microsoft.com/downloads) with the **ASP.NET and web development** workload enabled. Oqtane works with ALL editions of Visual Studio from Community to Enterprise. If you wish to use LocalDB for development ( not a requirement as Oqtane supports SQLite, mySQL, and PostgreSQL ) you must also install the **Data storage and processing**.
|
- Install the latest edition of [Visual Studio 2026](https://visualstudio.microsoft.com/downloads) with the **ASP.NET and web development** workload enabled. Oqtane works with ALL editions of Visual Studio from Community to Enterprise. If you wish to use LocalDB for development ( not a requirement as Oqtane supports SQLite, mySQL, and PostgreSQL ) you must also install the **Data storage and processing**.
|
||||||
|
|
||||||
- Clone (or download) the Oqtane Master or Dev branch source code to your local system.
|
- Clone (or download) the Oqtane source code to your local system:
|
||||||
|
|
||||||
- Open the **Oqtane.sln** solution file.
|
- Dev Branch: git clone https://github.com/oqtane/oqtane.framework
|
||||||
|
- Master Branch: git clone --single-branch --branch master https://github.com/oqtane/oqtane.framework
|
||||||
- Make sure you specify Oqtane.Server as the Startup Project.
|
|
||||||
|
- Open the **Oqtane.slnx** solution file (make sure you specify Oqtane.Server as the Startup Project)
|
||||||
|
|
||||||
- Run the application... an Installation Wizard screen will be displayed which will allow you to configure your preferred database and create a host user account.
|
- Run the application... an Installation Wizard screen will be displayed which will allow you to configure your preferred database and create a host user account.
|
||||||
|
|
||||||
@@ -83,7 +88,7 @@ dotnet run
|
|||||||
|
|
||||||
- If you have already installed a previous version of Oqtane and you wish to do a clean database install, simply reset the DefaultConnection value in the Oqtane.Server\appsettings.json file to "". This will trigger a re-install when you run the application which will execute the database installation.
|
- If you have already installed a previous version of Oqtane and you wish to do a clean database install, simply reset the DefaultConnection value in the Oqtane.Server\appsettings.json file to "". This will trigger a re-install when you run the application which will execute the database installation.
|
||||||
|
|
||||||
- If you want to submit pull requests make sure you install the [Github Extension For Visual Studio](https://visualstudio.github.com/). It is recommended you ignore any local changes you have made to the appsettings.json file before you submit a pull request. To automate this activity, open a command prompt and navigate to the /Oqtane.Server/ folder and enter the command "git update-index --skip-worktree appsettings.json"
|
- If you want to submit pull requests it is recommended you ignore any local changes you have made to the appsettings.json file before you submit a pull request. To automate this activity, open a command prompt and navigate to the /Oqtane.Server/ folder and enter the command "git update-index --skip-worktree appsettings.json"
|
||||||
|
|
||||||
**Video Series**
|
**Video Series**
|
||||||
|
|
||||||
@@ -106,6 +111,10 @@ Connect with other developers, get support, and share ideas by joining the Oqtan
|
|||||||
# 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...
|
||||||
|
|
||||||
|
[10.0.0](https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.0) (Nov 14, 2025)
|
||||||
|
- [x] Migration to .NET 10
|
||||||
|
- [x] Passkey Authentication
|
||||||
|
|
||||||
[6.2.1](https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1) (Sep 29, 2025)
|
[6.2.1](https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1) (Sep 29, 2025)
|
||||||
- [x] Stabilization improvements
|
- [x] Stabilization improvements
|
||||||
|
|
||||||
@@ -188,7 +197,7 @@ This project is open source, and therefore is a work in progress...
|
|||||||
➡️ Full list and older versions can be found in the [docs roadmap](https://docs.oqtane.org/guides/roadmap/index.html)
|
➡️ Full list and older versions can be found in the [docs roadmap](https://docs.oqtane.org/guides/roadmap/index.html)
|
||||||
|
|
||||||
# Background
|
# Background
|
||||||
Oqtane was created by [Shaun Walker](https://www.linkedin.com/in/shaunbrucewalker/) and is inspired by the DotNetNuke web application framework. Oqtane is a native Blazor application written from the ground up using modern .NET Core technology and a Single Page Application (SPA) architecture. It is a modular application framework offering a fully dynamic page compositing model, multi-site support, designer friendly themes, and extensibility via third party modules.
|
Oqtane was created by [Shaun Walker](https://www.linkedin.com/in/shaunbrucewalker/) and was inspired by his earlier efforts creating the DotNetNuke web application framework for the .NET Framework. Oqtane is a native Blazor application written from the ground up using modern .NET Core technology and a Single Page Application (SPA) architecture. It is a modular application framework offering a fully dynamic page compositing model, multi-site support, designer friendly themes, and extensibility via third party modules.
|
||||||
|
|
||||||
# Reference Implementations
|
# Reference Implementations
|
||||||
|
|
||||||
|
|||||||
@@ -205,7 +205,7 @@
|
|||||||
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
|
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
|
||||||
"siteConfig": {
|
"siteConfig": {
|
||||||
"webSocketsEnabled": true,
|
"webSocketsEnabled": true,
|
||||||
"netFrameworkVersion": "v9.0"
|
"netFrameworkVersion": "v10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
@@ -220,7 +220,7 @@
|
|||||||
"apiVersion": "2024-04-01",
|
"apiVersion": "2024-04-01",
|
||||||
"name": "[concat(parameters('BlazorWebsiteName'), '/ZipDeploy')]",
|
"name": "[concat(parameters('BlazorWebsiteName'), '/ZipDeploy')]",
|
||||||
"properties": {
|
"properties": {
|
||||||
"packageUri": "https://github.com/oqtane/oqtane.framework/releases/download/v6.2.1/Oqtane.Framework.6.2.1.Install.zip"
|
"packageUri": "https://github.com/oqtane/oqtane.framework/releases/download/v10.0.0/Oqtane.Framework.10.0.0.Install.zip"
|
||||||
},
|
},
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"[resourceId('Microsoft.Web/sites', parameters('BlazorWebsiteName'))]"
|
"[resourceId('Microsoft.Web/sites', parameters('BlazorWebsiteName'))]"
|
||||||
|
|||||||
Reference in New Issue
Block a user