Merge pull request #4148 from oqtane/dev

5.1.1 release
This commit is contained in:
Shaun Walker
2024-04-16 13:33:51 -04:00
committed by GitHub
62 changed files with 526 additions and 469 deletions

26
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@ -0,0 +1,26 @@
---
name: Bug Report
about: Create a bug report to help us improve the product
title: "[BUG] "
labels: ''
assignees: ''
---
### Oqtane Info
Version - #.#.#
Render Mode - Static
Interactivity - Server
Database - SQL Server
### Describe the bug
### Expected Behavior
### Steps To Reproduce
### Anything else?

View File

@ -0,0 +1,20 @@
---
name: Enhancement Request
about: 'Suggest a product enhancement '
title: "[ENH] "
labels: ''
assignees: ''
---
### Oqtane Info
Version - #.#.#
Render Mode - Static
Interactivity - Server
Database - SQL Server
### Describe the enhancement
### Anything else?

View File

@ -86,47 +86,48 @@ else
</div> </div>
</div> </div>
<br /> <br />
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button> <button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
<ActionDialog Header="Clear Events" Message="Are You Sure You Wish To Remove All Log Events?" Action="DeleteLogs" Class="btn btn-danger" OnClick="@(async () => await DeleteLogs())" ResourceKey="DeleteLogs" />
</TabPanel> </TabPanel>
</TabStrip> </TabStrip>
} }
@code { @code {
private string _level = "-"; private string _level = "-";
private string _function = "-"; private string _function = "-";
private string _rows = "10"; private string _rows = "10";
private int _page = 1; private int _page = 1;
private List<Log> _logs; private List<Log> _logs;
private int _retention = 30; private int _retention = 30;
public override string UrlParametersTemplate => "/{level}/{function}/{rows}/{page}"; public override string UrlParametersTemplate => "/{level}/{function}/{rows}/{page}";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnParametersSetAsync() protected override async Task OnParametersSetAsync()
{ {
try try
{ {
if (UrlParameters.ContainsKey("level")) if (UrlParameters.ContainsKey("level"))
{ {
_level = UrlParameters["level"]; _level = UrlParameters["level"];
} }
if (UrlParameters.ContainsKey("function")) if (UrlParameters.ContainsKey("function"))
{ {
_function = UrlParameters["function"]; _function = UrlParameters["function"];
} }
if (UrlParameters.ContainsKey("rows")) if (UrlParameters.ContainsKey("rows"))
{ {
_rows = UrlParameters["rows"]; _rows = UrlParameters["rows"];
} }
if (UrlParameters.ContainsKey("page") && int.TryParse(UrlParameters["page"], out int page)) if (UrlParameters.ContainsKey("page") && int.TryParse(UrlParameters["page"], out int page))
{ {
_page = page; _page = page;
} }
await GetLogs(); await GetLogs();
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
_retention = int.Parse( SettingService.GetSetting(settings, "LogRetention", "30")); _retention = int.Parse( SettingService.GetSetting(settings, "LogRetention", "30"));
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -213,22 +214,37 @@ else
return classname; return classname;
} }
private async Task SaveSiteSettings() private async Task SaveSiteSettings()
{ {
try try
{ {
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
settings = SettingService.SetSetting(settings, "LogRetention", _retention.ToString(), true); settings = SettingService.SetSetting(settings, "LogRetention", _retention.ToString(), true);
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success); AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
} }
catch (Exception ex) catch (Exception ex)
{ {
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message); await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error); AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
} }
} }
private async Task DeleteLogs()
{
try
{
await LogService.DeleteLogsAsync(PageState.Site.SiteId);
await GetLogs();
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Logs {Error}", ex.Message);
AddModuleMessage(Localizer["Error.DeleteLogs"], MessageType.Error);
}
}
private void OnPageChange(int page) private void OnPageChange(int page)
{ {

View File

@ -385,45 +385,34 @@
page.ParentId = Int32.Parse(_parentid); page.ParentId = Int32.Parse(_parentid);
} }
// path can be a link to an external url if (string.IsNullOrEmpty(_path))
if (!_path.Contains("://"))
{ {
if (string.IsNullOrEmpty(_path)) _path = _name;
{ }
_path = _name;
}
(_path, string parameters) = Utilities.ParsePath(_path); if (_path.Contains("/"))
{
if (_path.Contains("/")) if (_path.EndsWith("/") && _path != "/")
{ {
if (_path.EndsWith("/") && _path != "/") _path = _path.Substring(0, _path.Length - 1);
{
_path = _path.Substring(0, _path.Length - 1);
}
_path = _path.Substring(_path.LastIndexOf("/") + 1);
} }
if (_parentid == "-1") _path = _path.Substring(_path.LastIndexOf("/") + 1);
{ }
page.Path = Utilities.GetFriendlyUrl(_path); if (_parentid == "-1")
} {
else page.Path = Utilities.GetFriendlyUrl(_path);
{
Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId);
if (parent.Path == string.Empty)
{
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
}
else
{
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
}
}
page.Path += parameters;
} }
else else
{ {
page.Path = _path; Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId);
if (parent.Path == string.Empty)
{
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
}
else
{
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
}
} }
var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId); var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
@ -497,14 +486,7 @@
} }
else else
{ {
if (!page.Path.Contains("://")) NavigationManager.NavigateTo(page.Path); // redirect to new page created
{
NavigationManager.NavigateTo(page.Path); // redirect to new page created
}
else
{
NavigationManager.NavigateTo(NavigateUrl("admin/pages"));
}
} }
} }
else else

View File

@ -380,7 +380,7 @@
} }
else else
{ {
if (_path.Contains("/") & !_path.Contains("://")) if (_path.Contains("/"))
{ {
_path = _path.Substring(_path.LastIndexOf("/") + 1); _path = _path.Substring(_path.LastIndexOf("/") + 1);
} }
@ -529,45 +529,34 @@
_page.ParentId = Int32.Parse(_parentid); _page.ParentId = Int32.Parse(_parentid);
} }
// path can be a link to an external url if (string.IsNullOrEmpty(_path))
if (!_path.Contains("://"))
{ {
if (string.IsNullOrEmpty(_path)) _path = _name;
{ }
_path = _name;
}
(_path, string parameters) = Utilities.ParsePath(_path); if (_path.Contains("/"))
{
if (_path.Contains("/")) if (_path.EndsWith("/") && _path != "/")
{ {
if (_path.EndsWith("/") && _path != "/") _path = _path.Substring(0, _path.Length - 1);
{
_path = _path.Substring(0, _path.Length - 1);
}
_path = _path.Substring(_path.LastIndexOf("/") + 1);
} }
if (_parentid == "-1") _path = _path.Substring(_path.LastIndexOf("/") + 1);
{ }
_page.Path = Utilities.GetFriendlyUrl(_path); if (_parentid == "-1")
} {
else _page.Path = Utilities.GetFriendlyUrl(_path);
{
Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId);
if (parent.Path == string.Empty)
{
_page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
}
else
{
_page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
}
}
_page.Path += parameters;
} }
else else
{ {
_page.Path = _path; Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId);
if (parent.Path == string.Empty)
{
_page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
}
else
{
_page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
}
} }
var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId); var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
@ -658,14 +647,7 @@
} }
else else
{ {
if (!_page.Path.Contains("://")) NavigationManager.NavigateTo(NavigateUrl(), true); // redirect to page being edited
{
NavigationManager.NavigateTo(NavigateUrl(), true); // redirect to page being edited
}
else
{
NavigationManager.NavigateTo(NavigateUrl("admin/pages"));
}
} }
} }
else else

View File

@ -26,6 +26,12 @@
<input id="osversion" class="form-control" @bind="@_osversion" readonly /> <input id="osversion" class="form-control" @bind="@_osversion" readonly />
</div> </div>
</div> </div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="process" HelpText="Indicates if the current process is 32 bit or 64 bit" ResourceKey="Process">Process: </Label>
<div class="col-sm-9">
<input id="process" class="form-control" @bind="@_process" readonly />
</div>
</div>
<div class="row mb-1 align-items-center"> <div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="machinename" HelpText="Machine Name" ResourceKey="MachineName">Machine Name: </Label> <Label Class="col-sm-3" For="machinename" HelpText="Machine Name" ResourceKey="MachineName">Machine Name: </Label>
<div class="col-sm-9"> <div class="col-sm-9">
@ -62,12 +68,6 @@
<input id="servertime" class="form-control" @bind="@_servertime" readonly /> <input id="servertime" class="form-control" @bind="@_servertime" readonly />
</div> </div>
</div> </div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="tickcount" HelpText="Amount Of Time The Service Has Been Available And Operational" ResourceKey="TickCount">Service Uptime: </Label>
<div class="col-sm-9">
<input id="tickcount" class="form-control" @bind="@_tickcount" readonly />
</div>
</div>
<div class="row mb-1 align-items-center"> <div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="workingset" HelpText="Memory Allocation Of Service (in MB)" ResourceKey="WorkingSet">Memory Allocation: </Label> <Label Class="col-sm-3" For="workingset" HelpText="Memory Allocation Of Service (in MB)" ResourceKey="WorkingSet">Memory Allocation: </Label>
<div class="col-sm-9"> <div class="col-sm-9">
@ -165,13 +165,13 @@
private string _version = string.Empty; private string _version = string.Empty;
private string _clrversion = string.Empty; private string _clrversion = string.Empty;
private string _osversion = string.Empty; private string _osversion = string.Empty;
private string _machinename = string.Empty; private string _process = string.Empty;
private string _machinename = string.Empty;
private string _ipaddress = string.Empty; private string _ipaddress = string.Empty;
private string _environment = string.Empty; private string _environment = string.Empty;
private string _contentrootpath = string.Empty; private string _contentrootpath = string.Empty;
private string _webrootpath = string.Empty; private string _webrootpath = string.Empty;
private string _servertime = string.Empty; private string _servertime = string.Empty;
private string _tickcount = string.Empty;
private string _workingset = string.Empty; private string _workingset = string.Empty;
private string _installationid = string.Empty; private string _installationid = string.Empty;
@ -192,13 +192,13 @@
{ {
_clrversion = systeminfo["CLRVersion"].ToString(); _clrversion = systeminfo["CLRVersion"].ToString();
_osversion = systeminfo["OSVersion"].ToString(); _osversion = systeminfo["OSVersion"].ToString();
_machinename = systeminfo["MachineName"].ToString(); _process = systeminfo["Process"].ToString();
_machinename = systeminfo["MachineName"].ToString();
_ipaddress = systeminfo["IPAddress"].ToString(); _ipaddress = systeminfo["IPAddress"].ToString();
_environment = systeminfo["Environment"].ToString(); _environment = systeminfo["Environment"].ToString();
_contentrootpath = systeminfo["ContentRootPath"].ToString(); _contentrootpath = systeminfo["ContentRootPath"].ToString();
_webrootpath = systeminfo["WebRootPath"].ToString(); _webrootpath = systeminfo["WebRootPath"].ToString();
_servertime = systeminfo["ServerTime"].ToString() + " UTC"; _servertime = systeminfo["ServerTime"].ToString() + " UTC";
_tickcount = TimeSpan.FromMilliseconds(Convert.ToInt64(systeminfo["TickCount"].ToString())).ToString();
_workingset = (Convert.ToInt64(systeminfo["WorkingSet"].ToString()) / 1000000).ToString() + " MB"; _workingset = (Convert.ToInt64(systeminfo["WorkingSet"].ToString()) / 1000000).ToString() + " MB";
} }

View File

@ -54,7 +54,7 @@ else
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">@Header</h5> <h5 class="modal-title">@Header</h5>
<form method="post" @formname="@($"ActionDialogCloseForm{Id}")" @onsubmit="DisplayModal" data-enhance> <form method="post" @formname="@($"ActionDialogCloseForm{Id}")" @onsubmit="DisplayModal" data-enhance>
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" /> <input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<button type="submit" class="btn-close" aria-label="Close"></button> <button type="submit" class="btn-close" aria-label="Close"></button>
</form> </form>
</div> </div>
@ -65,12 +65,12 @@ else
@if (!string.IsNullOrEmpty(Action)) @if (!string.IsNullOrEmpty(Action))
{ {
<form method="post" @formname="@($"ActionDialogConfirmForm{Id}")" @onsubmit="Confirm" data-enhance> <form method="post" @formname="@($"ActionDialogConfirmForm{Id}")" @onsubmit="Confirm" data-enhance>
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" /> <input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<button type="submit" class="@Class">@((MarkupString)_iconSpan) @Text</button> <button type="submit" class="@Class">@((MarkupString)_iconSpan) @Text</button>
</form> </form>
} }
<form method="post" @formname="@($"ActionDialogCancelForm{Id}")" @onsubmit="DisplayModal" data-enhance> <form method="post" @formname="@($"ActionDialogCancelForm{Id}")" @onsubmit="DisplayModal" data-enhance>
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" /> <input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<button type="submit" class="btn btn-secondary">@SharedLocalizer["Cancel"]</button> <button type="submit" class="btn btn-secondary">@SharedLocalizer["Cancel"]</button>
</form> </form>
</div> </div>
@ -88,7 +88,7 @@ else
else else
{ {
<form method="post" @formname="@($"ActionDialogActionForm{Id}")" @onsubmit="DisplayModal" data-enhance> <form method="post" @formname="@($"ActionDialogActionForm{Id}")" @onsubmit="DisplayModal" data-enhance>
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" /> <input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<button type="submit" class="@Class">@((MarkupString)_iconSpan) @Text</button> <button type="submit" class="@Class">@((MarkupString)_iconSpan) @Text</button>
</form> </form>
} }

View File

@ -99,7 +99,7 @@
if (!string.IsNullOrEmpty(Text)) if (!string.IsNullOrEmpty(Text))
{ {
_text = Localize(nameof(Text), _text); _text = Localize(nameof(Text), Text);
} }
else else
{ {

View File

@ -13,7 +13,7 @@
<NavLink class="ms-2" href="@NavigateUrl("admin/log")">View Details</NavLink> <NavLink class="ms-2" href="@NavigateUrl("admin/log")">View Details</NavLink>
} }
<form method="post" @onsubmit="DismissModal" @formname="@_formname" data-enhance> <form method="post" @onsubmit="DismissModal" @formname="@_formname" data-enhance>
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" /> <input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<button type="submit" class="btn-close" aria-label="Close"></button> <button type="submit" class="btn-close" aria-label="Close"></button>
</form> </form>
} }

View File

@ -73,7 +73,7 @@
@if (!string.IsNullOrEmpty(SearchProperties)) @if (!string.IsNullOrEmpty(SearchProperties))
{ {
<form method="post" autocomplete="off" @formname="PagerForm" @onsubmit="Search" data-enhance> <form method="post" autocomplete="off" @formname="PagerForm" @onsubmit="Search" data-enhance>
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" /> <input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<div class="input-group my-3"> <div class="input-group my-3">
<input type="text" id="pagersearch" name="_search" class="form-control" placeholder=@string.Format(Localizer["SearchPlaceholder"], FormatSearchProperties()) @bind="@_search" /> <input type="text" id="pagersearch" name="_search" class="form-control" placeholder=@string.Format(Localizer["SearchPlaceholder"], FormatSearchProperties()) @bind="@_search" />
<button type="submit" class="btn btn-primary">@SharedLocalizer["Search"]</button> <button type="submit" class="btn btn-primary">@SharedLocalizer["Search"]</button>

View File

@ -63,8 +63,7 @@
</span> </span>
} }
</div> </div>
<div @ref="@_editorElement"> <div @ref="@_editorElement"></div>
</div>
</div> </div>
</div> </div>
</TabPanel> </TabPanel>
@ -91,11 +90,11 @@
</div> </div>
@if (ReadOnly) @if (ReadOnly)
{ {
<textarea id="rawhtmleditor" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10" readonly></textarea> <textarea id="@_rawhtmlid" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10" readonly></textarea>
} }
else else
{ {
<textarea id="rawhtmleditor" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10"></textarea> <textarea id="@_rawhtmlid" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10"></textarea>
} }
</TabPanel> </TabPanel>
} }
@ -104,17 +103,25 @@
</div> </div>
@code { @code {
private bool _initialized = false;
private RichTextEditorInterop interop;
private FileManager _fileManager;
private string _activetab = "Rich";
private ElementReference _editorElement; private ElementReference _editorElement;
private ElementReference _toolBar; private ElementReference _toolBar;
private bool _richfilemanager = false; private bool _richfilemanager = false;
private FileManager _fileManager;
private string _richhtml = string.Empty; private string _richhtml = string.Empty;
private string _originalrichhtml = string.Empty; private string _originalrichhtml = string.Empty;
private bool _rawfilemanager = false; private bool _rawfilemanager = false;
private string _rawhtmlid = "RawHtmlEditor_" + Guid.NewGuid().ToString("N");
private string _rawhtml = string.Empty; private string _rawhtml = string.Empty;
private string _originalrawhtml = string.Empty; private string _originalrawhtml = string.Empty;
private string _message = string.Empty; private string _message = string.Empty;
private string _activetab = "Rich"; private bool _contentchanged = false;
[Parameter] [Parameter]
public string Content { get; set; } public string Content { get; set; }
@ -123,7 +130,7 @@
public bool ReadOnly { get; set; } = false; public bool ReadOnly { get; set; } = false;
[Parameter] [Parameter]
public string Placeholder { get; set; } = "Enter Your Content..."; public string Placeholder { get; set; }
[Parameter] [Parameter]
public bool AllowFileManagement { get; set; } = true; public bool AllowFileManagement { get; set; } = true;
@ -146,20 +153,29 @@
public override List<Resource> Resources => new List<Resource>() public override List<Resource> Resources => new List<Resource>()
{ {
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js" }, new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js", Location = ResourceLocation.Body },
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" }, new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js", Location = ResourceLocation.Body },
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" } new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js", Location = ResourceLocation.Body }
}; };
protected override void OnInitialized()
{
interop = new RichTextEditorInterop(JSRuntime);
if (string.IsNullOrEmpty(Placeholder))
{
Placeholder = Localizer["Placeholder"];
}
}
protected override void OnParametersSet() protected override void OnParametersSet()
{ {
_richhtml = Content; _richhtml = Content;
_rawhtml = Content; _rawhtml = Content;
_originalrawhtml = _rawhtml; // preserve for comparison later _originalrawhtml = _rawhtml; // preserve for comparison later
_originalrichhtml = ""; _originalrichhtml = "";
_contentchanged = true; // identifies when Content parameter has changed
// Quill wraps content in <p> tags which can be used as a signal to set the active tab if (!AllowRichText)
if (!string.IsNullOrEmpty(Content) && !Content.StartsWith("<p>") && AllowRawHtml)
{ {
_activetab = "Raw"; _activetab = "Raw";
} }
@ -171,8 +187,6 @@
if (AllowRichText) if (AllowRichText)
{ {
var interop = new RichTextEditorInterop(JSRuntime);
if (firstRender) if (firstRender)
{ {
await interop.CreateEditor( await interop.CreateEditor(
@ -182,15 +196,38 @@
Placeholder, Placeholder,
Theme, Theme,
DebugLevel); DebugLevel);
}
await interop.LoadEditorContent(_editorElement, _richhtml); await interop.LoadEditorContent(_editorElement, _richhtml);
if (string.IsNullOrEmpty(_originalrichhtml)) // preserve a copy of the content (Quill sanitizes content so we need to retrieve it from the editor as it may have been modified)
{
// preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor)
_originalrichhtml = await interop.GetHtml(_editorElement); _originalrichhtml = await interop.GetHtml(_editorElement);
_initialized = true;
} }
else
{
if (_initialized)
{
if (_contentchanged)
{
// reload editor if Content passed to component has changed
await interop.LoadEditorContent(_editorElement, _richhtml);
_originalrichhtml = await interop.GetHtml(_editorElement);
}
else
{
// preserve changed content on re-render event
var richhtml = await interop.GetHtml(_editorElement);
if (richhtml != _richhtml)
{
_richhtml = richhtml;
await interop.LoadEditorContent(_editorElement, _richhtml);
}
}
}
}
_contentchanged = false;
} }
} }
@ -218,23 +255,27 @@
else else
{ {
var richhtml = ""; var richhtml = "";
if (AllowRichText) if (AllowRichText)
{ {
// return rich text content if it has changed
var interop = new RichTextEditorInterop(JSRuntime);
richhtml = await interop.GetHtml(_editorElement); richhtml = await interop.GetHtml(_editorElement);
} }
// rich text value will only be blank if AllowRichText is disabled or the JS Interop method failed
if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml) && !string.IsNullOrEmpty(_originalrichhtml)) if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml))
{ {
return richhtml; // convert Quill's empty content to empty string
} if (richhtml == "<p><br></p>")
else {
{ richhtml = string.Empty;
// return original raw html content }
return _originalrawhtml; return richhtml;
} }
} else
{
// return original raw html content
return _originalrawhtml;
}
}
} }
public async Task InsertRichImage() public async Task InsertRichImage()
@ -245,7 +286,6 @@
var file = _fileManager.GetFile(); var file = _fileManager.GetFile();
if (file != null) if (file != null)
{ {
var interop = new RichTextEditorInterop(JSRuntime);
await interop.InsertImage(_editorElement, file.Url, ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name)); await interop.InsertImage(_editorElement, file.Url, ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name));
_richhtml = await interop.GetHtml(_editorElement); _richhtml = await interop.GetHtml(_editorElement);
_richfilemanager = false; _richfilemanager = false;
@ -271,7 +311,7 @@
if (file != null) if (file != null)
{ {
var interop = new Interop(JSRuntime); var interop = new Interop(JSRuntime);
int pos = await interop.GetCaretPosition("rawhtmleditor"); int pos = await interop.GetCaretPosition(_rawhtmlid);
var image = "<img src=\"" + file.Url + "\" alt=\"" + ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name) + "\" class=\"img-fluid\">"; var image = "<img src=\"" + file.Url + "\" alt=\"" + ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name) + "\" class=\"img-fluid\">";
_rawhtml = _rawhtml.Substring(0, pos) + image + _rawhtml.Substring(pos); _rawhtml = _rawhtml.Substring(0, pos) + image + _rawhtml.Substring(pos);
_rawfilemanager = false; _rawfilemanager = false;

View File

@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
<Version>5.1.0</Version> <Version>5.1.1</Version>
<Product>Oqtane</Product> <Product>Oqtane</Product>
<Authors>Shaun Walker</Authors> <Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company> <Company>.NET Foundation</Company>
@ -12,7 +12,7 @@
<Copyright>.NET Foundation</Copyright> <Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl> <PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl> <RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane</RootNamespace> <RootNamespace>Oqtane</RootNamespace>
@ -22,9 +22,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.4" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.4" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
</ItemGroup> </ItemGroup>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@ -153,7 +153,7 @@
<data name="Integrated" xml:space="preserve"> <data name="Integrated" xml:space="preserve">
<value>Integrated</value> <value>Integrated</value>
</data> </data>
<data name="Encryption,Text" xml:space="preserve"> <data name="Encryption.Text" xml:space="preserve">
<value>Encryption:</value> <value>Encryption:</value>
</data> </data>
<data name="Encryption.HelpText" xml:space="preserve"> <data name="Encryption.HelpText" xml:space="preserve">

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@ -210,4 +210,16 @@
<data name="Success.SaveSiteSettings" xml:space="preserve"> <data name="Success.SaveSiteSettings" xml:space="preserve">
<value>Settings Saved Successfully</value> <value>Settings Saved Successfully</value>
</data> </data>
<data name="DeleteLogs.Header" xml:space="preserve">
<value>Clear Events</value>
</data>
<data name="DeleteLogs.Message" xml:space="preserve">
<value>Are You Sure You Wish To Remove All Log Events?</value>
</data>
<data name="DeleteLogs.Text" xml:space="preserve">
<value>Clear Events</value>
</data>
<data name="Error.DeleteLogs" xml:space="preserve">
<value>Error Deleting Log Events</value>
</data>
</root> </root>

View File

@ -255,12 +255,6 @@
<data name="MachineName.Text" xml:space="preserve"> <data name="MachineName.Text" xml:space="preserve">
<value>Machine Name:</value> <value>Machine Name:</value>
</data> </data>
<data name="TickCount.HelpText" xml:space="preserve">
<value>Amount Of Time The Service Has Been Available And Operational</value>
</data>
<data name="TickCount.Text" xml:space="preserve">
<value>Service Uptime:</value>
</data>
<data name="WebRootPath.HelpText" xml:space="preserve"> <data name="WebRootPath.HelpText" xml:space="preserve">
<value>Server Web Root Path</value> <value>Server Web Root Path</value>
</data> </data>
@ -294,4 +288,10 @@
<data name="Error.ClearLog" xml:space="preserve"> <data name="Error.ClearLog" xml:space="preserve">
<value>Ann Error Occurred Clearing The System Log</value> <value>Ann Error Occurred Clearing The System Log</value>
</data> </data>
<data name="Process.HelpText" xml:space="preserve">
<value>Indicates if the current process is 32 bit or 64 bit</value>
</data>
<data name="Process.Text" xml:space="preserve">
<value>Process: </value>
</data>
</root> </root>

View File

@ -126,4 +126,7 @@
<data name="Message.Require.Image" xml:space="preserve"> <data name="Message.Require.Image" xml:space="preserve">
<value>You Must Select An Image To Insert</value> <value>You Must Select An Image To Insert</value>
</data> </data>
<data name="Placeholder" xml:space="preserve">
<value>Enter Your Content...</value>
</data>
</root> </root>

View File

@ -29,6 +29,13 @@ namespace Oqtane.Services
/// <returns></returns> /// <returns></returns>
Task<Log> GetLogAsync(int logId); Task<Log> GetLogAsync(int logId);
/// <summary>
/// Clear the entire logs of the given site.
/// </summary>
/// <param name="siteId"></param>
/// <returns></returns>
Task DeleteLogsAsync(int siteId);
/// <summary> /// <summary>
/// Creates a new log entry /// Creates a new log entry
/// </summary> /// </summary>

View File

@ -35,6 +35,11 @@ namespace Oqtane.Services
return await GetJsonAsync<Log>($"{Apiurl}/{logId}"); return await GetJsonAsync<Log>($"{Apiurl}/{logId}");
} }
public async Task DeleteLogsAsync(int siteId)
{
await DeleteAsync($"{Apiurl}?siteid={siteId}");
}
public async Task Log(int? pageId, int? moduleId, int? userId, string category, string feature, LogFunction function, LogLevel level, Exception exception, string message, params object[] args) public async Task Log(int? pageId, int? moduleId, int? userId, string category, string feature, LogFunction function, LogLevel level, Exception exception, string message, params object[] args)
{ {
await Log(null, pageId, moduleId, userId, category, feature, function, level, exception, message, args); await Log(null, pageId, moduleId, userId, category, feature, function, level, exception, message, args);

View File

@ -33,7 +33,7 @@ namespace Oqtane.Services
public async Task<Profile> UpdateProfileAsync(Profile profile) public async Task<Profile> UpdateProfileAsync(Profile profile)
{ {
return await PutJsonAsync<Profile>($"{Apiurl}/{profile.SiteId}", profile); return await PutJsonAsync<Profile>($"{Apiurl}/{profile.ProfileId}", profile);
} }
public async Task DeleteProfileAsync(int profileId) public async Task DeleteProfileAsync(int profileId)
{ {

View File

@ -9,7 +9,7 @@
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title"><ModuleTitle /></h5> <h5 class="modal-title"><ModuleTitle /></h5>
<form method="post" class="app-form-inline" @formname="AdminContainerForm" @onsubmit="@CloseModal" data-enhance> <form method="post" class="app-form-inline" @formname="AdminContainerForm" @onsubmit="@CloseModal" data-enhance>
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" /> <input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<button type="submit" class="btn-close" aria-label="Close"></button> <button type="submit" class="btn-close" aria-label="Close"></button>
</form> </form>
</div> </div>

View File

@ -12,7 +12,7 @@
@if (_showEditMode || (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered))) @if (_showEditMode || (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered)))
{ {
<form method="post" class="app-form-inline" @formname="EditModeForm" @onsubmit="@(async () => await ToggleEditMode(PageState.EditMode))" data-enhance> <form method="post" class="app-form-inline" @formname="EditModeForm" @onsubmit="@(async () => await ToggleEditMode(PageState.EditMode))" data-enhance>
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" /> <input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
@if (PageState.EditMode) @if (PageState.EditMode)
{ {
<button type="submit" class="btn @ButtonClass active" aria-pressed="true" autocomplete="off"> <button type="submit" class="btn @ButtonClass active" aria-pressed="true" autocomplete="off">

View File

@ -16,7 +16,7 @@
else else
{ {
<form method="post" class="app-form-inline" action="@logouturl" @formname="LogoutForm"> <form method="post" class="app-form-inline" action="@logouturl" @formname="LogoutForm">
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" /> <input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
<input type="hidden" name="returnurl" value="@returnurl" /> <input type="hidden" name="returnurl" value="@returnurl" />
<button type="submit" class="btn btn-primary">@Localizer["Logout"]</button> <button type="submit" class="btn btn-primary">@Localizer["Logout"]</button>
</form> </form>

View File

@ -121,15 +121,15 @@
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
if (_login != "-") if (_login != "-")
{ {
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login, true); settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login);
} }
if (_register != "-") if (_register != "-")
{ {
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register, true); settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register);
} }
if (_footer != "-") if (_footer != "-")
{ {
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Footer", _footer, true); settings = SettingService.SetSetting(settings, GetType().Namespace + ":Footer", _footer);
} }
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
} }

View File

@ -3,8 +3,6 @@
@using Oqtane.Shared @using Oqtane.Shared
@inject SiteState SiteState @inject SiteState SiteState
@implements IDisposable @implements IDisposable
@* the following StreamRendering attribute is required - if it is removed the framework will not render the content in static rendering *@
@attribute [StreamRendering]
@if (!string.IsNullOrEmpty(_title)) @if (!string.IsNullOrEmpty(_title))
{ {

View File

@ -1,13 +1,13 @@
@namespace Oqtane.UI @namespace Oqtane.UI
@inject SiteState SiteState @inject SiteState SiteState
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Interactive) @if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static)
{ {
<StreamRenderingDisabled ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" /> <RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" />
} }
else else
{ {
<StreamRenderingEnabled ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" /> <RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, PageState.Site.Prerender)" />
} }
@code { @code {

View File

@ -3,8 +3,6 @@
@inject IInstallationService InstallationService @inject IInstallationService InstallationService
@inject IJSRuntime JSRuntime @inject IJSRuntime JSRuntime
@inject SiteState SiteState @inject SiteState SiteState
@* the following StreamRendering attribute is required - if it is removed the framework will not render the content in static rendering *@
@attribute [StreamRendering]
@if (_initialized) @if (_initialized)
{ {

View File

@ -124,12 +124,20 @@
{ {
if (querystring.ContainsKey("reload") && querystring["reload"] == "post") if (querystring.ContainsKey("reload") && querystring["reload"] == "post")
{ {
// post back so that the cookies are set correctly - required on any change to the principal if (PageState.RenderMode == RenderModes.Interactive)
var interop = new Interop(JSRuntime); {
var fields = new { returnurl = "/" + NavigationManager.ToBaseRelativePath(_absoluteUri) }; // post back so that the cookies are set correctly - required on any change to the principal
string url = Utilities.TenantUrl(SiteState.Alias, "/pages/external/"); var interop = new Interop(JSRuntime);
await interop.SubmitForm(url, fields); var fields = new { returnurl = "/" + NavigationManager.ToBaseRelativePath(_absoluteUri) };
return; string url = Utilities.TenantUrl(SiteState.Alias, "/pages/external/");
await interop.SubmitForm(url, fields);
return;
}
else
{
NavigationManager.NavigateTo(_absoluteUri.Replace("?reload=post", "").Replace("&reload=post", ""), true);
return;
}
} }
else else
{ {
@ -163,9 +171,9 @@
visitorId = PageState.VisitorId; visitorId = PageState.VisitorId;
} }
if (PageState.RenderMode == RenderModes.Interactive) if (PageState != null && PageState.RenderMode == RenderModes.Interactive)
{ {
// process any sync events (for synchrozing the client application with the server) // process any sync events (for synchronizing the client application with the server)
var sync = await SyncService.GetSyncEventsAsync(lastsyncdate); var sync = await SyncService.GetSyncEventsAsync(lastsyncdate);
lastsyncdate = sync.SyncDate; lastsyncdate = sync.SyncDate;
if (sync.SyncEvents.Any()) if (sync.SyncEvents.Any())
@ -243,105 +251,97 @@
} }
} }
if (page != null) // check if user is authorized to view page
if (page != null && UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList)))
{ {
// check if user is authorized to view page // edit mode
if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList))) if (user != null)
{ {
// edit mode if (querystring.ContainsKey("editmode") && querystring["edit"] == "true")
if (user != null)
{ {
if (querystring.ContainsKey("editmode") && querystring["edit"] == "true") editmode = true;
}
else
{
editmode = (page.PageId == ((user.Settings.ContainsKey("CP-editmode")) ? int.Parse(user.Settings["CP-editmode"]) : -1));
if (!editmode)
{ {
editmode = true; var userSettings = new Dictionary<string, string> { { "CP-editmode", "-1" } };
} await SettingService.UpdateUserSettingsAsync(userSettings, user.UserId);
else
{
editmode = (page.PageId == ((user.Settings.ContainsKey("CP-editmode")) ? int.Parse(user.Settings["CP-editmode"]) : -1));
if (!editmode)
{
var userSettings = new Dictionary<string, string> { { "CP-editmode", "-1" } };
await SettingService.UpdateUserSettingsAsync(userSettings, user.UserId);
}
} }
} }
}
// load additional metadata for current page
page = ProcessPage(page, site, user, SiteState.Alias);
// load additional metadata for modules // load additional metadata for current page
(page, site.Modules) = ProcessModules(page, site.Modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias); page = ProcessPage(page, site, user, SiteState.Alias);
// populate page state (which acts as a client-side cache for subsequent requests) // load additional metadata for modules
_pagestate = new PageState (page, site.Modules) = ProcessModules(page, site.Modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias);
// populate page state (which acts as a client-side cache for subsequent requests)
_pagestate = new PageState
{
Alias = SiteState.Alias,
Site = site,
Page = page,
User = user,
Uri = new Uri(_absoluteUri, UriKind.Absolute),
Route = route,
QueryString = querystring,
UrlParameters = route.UrlParameters,
ModuleId = moduleid,
Action = action,
EditMode = editmode,
LastSyncDate = lastsyncdate,
RenderMode = RenderMode,
Runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime),
VisitorId = visitorId,
RemoteIPAddress = SiteState.RemoteIPAddress,
ReturnUrl = returnurl,
IsInternalNavigation = _isInternalNavigation,
RenderId = Guid.NewGuid(),
Refresh = false
};
OnStateChange?.Invoke(_pagestate);
if (PageState.RenderMode == RenderModes.Interactive)
{
await ScrollToFragment(_pagestate.Uri);
}
}
else
{
if (page == null)
{
// check for url mapping
var urlMapping = await UrlMappingService.GetUrlMappingAsync(site.SiteId, route.PagePath);
if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl))
{ {
Alias = SiteState.Alias, var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl + route.Query;
Site = site, NavigationManager.NavigateTo(url, false);
Page = page, return;
User = user,
Uri = new Uri(_absoluteUri, UriKind.Absolute),
Route = route,
QueryString = querystring,
UrlParameters = route.UrlParameters,
ModuleId = moduleid,
Action = action,
EditMode = editmode,
LastSyncDate = lastsyncdate,
RenderMode = RenderMode,
Runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime),
VisitorId = visitorId,
RemoteIPAddress = SiteState.RemoteIPAddress,
ReturnUrl = returnurl,
IsInternalNavigation = _isInternalNavigation,
RenderId = Guid.NewGuid(),
Refresh = false
};
OnStateChange?.Invoke(_pagestate);
if (PageState.RenderMode == RenderModes.Interactive)
{
await ScrollToFragment(_pagestate.Uri);
} }
} }
else else
{
// Need to redirect 404 as page doesnot exist in a Permission or Timeframe
if (route.PagePath != "404")
{
// redirect to 404 page
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "404", ""));
}
}
}
else // page not found
{
// look for url mapping
var urlMapping = await UrlMappingService.GetUrlMappingAsync(site.SiteId, route.PagePath);
if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl))
{
var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl + route.Query;
NavigationManager.NavigateTo(url, false);
}
else // not mapped
{ {
if (user == null) if (user == null)
{ {
// redirect to login page if user not logged in as they may need to be authenticated // redirect to login page if user not logged in as they may need to be authenticated
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + WebUtility.UrlEncode(route.PathAndQuery))); NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + WebUtility.UrlEncode(route.PathAndQuery)));
return;
} }
else }
{
if (route.PagePath != "404") // page not found or user does not have sufficient access
{ if (route.PagePath != "404")
// redirect to 404 page {
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "404", "")); // redirect to 404 page
} NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "404", ""));
else }
{ else
// redirect to home page as a fallback {
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", "")); // redirect to home page as a fallback
} NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", ""));
}
} }
} }
} }

View File

@ -1,21 +0,0 @@
@attribute [StreamRendering(false)]
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static)
{
<RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" />
}
else
{
<RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, PageState.Site.Prerender)" />
}
@code {
[Parameter]
public SiteState SiteState { get; set; }
[Parameter]
public PageState PageState { get; set; }
[Parameter]
public Module ModuleState { get; set; }
}

View File

@ -1,21 +0,0 @@
@attribute [StreamRendering(true)]
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static)
{
<RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" />
}
else
{
<RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, PageState.Site.Prerender)" />
}
@code {
[Parameter]
public SiteState SiteState { get; set; }
[Parameter]
public PageState PageState { get; set; }
[Parameter]
public Module ModuleState { get; set; }
}

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Version>5.1.0</Version> <Version>5.1.1</Version>
<Product>Oqtane</Product> <Product>Oqtane</Product>
<Authors>Shaun Walker</Authors> <Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company> <Company>.NET Foundation</Company>
@ -10,7 +10,7 @@
<Copyright>.NET Foundation</Copyright> <Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl> <PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl> <RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Version>5.1.0</Version> <Version>5.1.1</Version>
<Product>Oqtane</Product> <Product>Oqtane</Product>
<Authors>Shaun Walker</Authors> <Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company> <Company>.NET Foundation</Company>
@ -10,7 +10,7 @@
<Copyright>.NET Foundation</Copyright> <Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl> <PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl> <RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@ -34,7 +34,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="EFCore.NamingConventions" Version="8.0.3" /> <PackageReference Include="EFCore.NamingConventions" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.4" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
</ItemGroup> </ItemGroup>

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Version>5.1.0</Version> <Version>5.1.1</Version>
<Product>Oqtane</Product> <Product>Oqtane</Product>
<Authors>Shaun Walker</Authors> <Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company> <Company>.NET Foundation</Company>
@ -10,7 +10,7 @@
<Copyright>.NET Foundation</Copyright> <Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl> <PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl> <RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@ -33,7 +33,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Version>5.1.0</Version> <Version>5.1.1</Version>
<Product>Oqtane</Product> <Product>Oqtane</Product>
<Authors>Shaun Walker</Authors> <Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company> <Company>.NET Foundation</Company>
@ -10,7 +10,7 @@
<Copyright>.NET Foundation</Copyright> <Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl> <PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl> <RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@ -33,7 +33,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -6,7 +6,7 @@
<!-- <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks> --> <!-- <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks> -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> --> <!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<Version>5.1.0</Version> <Version>5.1.1</Version>
<Product>Oqtane</Product> <Product>Oqtane</Product>
<Authors>Shaun Walker</Authors> <Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company> <Company>.NET Foundation</Company>
@ -14,7 +14,7 @@
<Copyright>.NET Foundation</Copyright> <Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl> <PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl> <RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane.Maui</RootNamespace> <RootNamespace>Oqtane.Maui</RootNamespace>
@ -31,7 +31,7 @@
<ApplicationIdGuid>0E29FC31-1B83-48ED-B6E0-9F3C67B775D4</ApplicationIdGuid> <ApplicationIdGuid>0E29FC31-1B83-48ED-B6E0-9F3C67B775D4</ApplicationIdGuid>
<!-- Versions --> <!-- Versions -->
<ApplicationDisplayVersion>5.1.0</ApplicationDisplayVersion> <ApplicationDisplayVersion>5.1.1</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion> <ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
@ -65,15 +65,15 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.4" />
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" /> <PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.10" /> <PackageReference Include="Microsoft.Maui.Controls" Version="8.0.20" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.10" /> <PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.20" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="8.0.10" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="8.0.20" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>Oqtane.Client</id> <id>Oqtane.Client</id>
<version>5.1.0</version> <version>5.1.1</version>
<authors>Shaun Walker</authors> <authors>Shaun Walker</authors>
<owners>.NET Foundation</owners> <owners>.NET Foundation</owners>
<title>Oqtane Framework</title> <title>Oqtane Framework</title>
@ -12,7 +12,7 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license> <license type="expression">MIT</license>
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl> <projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</releaseNotes> <releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</releaseNotes>
<icon>icon.png</icon> <icon>icon.png</icon>
<tags>oqtane</tags> <tags>oqtane</tags>
</metadata> </metadata>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>Oqtane.Framework</id> <id>Oqtane.Framework</id>
<version>5.1.0</version> <version>5.1.1</version>
<authors>Shaun Walker</authors> <authors>Shaun Walker</authors>
<owners>.NET Foundation</owners> <owners>.NET Foundation</owners>
<title>Oqtane Framework</title> <title>Oqtane Framework</title>
@ -11,8 +11,8 @@
<copyright>.NET Foundation</copyright> <copyright>.NET Foundation</copyright>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license> <license type="expression">MIT</license>
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v5.1.0/Oqtane.Framework.5.1.0.Upgrade.zip</projectUrl> <projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v5.1.1/Oqtane.Framework.5.1.1.Upgrade.zip</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</releaseNotes> <releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</releaseNotes>
<icon>icon.png</icon> <icon>icon.png</icon>
<tags>oqtane framework</tags> <tags>oqtane framework</tags>
</metadata> </metadata>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>Oqtane.Server</id> <id>Oqtane.Server</id>
<version>5.1.0</version> <version>5.1.1</version>
<authors>Shaun Walker</authors> <authors>Shaun Walker</authors>
<owners>.NET Foundation</owners> <owners>.NET Foundation</owners>
<title>Oqtane Framework</title> <title>Oqtane Framework</title>
@ -12,7 +12,7 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license> <license type="expression">MIT</license>
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl> <projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</releaseNotes> <releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</releaseNotes>
<icon>icon.png</icon> <icon>icon.png</icon>
<tags>oqtane</tags> <tags>oqtane</tags>
</metadata> </metadata>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>Oqtane.Shared</id> <id>Oqtane.Shared</id>
<version>5.1.0</version> <version>5.1.1</version>
<authors>Shaun Walker</authors> <authors>Shaun Walker</authors>
<owners>.NET Foundation</owners> <owners>.NET Foundation</owners>
<title>Oqtane Framework</title> <title>Oqtane Framework</title>
@ -12,7 +12,7 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license> <license type="expression">MIT</license>
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl> <projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</releaseNotes> <releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</releaseNotes>
<icon>icon.png</icon> <icon>icon.png</icon>
<tags>oqtane</tags> <tags>oqtane</tags>
</metadata> </metadata>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>Oqtane.Updater</id> <id>Oqtane.Updater</id>
<version>5.1.0</version> <version>5.1.1</version>
<authors>Shaun Walker</authors> <authors>Shaun Walker</authors>
<owners>.NET Foundation</owners> <owners>.NET Foundation</owners>
<title>Oqtane Framework</title> <title>Oqtane Framework</title>
@ -12,7 +12,7 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license> <license type="expression">MIT</license>
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl> <projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</releaseNotes> <releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</releaseNotes>
<icon>icon.png</icon> <icon>icon.png</icon>
<tags>oqtane</tags> <tags>oqtane</tags>
</metadata> </metadata>

View File

@ -1 +1 @@
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.1.0.Install.zip" -Force Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.1.1.Install.zip" -Force

View File

@ -1 +1 @@
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.1.0.Upgrade.zip" -Force Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.1.1.Upgrade.zip" -Force

View File

@ -76,5 +76,20 @@ namespace Oqtane.Controllers
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
} }
} }
[HttpDelete]
[Authorize(Roles = RoleNames.Admin)]
public void Delete(string siteId)
{
if (int.TryParse(siteId, out int parsedSiteId) && parsedSiteId == _alias.SiteId)
{
_logs.DeleteLogs(parsedSiteId, 0); // specifying zero for age results in all logs being deleted
}
else
{
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Log Delete Attempt {SiteId}", siteId);
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
}
}
} }
} }

View File

@ -365,8 +365,8 @@ namespace Oqtane.Controllers
{ {
{ "FrameworkVersion", moduleDefinition.Version }, { "FrameworkVersion", moduleDefinition.Version },
{ "ClientReference", $"<PackageReference Include=\"Oqtane.Client\" Version=\"{moduleDefinition.Version}\" />" }, { "ClientReference", $"<PackageReference Include=\"Oqtane.Client\" Version=\"{moduleDefinition.Version}\" />" },
{ "ServerReference", $"<PackageReference Include=\"Oqtane.Client\" Version=\"{moduleDefinition.Version}\" />" }, { "ServerReference", $"<PackageReference Include=\"Oqtane.Server\" Version=\"{moduleDefinition.Version}\" />" },
{ "SharedReference", $"<PackageReference Include=\"Oqtane.Client\" Version=\"{moduleDefinition.Version}\" />" }, { "SharedReference", $"<PackageReference Include=\"Oqtane.Shared\" Version=\"{moduleDefinition.Version}\" />" },
}; };
}); });
} }

View File

@ -34,6 +34,7 @@ namespace Oqtane.Controllers
case "environment": case "environment":
systeminfo.Add("CLRVersion", Environment.Version.ToString()); systeminfo.Add("CLRVersion", Environment.Version.ToString());
systeminfo.Add("OSVersion", Environment.OSVersion.ToString()); systeminfo.Add("OSVersion", Environment.OSVersion.ToString());
systeminfo.Add("Process", (Environment.Is64BitProcess) ? "64 Bit" : "32 Bit");
systeminfo.Add("MachineName", Environment.MachineName); systeminfo.Add("MachineName", Environment.MachineName);
systeminfo.Add("WorkingSet", Environment.WorkingSet.ToString()); systeminfo.Add("WorkingSet", Environment.WorkingSet.ToString());
systeminfo.Add("TickCount", Environment.TickCount64.ToString()); systeminfo.Add("TickCount", Environment.TickCount64.ToString());

View File

@ -157,7 +157,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.ConfigureApplicationCookie(options => services.ConfigureApplicationCookie(options =>
{ {
options.Cookie.HttpOnly = true; options.Cookie.HttpOnly = true;
options.Cookie.SameSite = SameSiteMode.Strict; options.Cookie.SameSite = SameSiteMode.Lax;
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
options.Events.OnRedirectToLogin = context => options.Events.OnRedirectToLogin = context =>
{ {

View File

@ -93,6 +93,7 @@ namespace Oqtane.Infrastructure
} }
var result = new StringBuilder(); var result = new StringBuilder();
source = source.Replace("[[", "[$_["); //avoid nested square bracket issue.
foreach (Match match in this.TokenizerRegex.Matches(source)) foreach (Match match in this.TokenizerRegex.Matches(source))
{ {
var key = match.Result("${key}"); var key = match.Result("${key}");
@ -126,7 +127,7 @@ namespace Oqtane.Infrastructure
result.Append(match.Result("${text}")); result.Append(match.Result("${text}"));
} }
} }
result.Replace("[$_", "["); //restore the changes.
return result.ToString(); return result.ToString();
} }

View File

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
<Version>5.1.0</Version> <Version>5.1.1</Version>
<Product>Oqtane</Product> <Product>Oqtane</Product>
<Authors>Shaun Walker</Authors> <Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company> <Company>.NET Foundation</Company>
@ -11,7 +11,7 @@
<Copyright>.NET Foundation</Copyright> <Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl> <PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl> <RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane</RootNamespace> <RootNamespace>Oqtane</RootNamespace>
@ -33,19 +33,19 @@
<EmbeddedResource Include="Scripts\MigrateTenant.sql" /> <EmbeddedResource Include="Scripts\MigrateTenant.sql" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.4" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" /> <PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.3"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.4">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.4" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" /> <PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.4" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="8.0.3" /> <PackageReference Include="Microsoft.Data.Sqlite.Core" Version="8.0.4" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.8" /> <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.8" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -47,14 +47,23 @@ namespace Oqtane.Pages
var sitemap = new List<Sitemap>(); var sitemap = new List<Sitemap>();
// build site map // build site map
var rooturl = _alias.Protocol + (string.IsNullOrEmpty(_alias.Path) ? _alias.Name : _alias.Name.Substring(0, _alias.Name.IndexOf("/")));
var moduleDefinitions = _moduleDefinitions.GetModuleDefinitions(_alias.SiteId).ToList(); var moduleDefinitions = _moduleDefinitions.GetModuleDefinitions(_alias.SiteId).ToList();
var pageModules = _pageModules.GetPageModules(_alias.SiteId); var pageModules = _pageModules.GetPageModules(_alias.SiteId);
foreach (var page in _pages.GetPages(_alias.SiteId)) foreach (var page in _pages.GetPages(_alias.SiteId))
{ {
if (_userPermissions.IsAuthorized(null, PermissionNames.View, page.PermissionList) && page.IsNavigation) if (_userPermissions.IsAuthorized(null, PermissionNames.View, page.PermissionList) && page.IsNavigation)
{ {
var rooturl = _alias.Protocol + (string.IsNullOrEmpty(_alias.Path) ? _alias.Name : _alias.Name.Substring(0, _alias.Name.IndexOf("/"))); var pageurl = rooturl;
sitemap.Add(new Sitemap { Url = rooturl + Utilities.NavigateUrl(_alias.Path, page.Path, ""), ModifiedOn = DateTime.UtcNow }); if (string.IsNullOrEmpty(page.Url))
{
pageurl += Utilities.NavigateUrl(_alias.Path, page.Path, "");
}
else
{
pageurl += (page.Url.StartsWith("/") ? "" : "/") + page.Url;
}
sitemap.Add(new Sitemap { Url = pageurl, ModifiedOn = DateTime.UtcNow });
foreach (var pageModule in pageModules.Where(item => item.PageId == page.PageId)) foreach (var pageModule in pageModules.Where(item => item.PageId == page.PageId))
{ {

View File

@ -59,14 +59,14 @@ namespace Oqtane.Repository
// delete logs in batches of 100 records // delete logs in batches of 100 records
var count = 0; var count = 0;
var purgedate = DateTime.UtcNow.AddDays(-age); var purgedate = DateTime.UtcNow.AddDays(-age);
var logs = db.Log.Where(item => item.SiteId == siteId && item.Level != "Error" && item.LogDate < purgedate) var logs = db.Log.Where(item => item.SiteId == siteId && item.LogDate < purgedate)
.OrderBy(item => item.LogDate).Take(100).ToList(); .OrderBy(item => item.LogDate).Take(100).ToList();
while (logs.Count > 0) while (logs.Count > 0)
{ {
count += logs.Count; count += logs.Count;
db.Log.RemoveRange(logs); db.Log.RemoveRange(logs);
db.SaveChanges(); db.SaveChanges();
logs = db.Log.Where(item => item.SiteId == siteId && item.Level != "Error" && item.LogDate < purgedate) logs = db.Log.Where(item => item.SiteId == siteId && item.LogDate < purgedate)
.OrderBy(item => item.LogDate).Take(100).ToList(); .OrderBy(item => item.LogDate).Take(100).ToList();
} }
return count; return count;

View File

@ -22,6 +22,7 @@ using Oqtane.UI;
using OqtaneSSR.Extensions; using OqtaneSSR.Extensions;
using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Authorization;
using Oqtane.Providers; using Oqtane.Providers;
using Microsoft.AspNetCore.Cors.Infrastructure;
namespace Oqtane namespace Oqtane
{ {
@ -135,7 +136,7 @@ namespace Oqtane
{ {
// allow .NET MAUI client cross origin calls // allow .NET MAUI client cross origin calls
policy.WithOrigins("https://0.0.0.0", "http://0.0.0.0", "app://0.0.0.0") policy.WithOrigins("https://0.0.0.0", "http://0.0.0.0", "app://0.0.0.0")
.AllowAnyHeader().AllowCredentials(); .AllowAnyHeader().AllowAnyMethod().AllowCredentials();
}); });
}); });
@ -169,7 +170,7 @@ namespace Oqtane
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncManager sync, ILogger<Startup> logger) public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncManager sync, ICorsService corsService, ICorsPolicyProvider corsPolicyProvider, ILogger<Startup> logger)
{ {
if (!string.IsNullOrEmpty(_configureServicesErrors)) if (!string.IsNullOrEmpty(_configureServicesErrors))
{ {
@ -198,7 +199,16 @@ namespace Oqtane
app.UseOqtaneLocalization(); app.UseOqtaneLocalization();
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseStaticFiles(); app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
OnPrepareResponse = (ctx) =>
{
var policy = corsPolicyProvider.GetPolicyAsync(ctx.Context, Constants.MauiCorsPolicy)
.ConfigureAwait(false).GetAwaiter().GetResult();
corsService.ApplyResult(corsService.EvaluatePolicy(ctx.Context, policy), ctx.Context.Response);
}
});
app.UseExceptionMiddleWare(); app.UseExceptionMiddleWare();
app.UseTenantResolution(); app.UseTenantResolution();
app.UseJwtAuthorization(); app.UseJwtAuthorization();

View File

@ -13,9 +13,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.4" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.4" />
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" /> <PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<AccelerateBuildsInVisualStudio>false</AccelerateBuildsInVisualStudio>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -19,10 +19,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.4" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -108,12 +108,12 @@
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
if (_login != "-") if (_login != "-")
{ {
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login, true); settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login);
} }
if (_register != "-") if (_register != "-")
{ {
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register, true); settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register);
} }
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
} }

View File

@ -12,9 +12,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.4" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<AccelerateBuildsInVisualStudio>false</AccelerateBuildsInVisualStudio>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -35,6 +35,9 @@ app {
} }
/* Action Dialog */ /* Action Dialog */
.app-actiondialog{
position: absolute;
}
.app-actiondialog .modal { .app-actiondialog .modal {
position: fixed; /* Stay in place */ position: fixed; /* Stay in place */
z-index: 9999; /* Sit on top */ z-index: 9999; /* Sit on top */

View File

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
<Version>5.1.0</Version> <Version>5.1.1</Version>
<Product>Oqtane</Product> <Product>Oqtane</Product>
<Authors>Shaun Walker</Authors> <Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company> <Company>.NET Foundation</Company>
@ -11,7 +11,7 @@
<Copyright>.NET Foundation</Copyright> <Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl> <PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl> <RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane</RootNamespace> <RootNamespace>Oqtane</RootNamespace>
@ -19,8 +19,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.4" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Text.Json" Version="8.0.3" /> <PackageReference Include="System.Text.Json" Version="8.0.3" />

View File

@ -4,8 +4,8 @@ namespace Oqtane.Shared
{ {
public class Constants public class Constants
{ {
public static readonly string Version = "5.1.0"; public static readonly string Version = "5.1.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,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0"; 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,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0,5.1.1";
public const string PackageId = "Oqtane.Framework"; public const string PackageId = "Oqtane.Framework";
public const string ClientId = "Oqtane.Client"; public const string ClientId = "Oqtane.Client";
public const string UpdaterPackageId = "Oqtane.Updater"; public const string UpdaterPackageId = "Oqtane.Updater";

View File

@ -21,86 +21,50 @@ namespace Oqtane.Shared
return $"{type.Namespace}, {assemblyName}"; return $"{type.Namespace}, {assemblyName}";
} }
public static (string UrlParameters, string Querystring, string Fragment) ParseParameters(string url) public static (string UrlParameters, string Querystring, string Fragment) ParseParameters(string parameters)
{ {
// /path/urlparameters
// /urlparameters /urlparameters?Id=1 /urlparameters#5 /urlparameters?Id=1#5 /urlparameters?reload#5 // /urlparameters /urlparameters?Id=1 /urlparameters#5 /urlparameters?Id=1#5 /urlparameters?reload#5
// Id=1 Id=1#5 reload#5 reload // Id=1 Id=1#5 reload#5 reload
// #5 // #5
if (!url.Contains("://")) // create absolute url to convert to Uri
{ parameters = (!parameters.StartsWith("/") && !parameters.StartsWith("#") ? "?" : "") + parameters;
if (!url.StartsWith("/")) // urlparameters always start with "/" parameters = Constants.PackageRegistryUrl + parameters;
{ var uri = new Uri(parameters);
url = ((!url.StartsWith("#")) ? "?" : "/") + url;
}
url = Constants.PackageRegistryUrl + url; // create absolute url
}
var uri = new Uri(url);
var querystring = uri.Query.Replace("?", ""); var querystring = uri.Query.Replace("?", "");
var fragment = uri.Fragment.Replace("#", ""); var fragment = uri.Fragment.Replace("#", "");
var urlparameters = uri.LocalPath; var urlparameters = uri.LocalPath;
urlparameters = (urlparameters == "/") ? "" : urlparameters; urlparameters = (urlparameters == "/") ? "" : urlparameters;
if (urlparameters.Contains(Constants.UrlParametersDelimiter))
{
urlparameters = urlparameters.Substring(urlparameters.IndexOf(Constants.UrlParametersDelimiter) + 1);
}
return (urlparameters, querystring, fragment); return (urlparameters, querystring, fragment);
} }
public static (string Path, string Parameters) ParsePath(string url)
{
url = ((!url.StartsWith("/") && !url.Contains("://")) ? "/" : "") + url;
(string path, string querystring, string fragment) = ParseParameters(url);
var uriBuilder = new UriBuilder
{
Path = path,
Query = querystring,
Fragment = fragment
};
return (uriBuilder.Path, uriBuilder.Uri.Query + uriBuilder.Uri.Fragment);
}
public static string NavigateUrl(string alias, string path, string parameters) public static string NavigateUrl(string alias, string path, string parameters)
{ {
string querystring = "";
string fragment = "";
if (!string.IsNullOrEmpty(parameters)) if (!string.IsNullOrEmpty(parameters))
{ {
// parse path
(path, _) = ParsePath(path);
// parse parameters // parse parameters
(string urlparameters, string querystring, string fragment) = ParseParameters(parameters); (string urlparameters, querystring, fragment) = ParseParameters(parameters);
// add urlparameters to path
if (!string.IsNullOrEmpty(urlparameters)) if (!string.IsNullOrEmpty(urlparameters))
{ {
if (urlparameters.StartsWith("/")) urlparameters = urlparameters.Remove(0, 1); path += (path.EndsWith("/") ? "" : "/") + $"{Constants.UrlParametersDelimiter}/{urlparameters.Substring(1)}";
path += $"/{Constants.UrlParametersDelimiter}/{urlparameters}";
} }
// build url
var uriBuilder = new UriBuilder
{
Path = !string.IsNullOrEmpty(alias)
? (!string.IsNullOrEmpty(path)) ? $"{alias}{path}": $"{alias}"
: $"{path}",
Query = querystring,
Fragment = fragment
};
path = uriBuilder.Uri.PathAndQuery;
} }
else
// build url
var uriBuilder = new UriBuilder
{ {
path = ((!string.IsNullOrEmpty(alias)) ? alias + (!path.StartsWith("/") ? "/" : "") : "") + path; Path = !string.IsNullOrEmpty(alias)
} ? (!string.IsNullOrEmpty(path)) ? $"{alias}{path}": $"{alias}"
: $"{path}",
Query = querystring,
Fragment = fragment
};
return path; return uriBuilder.Uri.PathAndQuery;
} }
public static string EditUrl(string alias, string path, int moduleid, string action, string parameters) public static string EditUrl(string alias, string path, int moduleid, string action, string parameters)
@ -185,6 +149,7 @@ namespace Oqtane.Shared
break; break;
case "render": case "render":
content = content.Replace(Constants.FileUrl, alias?.BaseUrl + aliasUrl + Constants.FileUrl); content = content.Replace(Constants.FileUrl, alias?.BaseUrl + aliasUrl + Constants.FileUrl);
content = content.Replace("[wwwroot]", alias?.BaseUrl + aliasUrl + "/");
// legacy // legacy
content = content.Replace("[siteroot]", UrlCombine("Content", "Tenants", alias.TenantId.ToString(), "Sites", alias.SiteId.ToString())); content = content.Replace("[siteroot]", UrlCombine("Content", "Tenants", alias.TenantId.ToString(), "Sites", alias.SiteId.ToString()));
content = content.Replace(Constants.ContentUrl, alias.Path + Constants.ContentUrl); content = content.Replace(Constants.ContentUrl, alias.Path + Constants.ContentUrl);

View File

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<Version>5.1.0</Version> <Version>5.1.1</Version>
<Product>Oqtane</Product> <Product>Oqtane</Product>
<Authors>Shaun Walker</Authors> <Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company> <Company>.NET Foundation</Company>
@ -11,7 +11,7 @@
<Copyright>.NET Foundation</Copyright> <Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl> <PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl> <RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType> <RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane</RootNamespace> <RootNamespace>Oqtane</RootNamespace>

View File

@ -1,6 +1,6 @@
# Latest Release # Latest Release
[5.0.2](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2) was released on Jan 25, 2024 and is a stabilization release targeted at .NET 8. This release includes 51 pull requests by 6 different contributors, pushing the total number of project commits all-time to over 4600. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers. [5.1.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0) was released on Mar 27, 2024 and is a major release providing Static Server Rendering support for Blazor in .NET 8. This release includes 263 pull requests by 6 different contributors, pushing the total number of project commits all-time to over 5100. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Foqtane%2Foqtane.framework%2Fmaster%2Fazuredeploy.json) [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Foqtane%2Foqtane.framework%2Fmaster%2Fazuredeploy.json)
@ -63,8 +63,12 @@ Backlog (TBD)
- [ ] Folder Providers - [ ] Folder Providers
- [ ] Generative AI Integration - [ ] Generative AI Integration
5.1.0 (Q1 2024) 5.1.1 (Apr 2024)
- [ ] Full Stack Blazor (Static Server-Side Rendering) - [ ] Stabilization improvements
[5.1.0](https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0) (Mar 27, 2024)
- [x] Migration to the new unified Blazor approach in .NET 8 (ie. blazor.web.js)
- [x] Static Server Rendering (SSR) support
[5.0.2](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2) (Jan 25, 2024) [5.0.2](https://github.com/oqtane/oqtane.framework/releases/tag/v5.0.2) (Jan 25, 2024)
- [x] Stabilization improvements - [x] Stabilization improvements