Compare commits
225 Commits
Author | SHA1 | Date | |
---|---|---|---|
e95ae8dbcf | |||
5fbd64da71 | |||
b282a2a621 | |||
9a7a534051 | |||
52fd030b6e | |||
dfe530a764 | |||
b079956075 | |||
e30037c4d1 | |||
eda7be627c | |||
af0a649656 | |||
8b6a3c4236 | |||
0988a92d8a | |||
9cf67764b7 | |||
6c4e1d1c41 | |||
b1cd1ea8b3 | |||
5169ed494c | |||
824211c31b | |||
be3dd83bc7 | |||
c2911c1e48 | |||
9a66c5c07d | |||
34d393b986 | |||
d4da02318d | |||
47162af6d5 | |||
8cd6a72dd3 | |||
ba0a183b6f | |||
73781c7edb | |||
6d99852c81 | |||
9325c726fd | |||
947bb8530e | |||
2b32f316ee | |||
4b1f23a189 | |||
71d220e7a4 | |||
747d0d0d17 | |||
5c72e6d335 | |||
e1ac2b0e10 | |||
0ba94f3bc9 | |||
ba0bfafcd5 | |||
81adb80b7e | |||
cb238ef170 | |||
b9b921de82 | |||
d10e31c278 | |||
fd641d77c7 | |||
2aa9710dd1 | |||
4afb2ef2b8 | |||
a54e6e7c4b | |||
7af26a356f | |||
2f66165f8c | |||
e86ce8fc38 | |||
9b48c65129 | |||
434cd133df | |||
aa91e4cdee | |||
d57c1e7ff0 | |||
13e97703e5 | |||
c597b293b8 | |||
6620d64ce7 | |||
2ae120c878 | |||
7a25035fb1 | |||
bf4052b550 | |||
5ca5ad2cee | |||
2848f1e13c | |||
f7895823cb | |||
b841c5c5e5 | |||
a7952a4633 | |||
d047d26dbf | |||
ddedc1640f | |||
021d7e5efc | |||
332e528012 | |||
a0155da06b | |||
d58d22adbe | |||
653352bff0 | |||
4f5b33d8df | |||
7e7d83ac36 | |||
0de5c043bb | |||
ec2769ea3c | |||
3f742f5f8e | |||
50849101d4 | |||
1ccf4a74c9 | |||
7cd4967963 | |||
21e2700da5 | |||
395a68ad80 | |||
b7f0132675 | |||
4ac827b9e8 | |||
d96963862e | |||
53217b061d | |||
4770daa7c6 | |||
2b709ad094 | |||
378b81b13b | |||
56ee72214f | |||
2e7c3167f5 | |||
a2fb728d3b | |||
be1c936e90 | |||
af8037ab03 | |||
3b8dc98226 | |||
b411b4e61b | |||
436eb30490 | |||
09b8087787 | |||
4ac4c69820 | |||
3ebc5c0865 | |||
7b94f8f105 | |||
ec994b3e97 | |||
86ae0182fd | |||
bfa891f0ca | |||
ef843cac63 | |||
78d68d0a4f | |||
4bceba777d | |||
2e537b1e5e | |||
df8463b625 | |||
f40371e0cf | |||
a565e7aed6 | |||
c948361090 | |||
4cf2b74a01 | |||
de9c8362ac | |||
b5bb5d35e7 | |||
d910cfa919 | |||
5857e3d5c6 | |||
25daa343c6 | |||
85224c8f0c | |||
5f8583e3eb | |||
062821d267 | |||
1fdaaf82d2 | |||
e4c1b17810 | |||
70057542c1 | |||
f2255ee707 | |||
791cc70b09 | |||
24dcb9973b | |||
adfd0d5c18 | |||
cfb128acb8 | |||
1e8e246ffb | |||
6162244730 | |||
86cbdf2442 | |||
5334626efb | |||
708d473b47 | |||
ead954ddaa | |||
294f511b9a | |||
b5ebcc3e07 | |||
7b8e7ac5c2 | |||
904d39beac | |||
8958b61fdd | |||
09293f7d9a | |||
d520c3d674 | |||
430e616328 | |||
976ad5fcee | |||
4d58ee2162 | |||
03b6abe5ec | |||
4479304f3f | |||
ed83405254 | |||
b815d945d9 | |||
2b8e024f48 | |||
2a0399b98d | |||
4e333e2d75 | |||
4f25b7bbbe | |||
3678db649b | |||
9d8b1fd99b | |||
7b62c06be3 | |||
bc978a91e3 | |||
611ba97b60 | |||
39dff1ea7c | |||
bcf7bcba1d | |||
8f00730189 | |||
1dde79ace2 | |||
5954fb91be | |||
e192383662 | |||
4a20fad4e5 | |||
a469e0864e | |||
cfce2bdbd9 | |||
529b5c0a00 | |||
7cc5787779 | |||
48eeb279e2 | |||
d67566252a | |||
8a2d79e17d | |||
17370dff54 | |||
f08a8e7634 | |||
83543bbddc | |||
b898c90f41 | |||
1ec927cf4f | |||
aef21ba9d5 | |||
0b31709aee | |||
7c3433256a | |||
c79c638f35 | |||
a148941a39 | |||
23abe26b0b | |||
8f21d6dde0 | |||
b74a6c9e03 | |||
b63f73ef93 | |||
1f0b369a15 | |||
7a43473513 | |||
07f367a2a5 | |||
c52ad68d92 | |||
85467dbd2a | |||
aa767846f0 | |||
6d3ad15d20 | |||
7b95db4d13 | |||
160b3ff655 | |||
757a39a75e | |||
4c08a527be | |||
578b7b0512 | |||
45e0259099 | |||
1ac1933ec1 | |||
43353e89bb | |||
010e4610f7 | |||
ba38853406 | |||
4944a9e51e | |||
73ad97859c | |||
e600da229c | |||
273b4f20db | |||
9843dccdf0 | |||
60ae1ec1e8 | |||
650c6670f2 | |||
d6dcba7a60 | |||
5b3849082f | |||
5de988a2e6 | |||
26220b2f54 | |||
8d8436f1f1 | |||
93057d9449 | |||
b2419abdc8 | |||
9f654918ae | |||
cb086fe08d | |||
1482166ba3 | |||
6b8dd9bf03 | |||
a8af9da249 | |||
e410f82fdb | |||
4f70f228f1 | |||
ddc97b99fa | |||
5f42918cc9 | |||
e6dfe6fe89 |
26
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
26
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal 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?
|
20
.github/ISSUE_TEMPLATE/enhancement-request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/enhancement-request.md
vendored
Normal 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?
|
@ -170,6 +170,7 @@
|
||||
try
|
||||
{
|
||||
Folder folder;
|
||||
|
||||
if (_folderId != -1)
|
||||
{
|
||||
folder = await FolderService.GetFolderAsync(_folderId);
|
||||
@ -179,8 +180,6 @@
|
||||
folder = new Folder();
|
||||
}
|
||||
|
||||
folder.SiteId = PageState.Site.SiteId;
|
||||
|
||||
if (_parentId == -1)
|
||||
{
|
||||
folder.ParentId = null;
|
||||
@ -189,7 +188,15 @@
|
||||
{
|
||||
folder.ParentId = _parentId;
|
||||
}
|
||||
|
||||
// check for duplicate folder names
|
||||
if (_folders.Any(item => item.ParentId == folder.ParentId && item.Name == _name && item.FolderId != _folderId))
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Folder.Duplicate"], MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
folder.SiteId = PageState.Site.SiteId;
|
||||
folder.Name = _name;
|
||||
folder.Type = _type;
|
||||
folder.ImageSizes = _imagesizes;
|
||||
|
@ -26,8 +26,8 @@ else
|
||||
<th style="width: 1px;"> </th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="EditJob" /></td>
|
||||
<td><ActionLink Action="Log" Class="btn btn-secondary" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="JobLog" /></td>
|
||||
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="EditJob" /></td>
|
||||
<td><ActionLink Action="Log" Text="Log" Class="btn btn-secondary" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="JobLog" /></td>
|
||||
<td>@context.Name</td>
|
||||
<td>@DisplayStatus(context.IsEnabled, context.IsExecuting)</td>
|
||||
<td>@DisplayFrequency(context.Interval, context.Frequency)</td>
|
||||
|
@ -63,7 +63,7 @@ else
|
||||
<th>@Localizer["Function"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"/{context.LogId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_level, _function, _rows, _page)))" ResourceKey="LogDetails" /></td>
|
||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Text="Details" Parameters="@($"/{context.LogId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_level, _function, _rows, _page)))" ResourceKey="LogDetails" /></td>
|
||||
<td class="@GetClass(context.Function)">@context.LogDate</td>
|
||||
<td class="@GetClass(context.Function)">@context.Level</td>
|
||||
<td class="@GetClass(context.Function)">@context.Feature</td>
|
||||
@ -86,47 +86,48 @@ else
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _level = "-";
|
||||
private string _function = "-";
|
||||
private string _rows = "10";
|
||||
private int _page = 1;
|
||||
private List<Log> _logs;
|
||||
private int _retention = 30;
|
||||
private string _level = "-";
|
||||
private string _function = "-";
|
||||
private string _rows = "10";
|
||||
private int _page = 1;
|
||||
private List<Log> _logs;
|
||||
private int _retention = 30;
|
||||
|
||||
public override string UrlParametersTemplate => "/{level}/{function}/{rows}/{page}";
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
public override string UrlParametersTemplate => "/{level}/{function}/{rows}/{page}";
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (UrlParameters.ContainsKey("level"))
|
||||
{
|
||||
_level = UrlParameters["level"];
|
||||
}
|
||||
if (UrlParameters.ContainsKey("function"))
|
||||
{
|
||||
_function = UrlParameters["function"];
|
||||
}
|
||||
if (UrlParameters.ContainsKey("rows"))
|
||||
{
|
||||
_rows = UrlParameters["rows"];
|
||||
}
|
||||
if (UrlParameters.ContainsKey("page") && int.TryParse(UrlParameters["page"], out int page))
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (UrlParameters.ContainsKey("level"))
|
||||
{
|
||||
_level = UrlParameters["level"];
|
||||
}
|
||||
if (UrlParameters.ContainsKey("function"))
|
||||
{
|
||||
_function = UrlParameters["function"];
|
||||
}
|
||||
if (UrlParameters.ContainsKey("rows"))
|
||||
{
|
||||
_rows = UrlParameters["rows"];
|
||||
}
|
||||
if (UrlParameters.ContainsKey("page") && int.TryParse(UrlParameters["page"], out int page))
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
|
||||
await GetLogs();
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_retention = int.Parse( SettingService.GetSetting(settings, "LogRetention", "30"));
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_retention = int.Parse( SettingService.GetSetting(settings, "LogRetention", "30"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -213,22 +214,37 @@ else
|
||||
return classname;
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "LogRetention", _retention.ToString(), true);
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "LogRetention", _retention.ToString(), true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||
|
||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -32,7 +32,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="categories" HelpText="Comma delimited list of module categories" ResourceKey="Categories">Categories: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required />
|
||||
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -306,10 +306,9 @@
|
||||
_languages = _languages.OrderBy(item => item.Name).ToList();
|
||||
}
|
||||
|
||||
// Group modules by PageId
|
||||
// Get distinct PageIds where modules are present
|
||||
// get distinct pages where module exists
|
||||
var distinctPageIds = PageState.Modules
|
||||
.Where(md => md.ModuleDefinition.ModuleDefinitionId == _moduleDefinitionId && md.IsDeleted == false)
|
||||
.Where(md => md.ModuleDefinition?.ModuleDefinitionId == _moduleDefinitionId && md.IsDeleted == false)
|
||||
.Select(md => md.PageId)
|
||||
.Distinct();
|
||||
|
||||
|
@ -50,7 +50,7 @@ else
|
||||
<th style="width: 1px;"> </th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" ResourceKey="EditModule" /></td>
|
||||
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" ResourceKey="EditModule" /></td>
|
||||
<td>
|
||||
@if (context.AssemblyName != Constants.ClientId)
|
||||
{
|
||||
|
@ -94,7 +94,7 @@
|
||||
</div>
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Permissions" ResourceKey="Permissions">
|
||||
<TabPanel Name="Permissions" Heading="Permissions" ResourceKey="Permissions">
|
||||
@if (_permissions != null)
|
||||
{
|
||||
<div class="container">
|
||||
@ -126,9 +126,8 @@
|
||||
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
|
||||
</form>
|
||||
|
||||
@code {
|
||||
@code {
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
public override string Title => "Module Settings";
|
||||
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
@ -144,7 +143,7 @@
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _moduleSettingsType;
|
||||
private object _moduleSettings;
|
||||
private string _moduleSettingsTitle = "Module Settings";
|
||||
private string _moduleSettingsTitle;
|
||||
private RenderFragment ModuleSettingsComponent { get; set; }
|
||||
private Type _containerSettingsType;
|
||||
private object _containerSettings;
|
||||
@ -158,8 +157,10 @@
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
SetModuleTitle(Localizer["ModuleSettings.Title"]);
|
||||
_module = ModuleState.ModuleDefinition.Name;
|
||||
_title = ModuleState.Title;
|
||||
_moduleSettingsTitle = Localizer["ModuleSettings.Heading"];
|
||||
_pane = ModuleState.Pane;
|
||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
||||
_containerType = ModuleState.ContainerType;
|
||||
@ -172,7 +173,8 @@
|
||||
modifiedon = ModuleState.ModifiedOn;
|
||||
_effectivedate = Utilities.UtcAsLocalDate(ModuleState.EffectiveDate);
|
||||
_expirydate = Utilities.UtcAsLocalDate(ModuleState.ExpiryDate);
|
||||
|
||||
|
||||
|
||||
if (ModuleState.ModuleDefinition != null)
|
||||
{
|
||||
_permissionNames = ModuleState.ModuleDefinition?.PermissionNames;
|
||||
|
@ -198,12 +198,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</TabPanel>
|
||||
@if (_themeSettingsType != null)
|
||||
{
|
||||
<TabPanel Name="ThemeSettings" Heading=@Localizer["Theme.Heading"] ResourceKey="ThemeSettings">
|
||||
@_themeSettingsComponent
|
||||
</TabPanel>
|
||||
}
|
||||
</TabStrip>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||
@ -238,9 +232,6 @@
|
||||
private string _bodycontent;
|
||||
private string _permissions = null;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _themeSettingsType;
|
||||
private object _themeSettings;
|
||||
private RenderFragment _themeSettingsComponent { get; set; }
|
||||
private bool _refresh = false;
|
||||
protected Page _parent = null;
|
||||
protected Dictionary<string, string> _icons;
|
||||
@ -281,7 +272,6 @@
|
||||
}
|
||||
_effectivedate = Utilities.UtcAsLocalDate(PageState.Page.EffectiveDate);
|
||||
_expirydate = Utilities.UtcAsLocalDate(PageState.Page.ExpiryDate);
|
||||
ThemeSettings();
|
||||
_initialized = true;
|
||||
}
|
||||
else
|
||||
@ -324,7 +314,6 @@
|
||||
_themetype = (string)e.Value;
|
||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||
_containertype = _containers.First().TypeName;
|
||||
ThemeSettings();
|
||||
StateHasChanged();
|
||||
|
||||
// if theme chosen is different than default site theme, display warning message to user
|
||||
@ -334,28 +323,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void ThemeSettings()
|
||||
{
|
||||
_themeSettingsType = null;
|
||||
_themeSettingsComponent = null;
|
||||
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
|
||||
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
|
||||
{
|
||||
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
|
||||
if (_themeSettingsType != null)
|
||||
{
|
||||
_themeSettingsComponent = builder =>
|
||||
{
|
||||
builder.OpenComponent(0, _themeSettingsType);
|
||||
builder.AddAttribute(1, "RenderModeBoundary", RenderModeBoundary);
|
||||
builder.AddComponentReferenceCapture(2, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
_refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SavePage()
|
||||
{
|
||||
validated = true;
|
||||
@ -385,45 +352,34 @@
|
||||
page.ParentId = Int32.Parse(_parentid);
|
||||
}
|
||||
|
||||
// path can be a link to an external url
|
||||
if (!_path.Contains("://"))
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
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(_path.LastIndexOf("/") + 1);
|
||||
_path = _path.Substring(0, _path.Length - 1);
|
||||
}
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
page.Path = Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
page.Path = Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
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);
|
||||
@ -493,18 +449,11 @@
|
||||
await logger.LogInformation("Page Added {Page}", page);
|
||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||
{
|
||||
NavigationManager.NavigateTo(PageState.ReturnUrl, true);
|
||||
NavigationManager.NavigateTo(page.Path, true); // redirect to page added and reload
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!page.Path.Contains("://"))
|
||||
{
|
||||
NavigationManager.NavigateTo(page.Path); // redirect to new page created
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl("admin/pages"));
|
||||
}
|
||||
NavigationManager.NavigateTo(NavigateUrl()); // redirect to page management
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1,5 +1,6 @@
|
||||
@namespace Oqtane.Modules.Admin.Pages
|
||||
@using Oqtane.Interfaces
|
||||
@using System.Globalization
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IPageService PageService
|
||||
@ -362,7 +363,7 @@
|
||||
_parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId);
|
||||
}
|
||||
_children = new List<Page>();
|
||||
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture))))
|
||||
{
|
||||
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||
{
|
||||
@ -380,7 +381,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_path.Contains("/") & !_path.Contains("://"))
|
||||
if (_path.Contains("/"))
|
||||
{
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
@ -529,45 +530,34 @@
|
||||
_page.ParentId = Int32.Parse(_parentid);
|
||||
}
|
||||
|
||||
// path can be a link to an external url
|
||||
if (!_path.Contains("://"))
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
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(_path.LastIndexOf("/") + 1);
|
||||
_path = _path.Substring(0, _path.Length - 1);
|
||||
}
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
_page.Path = Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
_page.Path = Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
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);
|
||||
@ -654,18 +644,11 @@
|
||||
await logger.LogInformation("Page Saved {Page}", _page);
|
||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||
{
|
||||
NavigationManager.NavigateTo(PageState.ReturnUrl, true);
|
||||
NavigationManager.NavigateTo(PageState.ReturnUrl, true); // redirect to page being edited and reload
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_page.Path.Contains("://"))
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(), true); // redirect to page being edited
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl("admin/pages"));
|
||||
}
|
||||
NavigationManager.NavigateTo(NavigateUrl()); // redirect to page management
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -17,7 +17,7 @@
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.PageId.ToString())" ResourceKey="EditPage" /></td>
|
||||
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.PageId.ToString())" ResourceKey="EditPage" /></td>
|
||||
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
||||
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => NavigationManager.NavigateTo(Browse(context)))">@Localizer["Browse"]</button></td>
|
||||
<td>@(new string('-', context.Level * 2))@(context.Name)</td>
|
||||
|
@ -22,7 +22,7 @@ else
|
||||
<th>@Localizer["Order"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditProfile" /></td>
|
||||
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditProfile" /></td>
|
||||
<td><ActionDialog Header="Delete Profile" Message="@string.Format(Localizer["Confirm.Profile.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Title</td>
|
||||
|
@ -20,9 +20,9 @@ else
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" Disabled="@(context.IsSystem)" ResourceKey="Edit" /></td>
|
||||
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" Disabled="@(context.IsSystem)" ResourceKey="Edit" /></td>
|
||||
<td><ActionDialog Header="Delete Role" Message="@string.Format(Localizer["Confirm.DeleteUser"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteRole(context))" Disabled="@(context.IsSystem)" ResourceKey="DeleteRole" /></td>
|
||||
<td><ActionLink Action="Users" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Users" /></td>
|
||||
<td><ActionLink Action="Users" Text="Users" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Users" /></td>
|
||||
<td>@context.Name</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
|
@ -319,7 +319,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="rendermode" HelpText="The default render mode for the site" ResourceKey="Rendermode">Render Mode: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="rendermode" class="form-select" @bind="@_rendermode" required>
|
||||
<select id="rendermode" class="form-select" value="@_rendermode" @onchange="(e => RenderModeChanged(e))" required>
|
||||
<option value="@RenderModes.Interactive">@(SharedLocalizer["RenderMode" + @RenderModes.Interactive])</option>
|
||||
<option value="@RenderModes.Static">@(SharedLocalizer["RenderMode" + @RenderModes.Static])</option>
|
||||
<option value="@RenderModes.Headless">@(SharedLocalizer["RenderMode" + @RenderModes.Headless])</option>
|
||||
@ -337,7 +337,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="prerender" HelpText="Specifies if interactive components should prerender their output" ResourceKey="Prerender">Prerender? </Label>
|
||||
<Label Class="col-sm-3" For="prerender" HelpText="Specifies if interactive components should prerender their output on the server" ResourceKey="Prerender">Prerender: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="prerender" class="form-select" @bind="@_prerender" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
@ -572,6 +572,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderModeChanged(ChangeEventArgs e)
|
||||
{
|
||||
_rendermode = (string)e.Value;
|
||||
switch (_rendermode)
|
||||
{
|
||||
case RenderModes.Interactive:
|
||||
_prerender = "True";
|
||||
break;
|
||||
case RenderModes.Static:
|
||||
_prerender = "False";
|
||||
break;
|
||||
case RenderModes.Headless:
|
||||
_prerender = "False";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveSite()
|
||||
{
|
||||
validated = true;
|
||||
|
@ -26,6 +26,12 @@
|
||||
<input id="osversion" class="form-control" @bind="@_osversion" readonly />
|
||||
</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">
|
||||
<Label Class="col-sm-3" For="machinename" HelpText="Machine Name" ResourceKey="MachineName">Machine Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -62,12 +68,6 @@
|
||||
<input id="servertime" class="form-control" @bind="@_servertime" readonly />
|
||||
</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">
|
||||
<Label Class="col-sm-3" For="workingset" HelpText="Memory Allocation Of Service (in MB)" ResourceKey="WorkingSet">Memory Allocation: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -165,13 +165,13 @@
|
||||
private string _version = string.Empty;
|
||||
private string _clrversion = 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 _environment = string.Empty;
|
||||
private string _contentrootpath = string.Empty;
|
||||
private string _webrootpath = string.Empty;
|
||||
private string _servertime = string.Empty;
|
||||
private string _tickcount = string.Empty;
|
||||
private string _workingset = string.Empty;
|
||||
private string _installationid = string.Empty;
|
||||
|
||||
@ -192,13 +192,13 @@
|
||||
{
|
||||
_clrversion = systeminfo["CLRVersion"].ToString();
|
||||
_osversion = systeminfo["OSVersion"].ToString();
|
||||
_machinename = systeminfo["MachineName"].ToString();
|
||||
_process = systeminfo["Process"].ToString();
|
||||
_machinename = systeminfo["MachineName"].ToString();
|
||||
_ipaddress = systeminfo["IPAddress"].ToString();
|
||||
_environment = systeminfo["Environment"].ToString();
|
||||
_contentrootpath = systeminfo["ContentRootPath"].ToString();
|
||||
_webrootpath = systeminfo["WebRootPath"].ToString();
|
||||
_servertime = systeminfo["ServerTime"].ToString() + " UTC";
|
||||
_tickcount = TimeSpan.FromMilliseconds(Convert.ToInt64(systeminfo["TickCount"].ToString())).ToString();
|
||||
_workingset = (Convert.ToInt64(systeminfo["WorkingSet"].ToString()) / 1000000).ToString() + " MB";
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ else
|
||||
<th> </th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ThemeId.ToString())" ResourceKey="EditTheme" /></td>
|
||||
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ThemeId.ToString())" ResourceKey="EditTheme" /></td>
|
||||
<td>
|
||||
@if (context.AssemblyName != Constants.ClientId)
|
||||
{
|
||||
@ -63,7 +63,6 @@ else
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadTheme(context.PackageName, version))>@SharedLocalizer["Upgrade"]</button>
|
||||
}
|
||||
</td>
|
||||
<td></td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ else
|
||||
<th>@Localizer["Requested"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.UrlMappingId.ToString())" ResourceKey="Edit" /></td>
|
||||
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.UrlMappingId.ToString())" ResourceKey="Edit" /></td>
|
||||
<td><ActionDialog Header="Delete Url Mapping" Message="@string.Format(Localizer["Confirm.DeleteUrlMapping"], context.Url)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUrlMapping(context))" ResourceKey="DeleteUrlMapping" /></td>
|
||||
<td>
|
||||
<a href="@Utilities.TenantUrl(PageState.Alias, context.Url)">@context.Url</a>
|
||||
|
@ -226,11 +226,6 @@
|
||||
user.Password = _password;
|
||||
user.Email = email;
|
||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||
user.PhotoFileId = null;
|
||||
if (user.PhotoFileId == -1)
|
||||
{
|
||||
user.PhotoFileId = null;
|
||||
}
|
||||
|
||||
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
||||
|
||||
|
@ -32,13 +32,13 @@ else
|
||||
</Header>
|
||||
<Row>
|
||||
<td>
|
||||
<ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditUser" />
|
||||
<ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditUser" />
|
||||
</td>
|
||||
<td>
|
||||
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId)" ResourceKey="DeleteUser" />
|
||||
</td>
|
||||
<td>
|
||||
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
|
||||
<ActionLink Action="Roles" Text="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
|
||||
</td>
|
||||
<td>@context.User.Username</td>
|
||||
<td>@context.User.DisplayName</td>
|
||||
|
@ -43,7 +43,7 @@ else
|
||||
<th>@Localizer["Created"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Detail" Parameters="@($"id={context.VisitorId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, $"type={_type}&days={_days}&page={_page}"))" ResourceKey="Details" /></td>
|
||||
<td><ActionLink Action="Detail" Text="Detail" Parameters="@($"id={context.VisitorId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, $"type={_type}&days={_days}&page={_page}"))" ResourceKey="Details" /></td>
|
||||
<td>@context.IPAddress</td>
|
||||
<td>
|
||||
@if (context.UserId != null)
|
||||
@ -69,14 +69,20 @@ else
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="duration" HelpText="The duration of a browsing session considered to be a distinct visit (in minutes)" ResourceKey="Duration">Session Duration: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="duration" class="form-control" type="number" min="0" step="1" @bind="@_duration" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="filter" HelpText="Comma delimited list of terms which may exist in IP addresses, user agents, or languages identifying visitors which should not be tracked" ResourceKey="Filter">Filter: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="filter" class="form-control" @bind="@_filter" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of visitor activity to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of visitor activity to retain" ResourceKey="Retention">Retention: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
|
||||
</div>
|
||||
@ -103,7 +109,8 @@ else
|
||||
private int _page = 1;
|
||||
private List<Visitor> _visitors;
|
||||
private string _tracking;
|
||||
private string _filter = "";
|
||||
private int _duration = 5;
|
||||
private string _filter = "";
|
||||
private int _retention = 30;
|
||||
private string _correlation = "true";
|
||||
|
||||
@ -128,7 +135,8 @@ else
|
||||
|
||||
_tracking = PageState.Site.VisitorTracking.ToString();
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
|
||||
_duration = int.Parse(SettingService.GetSetting(settings, "VisitorDuration", "5"));
|
||||
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
|
||||
_retention = int.Parse(SettingService.GetSetting(settings, "VisitorRetention", "30"));
|
||||
_correlation = SettingService.GetSetting(settings, "VisitorCorrelation", "true");
|
||||
}
|
||||
@ -179,7 +187,8 @@ else
|
||||
await SiteService.UpdateSiteAsync(site);
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
|
||||
settings = SettingService.SetSetting(settings, "VisitorDuration", _duration.ToString(), true);
|
||||
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
|
||||
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention.ToString(), true);
|
||||
settings = SettingService.SetSetting(settings, "VisitorCorrelation", _correlation, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||
|
@ -35,11 +35,11 @@
|
||||
{
|
||||
if (Disabled)
|
||||
{
|
||||
<button type="button" class="@Class" disabled>@((MarkupString)_iconSpan) @Text</button>
|
||||
<button type="button" class="@Class" disabled>@((MarkupString)_openIconSpan) @_openText</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="@Class" @onclick="DisplayModal">@((MarkupString)_iconSpan) @Text</button>
|
||||
<button type="button" class="@Class" @onclick="DisplayModal">@((MarkupString)_openIconSpan) @_openText</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,7 +54,7 @@ else
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@Header</h5>
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
@ -65,12 +65,12 @@ else
|
||||
@if (!string.IsNullOrEmpty(Action))
|
||||
{
|
||||
<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>
|
||||
</form>
|
||||
}
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
@ -83,13 +83,13 @@ else
|
||||
{
|
||||
if (Disabled)
|
||||
{
|
||||
<button type="button" class="@Class" disabled>@((MarkupString)_iconSpan) @Text</button>
|
||||
<button type="button" class="@Class" disabled>@((MarkupString)_openIconSpan) @_openText</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form method="post" @formname="@($"ActionDialogActionForm{Id}")" @onsubmit="DisplayModal" data-enhance>
|
||||
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||
<button type="submit" class="@Class">@((MarkupString)_iconSpan) @Text</button>
|
||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||
<button type="submit" class="@Class">@((MarkupString)_openIconSpan) @_openText</button>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
@ -101,6 +101,8 @@ else
|
||||
private bool _editmode = false;
|
||||
private bool _authorized = false;
|
||||
private string _iconSpan = string.Empty;
|
||||
private string _openIconSpan = string.Empty;
|
||||
private string _openText = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string Header { get; set; } // required
|
||||
@ -138,6 +140,9 @@ else
|
||||
[Parameter]
|
||||
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
||||
|
||||
[Parameter]
|
||||
public bool IconOnly { get; set; } // optional - specifies only icon in opening link
|
||||
|
||||
[Parameter]
|
||||
public string Id { get; set; } // optional - specifies a unique id for the compoment - required when there are multiple component instances on a page in static rendering
|
||||
|
||||
@ -157,6 +162,8 @@ else
|
||||
{
|
||||
Text = Action;
|
||||
}
|
||||
_openText = Text;
|
||||
|
||||
if (string.IsNullOrEmpty(Class))
|
||||
{
|
||||
Class = "btn btn-success";
|
||||
@ -169,11 +176,17 @@ else
|
||||
|
||||
if (!string.IsNullOrEmpty(IconName))
|
||||
{
|
||||
if (IconOnly)
|
||||
{
|
||||
_openText = string.Empty;
|
||||
}
|
||||
|
||||
if (!IconName.Contains(" "))
|
||||
{
|
||||
IconName = "oi oi-" + IconName;
|
||||
}
|
||||
_iconSpan = $"<span class=\"{IconName}\"></span> ";
|
||||
_openIconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
||||
_iconSpan = $"<span class=\"{IconName}\"></span> ";
|
||||
}
|
||||
|
||||
Text = Localize(nameof(Text), Text);
|
||||
|
@ -99,7 +99,7 @@
|
||||
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
_text = Localize(nameof(Text), _text);
|
||||
_text = Localize(nameof(Text), Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -6,23 +6,24 @@
|
||||
{
|
||||
<div class="@_classname alert-dismissible fade show mb-3" role="alert">
|
||||
@((MarkupString)Message)
|
||||
@if (PageState != null)
|
||||
@if (Type == MessageType.Error && PageState != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
@if (Type == MessageType.Error && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<NavLink class="ms-2" href="@NavigateUrl("admin/log")">View Details</NavLink>
|
||||
}
|
||||
<form method="post" @onsubmit="DismissModal" @formname="@_formname" data-enhance>
|
||||
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||
<button type="submit" class="btn-close" aria-label="Close"></button>
|
||||
</form>
|
||||
<NavLink class="ms-2" href="@NavigateUrl("admin/log")">View Details</NavLink>
|
||||
}
|
||||
@if (ModuleState.RenderMode == RenderModes.Static)
|
||||
{
|
||||
<a href="@NavigationManager.Uri" class="btn-close" data-dismiss="alert" aria-label="close"></a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn-close" data-dismiss="alert" aria-label="close" @onclick="CloseMessage"></button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _message = string.Empty;
|
||||
private string _classname = string.Empty;
|
||||
private string _formname = "ModuleMessageForm";
|
||||
|
||||
[Parameter]
|
||||
public string Message { get; set; }
|
||||
@ -30,32 +31,13 @@
|
||||
[Parameter]
|
||||
public MessageType Type { get; set; }
|
||||
|
||||
public void RefreshMessage(string message, MessageType type)
|
||||
{
|
||||
Message = message;
|
||||
Type = type;
|
||||
|
||||
UpdateClassName();
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
if (ModuleState != null)
|
||||
{
|
||||
_formname += ModuleState.PageModuleId.ToString();
|
||||
}
|
||||
}
|
||||
[Parameter]
|
||||
public RenderModeBoundary Parent { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
UpdateClassName();
|
||||
}
|
||||
|
||||
private void UpdateClassName()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Message))
|
||||
_message = Message;
|
||||
if (!string.IsNullOrEmpty(_message))
|
||||
{
|
||||
_classname = GetMessageType(Type);
|
||||
}
|
||||
@ -82,9 +64,15 @@
|
||||
|
||||
return classname;
|
||||
}
|
||||
|
||||
private void DismissModal()
|
||||
private void CloseMessage(MouseEventArgs e)
|
||||
{
|
||||
Message = "";
|
||||
if(Parent != null)
|
||||
{
|
||||
Parent.DismissMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,16 +23,16 @@
|
||||
{
|
||||
<ul class="pagination justify-content-center my-2">
|
||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
}
|
||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@for (int i = _startPage; i <= _endPage; i++)
|
||||
{
|
||||
@ -40,30 +40,30 @@
|
||||
if (pager == _page)
|
||||
{
|
||||
<li class="page-item app-pager-pointer active">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="page-item app-pager-pointer">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
}
|
||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
@ -73,7 +73,7 @@
|
||||
@if (!string.IsNullOrEmpty(SearchProperties))
|
||||
{
|
||||
<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">
|
||||
<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>
|
||||
@ -86,16 +86,16 @@
|
||||
{
|
||||
<ul class="pagination justify-content-center my-2">
|
||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(_startPage - 1, _search)"><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(_startPage - 1, _search)"><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
}
|
||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(((_page > 1) ? _page - 1 : _page), _search)"><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(((_page > 1) ? _page - 1 : _page), _search)"><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@for (int i = _startPage; i <= _endPage; i++)
|
||||
{
|
||||
@ -103,30 +103,30 @@
|
||||
if (pager == _page)
|
||||
{
|
||||
<li class="page-item app-pager-pointer active">
|
||||
<a class="page-link" href="@PageUrl(pager, _search)">@pager</a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="page-item app-pager-pointer">
|
||||
<a class="page-link" href="@PageUrl(pager, _search)">@pager</a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(((_page < _pages) ? _page + 1 : _page), _search)"><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(((_page < _pages) ? _page + 1 : _page), _search)"><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(_endPage + 1, _search)"><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(_endPage + 1, _search)"><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
}
|
||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(_pages, _search)"><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(_pages, _search)"><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
@ -202,16 +202,16 @@
|
||||
{
|
||||
<ul class="pagination justify-content-center my-2">
|
||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
}
|
||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@for (int i = _startPage; i <= _endPage; i++)
|
||||
{
|
||||
@ -219,30 +219,30 @@
|
||||
if (pager == _page)
|
||||
{
|
||||
<li class="page-item app-pager-pointer active">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="page-item app-pager-pointer">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
}
|
||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
@ -250,16 +250,16 @@
|
||||
{
|
||||
<ul class="pagination justify-content-center my-2">
|
||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(_startPage - 1, _search)"><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(_startPage - 1, _search)"><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
}
|
||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(((_page > 1) ? _page - 1 : _page), _search)"><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(((_page > 1) ? _page - 1 : _page), _search)"><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@for (int i = _startPage; i <= _endPage; i++)
|
||||
{
|
||||
@ -267,30 +267,30 @@
|
||||
if (pager == _page)
|
||||
{
|
||||
<li class="page-item app-pager-pointer active">
|
||||
<a class="page-link" href="@PageUrl(pager, _search)">@pager</a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="page-item app-pager-pointer">
|
||||
<a class="page-link" href="@PageUrl(pager, _search)">@pager</a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(((_page < _pages) ? _page + 1 : _page), _search)"><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(((_page < _pages) ? _page + 1 : _page), _search)"><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(_endPage + 1, _search)"><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(_endPage + 1, _search)"><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
}
|
||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||
<a class="page-link" href="@PageUrl(_pages, _search)"><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||
<a class="page-link shadow-none" href="@PageUrl(_pages, _search)"><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
|
@ -63,8 +63,7 @@
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
<div @ref="@_editorElement">
|
||||
</div>
|
||||
<div @ref="@_editorElement"></div>
|
||||
</div>
|
||||
</div>
|
||||
</TabPanel>
|
||||
@ -91,11 +90,11 @@
|
||||
</div>
|
||||
@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
|
||||
{
|
||||
<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>
|
||||
}
|
||||
@ -104,17 +103,26 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
|
||||
private RichTextEditorInterop interop;
|
||||
private FileManager _fileManager;
|
||||
private string _activetab = "Rich";
|
||||
|
||||
private ElementReference _editorElement;
|
||||
private ElementReference _toolBar;
|
||||
private bool _richfilemanager = false;
|
||||
private FileManager _fileManager;
|
||||
private string _richhtml = string.Empty;
|
||||
private string _originalrichhtml = string.Empty;
|
||||
|
||||
private bool _rawfilemanager = false;
|
||||
private string _rawhtmlid = "RawHtmlEditor_" + Guid.NewGuid().ToString("N");
|
||||
private string _rawhtml = string.Empty;
|
||||
private string _originalrawhtml = string.Empty;
|
||||
|
||||
private string _message = string.Empty;
|
||||
private string _activetab = "Rich";
|
||||
private bool _contentchanged = false;
|
||||
private int _editorIndex;
|
||||
|
||||
[Parameter]
|
||||
public string Content { get; set; }
|
||||
@ -123,7 +131,7 @@
|
||||
public bool ReadOnly { get; set; } = false;
|
||||
|
||||
[Parameter]
|
||||
public string Placeholder { get; set; } = "Enter Your Content...";
|
||||
public string Placeholder { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool AllowFileManagement { get; set; } = true;
|
||||
@ -146,11 +154,20 @@
|
||||
|
||||
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-blot-formatter.min.js" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.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", Location = ResourceLocation.Body },
|
||||
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()
|
||||
{
|
||||
_richhtml = Content;
|
||||
@ -158,8 +175,12 @@
|
||||
_originalrawhtml = _rawhtml; // preserve for comparison later
|
||||
_originalrichhtml = "";
|
||||
|
||||
// Quill wraps content in <p> tags which can be used as a signal to set the active tab
|
||||
if (!string.IsNullOrEmpty(Content) && !Content.StartsWith("<p>") && AllowRawHtml)
|
||||
if (Content != _originalrawhtml)
|
||||
{
|
||||
_contentchanged = true; // identifies when Content parameter has changed
|
||||
}
|
||||
|
||||
if (!AllowRichText)
|
||||
{
|
||||
_activetab = "Raw";
|
||||
}
|
||||
@ -171,8 +192,6 @@
|
||||
|
||||
if (AllowRichText)
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
await interop.CreateEditor(
|
||||
@ -182,15 +201,38 @@
|
||||
Placeholder,
|
||||
Theme,
|
||||
DebugLevel);
|
||||
}
|
||||
|
||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
||||
|
||||
if (string.IsNullOrEmpty(_originalrichhtml))
|
||||
{
|
||||
// preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor)
|
||||
// preserve a copy of the content (Quill sanitizes content so we need to retrieve it from the editor as it may have been modified)
|
||||
_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,35 +260,38 @@
|
||||
else
|
||||
{
|
||||
var richhtml = "";
|
||||
|
||||
if (AllowRichText)
|
||||
{
|
||||
// return rich text content if it has changed
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
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))
|
||||
{
|
||||
return richhtml;
|
||||
}
|
||||
else
|
||||
{
|
||||
// return original raw html content
|
||||
return _originalrawhtml;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InsertRichImage()
|
||||
{
|
||||
_message = string.Empty;
|
||||
if (_richfilemanager)
|
||||
{
|
||||
var file = _fileManager.GetFile();
|
||||
if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml))
|
||||
{
|
||||
// convert Quill's empty content to empty string
|
||||
if (richhtml == "<p><br></p>")
|
||||
{
|
||||
richhtml = string.Empty;
|
||||
}
|
||||
return richhtml;
|
||||
}
|
||||
else
|
||||
{
|
||||
// return original raw html content
|
||||
return _originalrawhtml;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InsertRichImage()
|
||||
{
|
||||
_message = string.Empty;
|
||||
if (_richfilemanager)
|
||||
{
|
||||
var file = _fileManager.GetFile();
|
||||
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), _editorIndex);
|
||||
_richhtml = await interop.GetHtml(_editorElement);
|
||||
_richfilemanager = false;
|
||||
}
|
||||
@ -257,6 +302,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
_editorIndex = await interop.GetCurrentCursor(_editorElement);
|
||||
_richfilemanager = true;
|
||||
}
|
||||
StateHasChanged();
|
||||
@ -271,7 +317,7 @@
|
||||
if (file != null)
|
||||
{
|
||||
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\">";
|
||||
_rawhtml = _rawhtml.Substring(0, pos) + image + _rawhtml.Substring(pos);
|
||||
_rawfilemanager = false;
|
||||
|
@ -105,13 +105,25 @@ namespace Oqtane.Modules.Controls
|
||||
}
|
||||
}
|
||||
|
||||
public Task InsertImage(ElementReference quillElement, string imageUrl, string altText)
|
||||
public ValueTask<int> GetCurrentCursor(ElementReference quillElement)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _jsRuntime.InvokeAsync<int>("Oqtane.RichTextEditor.getCurrentCursor", quillElement);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new ValueTask<int>(Task.FromResult(0));
|
||||
}
|
||||
}
|
||||
|
||||
public Task InsertImage(ElementReference quillElement, string imageUrl, string altText, int editorIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeAsync<object>(
|
||||
"Oqtane.RichTextEditor.insertQuillImage",
|
||||
quillElement, imageUrl, altText);
|
||||
quillElement, imageUrl, altText, editorIndex);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch
|
||||
|
@ -37,6 +37,10 @@
|
||||
content = htmltext.Content;
|
||||
content = Utilities.FormatContent(content, PageState.Alias, "render");
|
||||
}
|
||||
else
|
||||
{
|
||||
content = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -52,6 +52,8 @@ namespace Oqtane.Modules
|
||||
|
||||
public virtual string RenderMode { get { return RenderModes.Interactive; } } // interactive by default
|
||||
|
||||
public virtual bool? Prerender { get { return null; } } // allows the Site Prerender property to be overridden
|
||||
|
||||
// url parameters
|
||||
public virtual string UrlParametersTemplate { get; set; }
|
||||
|
||||
@ -276,7 +278,6 @@ namespace Oqtane.Modules
|
||||
|
||||
public void AddModuleMessage(string message, MessageType type, string position)
|
||||
{
|
||||
ClearModuleMessage();
|
||||
RenderModeBoundary.AddModuleMessage(message, type, position);
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>5.1.0</Version>
|
||||
<Version>5.1.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -12,7 +12,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
@ -22,9 +22,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -153,7 +153,7 @@
|
||||
<data name="Integrated" xml:space="preserve">
|
||||
<value>Integrated</value>
|
||||
</data>
|
||||
<data name="Encryption,Text" xml:space="preserve">
|
||||
<data name="Encryption.Text" xml:space="preserve">
|
||||
<value>Encryption:</value>
|
||||
</data>
|
||||
<data name="Encryption.HelpText" xml:space="preserve">
|
||||
|
@ -195,4 +195,7 @@
|
||||
<data name="Folder Management" xml:space="preserve">
|
||||
<value>Folder Management</value>
|
||||
</data>
|
||||
<data name="Message.Folder.Duplicate" xml:space="preserve">
|
||||
<value>Folder Name Specified Already Exists In Parent</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -210,4 +210,16 @@
|
||||
<data name="Success.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Settings Saved Successfully</value>
|
||||
</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>
|
@ -156,7 +156,7 @@
|
||||
<data name="Module.Text" xml:space="preserve">
|
||||
<value>Module:</value>
|
||||
</data>
|
||||
<data name="Module Settings" xml:space="preserve">
|
||||
<data name="ModuleSettings.Heading" xml:space="preserve">
|
||||
<value>Module Settings</value>
|
||||
</data>
|
||||
<data name="Pane.HelpText" xml:space="preserve">
|
||||
@ -177,4 +177,16 @@
|
||||
<data name="ExpiryDate.Text" xml:space="preserve">
|
||||
<value>Expiry Date: </value>
|
||||
</data>
|
||||
<data name="Permissions.Text" xml:space="preserve">
|
||||
<value>Permissions</value>
|
||||
</data>
|
||||
<data name="Permissions.Heading" xml:space="preserve">
|
||||
<value>Permissions</value>
|
||||
</data>
|
||||
<data name="ContainerSettings.Heading" xml:space="preserve">
|
||||
<value>Container Settings</value>
|
||||
</data>
|
||||
<data name="ModuleSettings.Title" xml:space="preserve">
|
||||
<value>Module Settings</value>
|
||||
</data>
|
||||
</root>
|
@ -147,4 +147,7 @@
|
||||
<data name="Title" xml:space="preserve">
|
||||
<value>Title</value>
|
||||
</data>
|
||||
<data name="Detail.Text" xml:space="preserve">
|
||||
<value>Detail</value>
|
||||
</data>
|
||||
</root>
|
@ -277,10 +277,10 @@
|
||||
<value>UI Component Settings</value>
|
||||
</data>
|
||||
<data name="Prerender.HelpText" xml:space="preserve">
|
||||
<value>Specifies if interactive components should prerender their output</value>
|
||||
<value>Specifies if interactive components should prerender their output on the server</value>
|
||||
</data>
|
||||
<data name="Prerender.Text" xml:space="preserve">
|
||||
<value>Prerender? </value>
|
||||
<value>Prerender: </value>
|
||||
</data>
|
||||
<data name="RenderMode.HelpText" xml:space="preserve">
|
||||
<value>The default render mode for the site</value>
|
||||
|
@ -255,12 +255,6 @@
|
||||
<data name="MachineName.Text" xml:space="preserve">
|
||||
<value>Machine Name:</value>
|
||||
</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">
|
||||
<value>Server Web Root Path</value>
|
||||
</data>
|
||||
@ -294,4 +288,10 @@
|
||||
<data name="Error.ClearLog" xml:space="preserve">
|
||||
<value>Ann Error Occurred Clearing The System Log</value>
|
||||
</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>
|
@ -159,4 +159,7 @@
|
||||
<data name="Url" xml:space="preserve">
|
||||
<value>Url</value>
|
||||
</data>
|
||||
<data name="Edit.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
</root>
|
@ -184,7 +184,7 @@
|
||||
<value>Number of days of visitor activity to retain</value>
|
||||
</data>
|
||||
<data name="Retention.Text" xml:space="preserve">
|
||||
<value>Retention (Days):</value>
|
||||
<value>Retention:</value>
|
||||
</data>
|
||||
<data name="Correlation.HelpText" xml:space="preserve">
|
||||
<value>Indicate if new visitors to this site should be correlated based on their IP Address</value>
|
||||
@ -192,4 +192,10 @@
|
||||
<data name="Correlation.Text" xml:space="preserve">
|
||||
<value>Correlate Visitors?</value>
|
||||
</data>
|
||||
<data name="Duration.HelpText" xml:space="preserve">
|
||||
<value>The duration of a browsing session considered to be a distinct visit (in minutes)</value>
|
||||
</data>
|
||||
<data name="Duration.Text" xml:space="preserve">
|
||||
<value>Session Duration:</value>
|
||||
</data>
|
||||
</root>
|
@ -126,4 +126,7 @@
|
||||
<data name="Message.Require.Image" xml:space="preserve">
|
||||
<value>You Must Select An Image To Insert</value>
|
||||
</data>
|
||||
<data name="Placeholder" xml:space="preserve">
|
||||
<value>Enter Your Content...</value>
|
||||
</data>
|
||||
</root>
|
@ -453,4 +453,10 @@
|
||||
<data name="RenderModeStatic" xml:space="preserve">
|
||||
<value>Static</value>
|
||||
</data>
|
||||
<data name="Disabled" xml:space="preserve">
|
||||
<value>Disabled</value>
|
||||
</data>
|
||||
<data name="Enabled" xml:space="preserve">
|
||||
<value>Enabled</value>
|
||||
</data>
|
||||
</root>
|
@ -198,4 +198,7 @@
|
||||
<data name="LocationTop" xml:space="preserve">
|
||||
<value>Top</value>
|
||||
</data>
|
||||
<data name="Module.CopyExisting" xml:space="preserve">
|
||||
<value>Copy Existing Module</value>
|
||||
</data>
|
||||
</root>
|
150
Oqtane.Client/Resources/Themes/Controls/ModuleActionsBase.resx
Normal file
150
Oqtane.Client/Resources/Themes/Controls/ModuleActionsBase.resx
Normal file
@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="DeleteModule" xml:space="preserve">
|
||||
<value>Delete Module</value>
|
||||
</data>
|
||||
<data name="ExportContent" xml:space="preserve">
|
||||
<value>Export Content</value>
|
||||
</data>
|
||||
<data name="ImportContent" xml:space="preserve">
|
||||
<value>Import Content</value>
|
||||
</data>
|
||||
<data name="ManageSettings" xml:space="preserve">
|
||||
<value>Manage Settings</value>
|
||||
</data>
|
||||
<data name="MoveDown" xml:space="preserve">
|
||||
<value>Move Down</value>
|
||||
</data>
|
||||
<data name="MoveToBottom" xml:space="preserve">
|
||||
<value>Move To Bottom</value>
|
||||
</data>
|
||||
<data name="MoveToTop" xml:space="preserve">
|
||||
<value>Move To Top</value>
|
||||
</data>
|
||||
<data name="MoveUp" xml:space="preserve">
|
||||
<value>MoveUp</value>
|
||||
</data>
|
||||
<data name="PublishModule" xml:space="preserve">
|
||||
<value>Publish Module</value>
|
||||
</data>
|
||||
<data name="UnpublishModule" xml:space="preserve">
|
||||
<value>Unpublish Module</value>
|
||||
</data>
|
||||
</root>
|
@ -29,6 +29,13 @@ namespace Oqtane.Services
|
||||
/// <returns></returns>
|
||||
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>
|
||||
/// Creates a new log entry
|
||||
/// </summary>
|
||||
|
@ -35,6 +35,11 @@ namespace Oqtane.Services
|
||||
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)
|
||||
{
|
||||
await Log(null, pageId, moduleId, userId, category, feature, function, level, exception, message, args);
|
||||
|
@ -33,7 +33,7 @@ namespace Oqtane.Services
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Shared;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
@ -18,7 +19,7 @@ namespace Oqtane.Services
|
||||
|
||||
public async Task<List<Visitor>> GetVisitorsAsync(int siteId, DateTime fromDate)
|
||||
{
|
||||
List<Visitor> visitors = await GetJsonAsync<List<Visitor>>($"{Apiurl}?siteid={siteId}&fromdate={fromDate.ToString("dd-MMM-yyyy")}");
|
||||
List<Visitor> visitors = await GetJsonAsync<List<Visitor>>($"{Apiurl}?siteid={siteId}&fromdate={fromDate.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}");
|
||||
return visitors.OrderByDescending(item => item.VisitedOn).ToList();
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
@namespace Oqtane.Themes
|
||||
@inherits ContainerBase
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<div class="app-admin-modal">
|
||||
<div class="modal" tabindex="-1" role="dialog">
|
||||
@ -8,10 +7,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><ModuleTitle /></h5>
|
||||
<form method="post" class="app-form-inline" @formname="AdminContainerForm" @onsubmit="@CloseModal" data-enhance>
|
||||
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||
<button type="submit" class="btn-close" aria-label="Close"></button>
|
||||
</form>
|
||||
<a href="@_url" class="btn-close" aria-label="Close"></a>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ModuleInstance />
|
||||
@ -22,9 +18,11 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private void CloseModal()
|
||||
{
|
||||
NavigationManager.NavigateTo((!string.IsNullOrEmpty(PageState.ReturnUrl)) ? PageState.ReturnUrl : NavigateUrl());
|
||||
private string _url;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_url = (!string.IsNullOrEmpty(PageState.ReturnUrl)) ? PageState.ReturnUrl : NavigateUrl();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,6 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<ModuleActionsInteractive PageState="@PageState" ModuleState="@ModuleState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, PageState.Site.Prerender)" />
|
||||
<ModuleActionsInteractive PageState="@PageState" ModuleState="@ModuleState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" />
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.UI;
|
||||
using System.Net;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
// ReSharper disable UnassignedGetOnlyAutoProperty
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
@ -20,6 +22,7 @@ namespace Oqtane.Themes.Controls
|
||||
[Inject] public NavigationManager NavigationManager { get; set; }
|
||||
[Inject] public IPageModuleService PageModuleService { get; set; }
|
||||
[Inject] public IModuleService ModuleService { get; set; }
|
||||
[Inject] public IStringLocalizer<ModuleActionsBase> Localizer { get; set; }
|
||||
|
||||
[Parameter] public PageState PageState { get; set; }
|
||||
[Parameter] public Module ModuleState { get; set; }
|
||||
@ -37,30 +40,30 @@ namespace Oqtane.Themes.Controls
|
||||
|
||||
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||
{
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.Cog, Name = "Manage Settings", Action = async (u, m) => await Settings(u, m) });
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.Cog, Name = Localizer["ManageSettings"], Action = async (u, m) => await Settings(u, m) });
|
||||
|
||||
if (UserSecurity.ContainsRole(ModuleState.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||
{
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.CircleX, Name = "Unpublish Module", Action = async (s, m) => await Unpublish(s, m) });
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.CircleX, Name = Localizer["UnpublishModule"], Action = async (s, m) => await Unpublish(s, m) });
|
||||
}
|
||||
else
|
||||
{
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.CircleCheck, Name = "Publish Module", Action = async (s, m) => await Publish(s, m) });
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.CircleCheck, Name = Localizer["PublishModule"], Action = async (s, m) => await Publish(s, m) });
|
||||
}
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.Trash, Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m) });
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.Trash, Name = Localizer["DeleteModule"], Action = async (u, m) => await DeleteModule(u, m) });
|
||||
|
||||
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.IsPortable)
|
||||
{
|
||||
actionList.Add(new ActionViewModel { Name = "" });
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.CloudUpload, Name = "Import Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import") });
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.CloudDownload, Name = "Export Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Export") });
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.CloudUpload, Name = Localizer["ImportContent"], Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import") });
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.CloudDownload, Name = Localizer["ExportContent"], Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Export") });
|
||||
}
|
||||
|
||||
actionList.Add(new ActionViewModel { Name = "" });
|
||||
|
||||
if (ModuleState.PaneModuleIndex > 0)
|
||||
{
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.DataTransferUpload, Name = "Move To Top", Action = async (s, m) => await MoveTop(s, m) });
|
||||
actionList.Add(new ActionViewModel { Icon = Icons.DataTransferUpload, Name = Localizer["MoveToTop"], Action = async (s, m) => await MoveTop(s, m) });
|
||||
}
|
||||
|
||||
if (ModuleState.PaneModuleIndex > 0)
|
||||
|
@ -6,13 +6,13 @@
|
||||
|
||||
@if (ShowLanguageSwitcher)
|
||||
{
|
||||
<LanguageSwitcher DropdownAlignment="@LanguageDropdownAlignment" />
|
||||
<LanguageSwitcher ButtonClass="@ButtonClass" DropdownAlignment="@LanguageDropdownAlignment" />
|
||||
}
|
||||
|
||||
@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>
|
||||
<input type="hidden" name="__RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||
@if (PageState.EditMode)
|
||||
{
|
||||
<button type="submit" class="btn @ButtonClass active" aria-pressed="true" autocomplete="off">
|
||||
@ -36,7 +36,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<ControlPanelInteractive PageState="@PageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, PageState.Site.Prerender)" />
|
||||
<ControlPanelInteractive PageState="@PageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" />
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
@inject ILogService LoggingService
|
||||
@inject IStringLocalizer<ControlPanelInteractive> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
@inject IServiceProvider ServiceProvider
|
||||
|
||||
<button type="button" class="btn @ButtonClass ms-1" data-bs-toggle="offcanvas" data-bs-target="#offcanvasControlPanel" aria-controls="offcanvasControlPanel" @onclick="ClearMessage">
|
||||
<span class="oi oi-cog"></span>
|
||||
@ -93,9 +94,13 @@
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Module" class="control-label">@Localizer["Module.Manage"]</label>
|
||||
<select class="form-select" @bind="@_moduleType">
|
||||
<select class="form-select" @onchange="(e => ModuleTypeChanged(e))">
|
||||
<option value="new">@Localizer["Module.AddNew"]</option>
|
||||
<option value="existing">@Localizer["Module.AddExisting"]</option>
|
||||
@if (PageState.Page.UserId == null)
|
||||
{
|
||||
<option value="add">@Localizer["Module.AddExisting"]</option>
|
||||
<option value="copy">@Localizer["Module.CopyExisting"]</option>
|
||||
}
|
||||
</select>
|
||||
@if (_moduleType == "new")
|
||||
{
|
||||
@ -138,7 +143,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<select class="form-select mt-1" @onchange="(e => PageChanged(e))">
|
||||
<select class="form-select mt-1" value="@_pageId" @onchange="(e => PageChanged(e))">
|
||||
<option value="-"><@Localizer["Page.Select"]></option>
|
||||
@foreach (Page p in _pages)
|
||||
{
|
||||
@ -211,7 +216,7 @@
|
||||
|
||||
<div class="row d-flex">
|
||||
<div class="col">
|
||||
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-secondary col-12" @onclick=@(async () => await LogoutUser())>@Localizer["Logout"]</button>
|
||||
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-secondary col-12 mt-2" @onclick=@(async () => await LogoutUser())>@Localizer["Logout"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -291,7 +296,7 @@
|
||||
_containerType = PageState.Site.DefaultContainerType;
|
||||
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
|
||||
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
||||
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',', StringSplitOptions.RemoveEmptyEntries)).Distinct().Where(item => item != "Headless").ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,6 +339,13 @@
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void ModuleTypeChanged(ChangeEventArgs e)
|
||||
{
|
||||
_moduleType = (string)e.Value;
|
||||
_pageId = "-";
|
||||
_moduleId = "-";
|
||||
}
|
||||
|
||||
private void PageChanged(ChangeEventArgs e)
|
||||
{
|
||||
_pageId = (string)e.Value;
|
||||
@ -341,7 +353,8 @@
|
||||
{
|
||||
_modules = PageState.Modules
|
||||
.Where(module => module.PageId == int.Parse(_pageId) &&
|
||||
UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
||||
UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList) &&
|
||||
(_moduleType == "add" || module.ModuleDefinition.IsPortable))
|
||||
.ToList();
|
||||
}
|
||||
_moduleId = "-";
|
||||
@ -354,6 +367,7 @@
|
||||
{
|
||||
if ((_moduleType == "new" && _moduleDefinitionName != "-") || (_moduleType != "new" && _moduleId != "-"))
|
||||
{
|
||||
var newModuleId = _moduleId != "-" ? int.Parse(_moduleId) : 0;
|
||||
if (_moduleType == "new")
|
||||
{
|
||||
Module module = new Module();
|
||||
@ -361,33 +375,37 @@
|
||||
module.PageId = PageState.Page.PageId;
|
||||
module.ModuleDefinitionName = _moduleDefinitionName;
|
||||
module.AllPages = false;
|
||||
|
||||
var permissions = new List<Permission>();
|
||||
if (_visibility == "view")
|
||||
{
|
||||
// set module view permissions to page view permissions
|
||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.View);
|
||||
}
|
||||
else
|
||||
{
|
||||
// set module view permissions to page edit permissions
|
||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.Edit);
|
||||
}
|
||||
// set module edit permissions to page edit permissions
|
||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.Edit, PermissionNames.Edit);
|
||||
module.PermissionList = permissions;
|
||||
module.PermissionList = GenerateDefaultPermissions(module.SiteId);
|
||||
|
||||
module = await ModuleService.AddModuleAsync(module);
|
||||
_moduleId = module.ModuleId.ToString();
|
||||
newModuleId = module.ModuleId;
|
||||
}
|
||||
else if (_moduleType == "copy")
|
||||
{
|
||||
var module = await ModuleService.GetModuleAsync(int.Parse(_moduleId));
|
||||
module.ModuleId = 0;
|
||||
module.SiteId = PageState.Site.SiteId;
|
||||
module.PageId = PageState.Page.PageId;
|
||||
module.AllPages = false;
|
||||
module.PermissionList = GenerateDefaultPermissions(module.SiteId);
|
||||
|
||||
module = await ModuleService.AddModuleAsync(module);
|
||||
var moduleContent = await ModuleService.ExportModuleAsync(int.Parse(_moduleId), PageState.Page.PageId);
|
||||
if (!string.IsNullOrEmpty(moduleContent))
|
||||
{
|
||||
await ModuleService.ImportModuleAsync(module.ModuleId, PageState.Page.PageId, moduleContent);
|
||||
}
|
||||
|
||||
newModuleId = module.ModuleId;
|
||||
}
|
||||
|
||||
var pageModule = new PageModule
|
||||
{
|
||||
PageId = PageState.Page.PageId,
|
||||
ModuleId = int.Parse(_moduleId),
|
||||
ModuleId = newModuleId,
|
||||
Title = _title
|
||||
};
|
||||
if (pageModule.Title == "")
|
||||
if (string.IsNullOrEmpty(pageModule.Title))
|
||||
{
|
||||
if (_moduleType == "new")
|
||||
{
|
||||
@ -412,9 +430,16 @@
|
||||
await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane);
|
||||
await UpdateSettingsAsync();
|
||||
|
||||
_message = $"<div class=\"alert alert-success mt-2 text-center\" role=\"alert\">{Localizer["Success.Page.ModuleAdd"]}</div>";
|
||||
_title = "";
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, ""));
|
||||
if (PageState.RenderMode == RenderModes.Interactive)
|
||||
{
|
||||
_message = $"<div class=\"alert alert-success mt-2 text-center\" role=\"alert\">{Localizer["Success.Page.ModuleAdd"]}</div>";
|
||||
_title = "";
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, ""));
|
||||
}
|
||||
else // reload page in static rendering
|
||||
{
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, ""), true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -427,6 +452,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
private List<Permission> GenerateDefaultPermissions(int siteId)
|
||||
{
|
||||
var permissions = new List<Permission>();
|
||||
if (_visibility == "view")
|
||||
{
|
||||
// set module view permissions to page view permissions
|
||||
permissions = SetPermissions(permissions, siteId, PermissionNames.View, PermissionNames.View);
|
||||
}
|
||||
else
|
||||
{
|
||||
// set module view permissions to page edit permissions
|
||||
permissions = SetPermissions(permissions, siteId, PermissionNames.View, PermissionNames.Edit);
|
||||
}
|
||||
// set module edit permissions to page edit permissions
|
||||
permissions = SetPermissions(permissions, siteId, PermissionNames.Edit, PermissionNames.Edit);
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
private List<Permission> SetPermissions(List<Permission> permissions, int siteId, string modulePermission, string pagePermission)
|
||||
{
|
||||
foreach (var permission in PageState.Page.PermissionList.Where(item => item.PermissionName == pagePermission))
|
||||
|
@ -1,21 +1,29 @@
|
||||
@namespace Oqtane.Themes.Controls
|
||||
@inherits ThemeControlBase
|
||||
@using System.Globalization
|
||||
@using Microsoft.AspNetCore.Localization
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@using Oqtane.Models
|
||||
@namespace Oqtane.Themes.Controls
|
||||
@inherits ThemeControlBase
|
||||
@inject ILanguageService LanguageService
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
@if (_supportedCultures?.Count() > 1)
|
||||
{
|
||||
<div class="btn-group pe-1" role="group">
|
||||
<button id="btnCultures" type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<button id="btnCultures" type="button" class="btn @ButtonClass dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="oi oi-globe"></span>
|
||||
</button>
|
||||
<div class="dropdown-menu @MenuAlignment" aria-labelledby="btnCultures">
|
||||
@foreach (var culture in _supportedCultures)
|
||||
{
|
||||
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="#" @onclick="@(async e => await SetCultureAsync(culture.Name))">@culture.DisplayName</a>
|
||||
@if (PageState.RenderMode == RenderModes.Interactive)
|
||||
{
|
||||
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="#" @onclick="@(async e => await SetCultureAsync(culture.Name))" @onclick:preventDefault="true">@culture.DisplayName</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="@NavigateUrl(PageState.Page.Path, "culture=" + culture.Name)">@culture.DisplayName</a>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@ -23,9 +31,15 @@
|
||||
|
||||
@code{
|
||||
private IEnumerable<Culture> _supportedCultures;
|
||||
private string MenuAlignment = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string DropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right
|
||||
private string MenuAlignment = string.Empty;
|
||||
[Parameter]
|
||||
public string ButtonClass { get; set; } = "btn-outline-secondary";
|
||||
|
||||
[CascadingParameter]
|
||||
HttpContext HttpContext { get; set; }
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
@ -33,16 +47,26 @@
|
||||
|
||||
var languages = PageState.Languages;
|
||||
_supportedCultures = languages.Select(l => new Culture { Name = l.Code, DisplayName = l.Name });
|
||||
|
||||
if (PageState.QueryString.ContainsKey("culture"))
|
||||
{
|
||||
var culture = PageState.QueryString["culture"];
|
||||
if (_supportedCultures.Any(item => item.Name == culture))
|
||||
{
|
||||
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
|
||||
HttpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, new CookieOptions { Path = "/", Expires = DateTimeOffset.UtcNow.AddYears(365) });
|
||||
}
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri.Replace($"?culture={culture}", ""), forceLoad: true);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetCultureAsync(string culture)
|
||||
{
|
||||
if (culture != CultureInfo.CurrentUICulture.Name)
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360);
|
||||
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
else
|
||||
{
|
||||
<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" />
|
||||
<button type="submit" class="btn btn-primary">@Localizer["Logout"]</button>
|
||||
</form>
|
||||
|
@ -121,15 +121,15 @@
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
if (_login != "-")
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login, true);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login);
|
||||
}
|
||||
if (_register != "-")
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register, true);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -3,8 +3,6 @@
|
||||
@using Oqtane.Shared
|
||||
@inject SiteState SiteState
|
||||
@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))
|
||||
{
|
||||
|
@ -1,13 +1,17 @@
|
||||
@namespace Oqtane.UI
|
||||
@inject SiteState SiteState
|
||||
|
||||
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Interactive)
|
||||
@if (_comment != null)
|
||||
{
|
||||
<StreamRenderingDisabled ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<StreamRenderingEnabled ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" />
|
||||
@((MarkupString)_comment)
|
||||
@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, _prerender)" />
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
@ -20,6 +24,24 @@ else
|
||||
[CascadingParameter]
|
||||
private Module ModuleState { get; set; }
|
||||
|
||||
private bool _prerender;
|
||||
private string _comment;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_prerender = ModuleState.Prerender ?? PageState.Site.Prerender;
|
||||
_comment = "<!-- rendermode: ";
|
||||
if (PageState.RenderMode == RenderModes.Static && ModuleState.RenderMode == RenderModes.Static)
|
||||
{
|
||||
_comment += RenderModes.Static;
|
||||
}
|
||||
else
|
||||
{
|
||||
_comment += $"{RenderModes.Interactive}:{PageState.Runtime} - prerender: {_prerender}";
|
||||
}
|
||||
_comment += " -->";
|
||||
}
|
||||
|
||||
|
||||
[Obsolete("AddModuleMessage is deprecated. Use AddModuleMessage in ModuleBase instead.", false)]
|
||||
public void AddModuleMessage(string message, MessageType type)
|
||||
|
@ -10,14 +10,19 @@
|
||||
{
|
||||
@if (ModuleType != null)
|
||||
{
|
||||
@((MarkupString)$"<!-- rendermode: {ModuleState.RenderMode} -->")
|
||||
<ModuleMessage @ref="moduleMessageTop" Message="@_messageContent" Type="@_messageType" />
|
||||
@if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "top")
|
||||
{
|
||||
<ModuleMessage Message="@_messageContent" Type="@_messageType" Parent="@this" />
|
||||
}
|
||||
@DynamicComponent
|
||||
@if (_progressIndicator)
|
||||
{
|
||||
<div class="app-progress-indicator"></div>
|
||||
}
|
||||
<ModuleMessage @ref="moduleMessageBottom" Message="@_messageContent" Type="@_messageType" />
|
||||
@if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "bottom")
|
||||
{
|
||||
<ModuleMessage Message="@_messageContent" Type="@_messageType" Parent="@this" />
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -42,8 +47,6 @@
|
||||
private string _messagePosition;
|
||||
private bool _progressIndicator = false;
|
||||
private string _error;
|
||||
private ModuleMessage moduleMessageTop;
|
||||
private ModuleMessage moduleMessageBottom;
|
||||
|
||||
[Parameter]
|
||||
public SiteState SiteState { get; set; }
|
||||
@ -104,12 +107,17 @@
|
||||
|
||||
public void AddModuleMessage(string message, MessageType type, string position)
|
||||
{
|
||||
_messageContent = message;
|
||||
_messageType = type;
|
||||
_messagePosition = position;
|
||||
_progressIndicator = false;
|
||||
if(message != _messageContent
|
||||
|| type != _messageType
|
||||
|| position != _messagePosition)
|
||||
{
|
||||
_messageContent = message;
|
||||
_messageType = type;
|
||||
_messagePosition = position;
|
||||
_progressIndicator = false;
|
||||
|
||||
Refresh();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowProgressIndicator()
|
||||
@ -124,25 +132,10 @@
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void DismissMessage()
|
||||
public void DismissMessage()
|
||||
{
|
||||
_messageContent = "";
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
var updateTop = string.IsNullOrEmpty(_messageContent) || _messagePosition == "top";
|
||||
var updateBottom = string.IsNullOrEmpty(_messageContent) || _messagePosition == "bottom";
|
||||
|
||||
if (updateTop && moduleMessageTop != null)
|
||||
{
|
||||
moduleMessageTop.RefreshMessage(_messageContent, _messageType);
|
||||
}
|
||||
|
||||
if (updateBottom && moduleMessageBottom != null)
|
||||
{
|
||||
moduleMessageBottom.RefreshMessage(_messageContent, _messageType);
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
protected override async Task OnErrorAsync(Exception exception)
|
||||
|
@ -3,8 +3,6 @@
|
||||
@inject IInstallationService InstallationService
|
||||
@inject IJSRuntime JSRuntime
|
||||
@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)
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
@using System.Diagnostics.CodeAnalysis
|
||||
@using System.Net
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@using System.Globalization
|
||||
@namespace Oqtane.UI
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject SiteState SiteState
|
||||
@ -103,7 +104,7 @@
|
||||
_error = "";
|
||||
|
||||
Route route = new Route(_absoluteUri, SiteState.Alias.Path);
|
||||
int moduleid = int.Parse(route.ModuleId);
|
||||
int moduleid = int.Parse(route.ModuleId, CultureInfo.InvariantCulture);
|
||||
var action = route.Action;
|
||||
|
||||
var querystring = Utilities.ParseQueryString(route.Query);
|
||||
@ -124,12 +125,20 @@
|
||||
{
|
||||
if (querystring.ContainsKey("reload") && querystring["reload"] == "post")
|
||||
{
|
||||
// post back so that the cookies are set correctly - required on any change to the principal
|
||||
var interop = new Interop(JSRuntime);
|
||||
var fields = new { returnurl = "/" + NavigationManager.ToBaseRelativePath(_absoluteUri) };
|
||||
string url = Utilities.TenantUrl(SiteState.Alias, "/pages/external/");
|
||||
await interop.SubmitForm(url, fields);
|
||||
return;
|
||||
if (PageState.RenderMode == RenderModes.Interactive)
|
||||
{
|
||||
// post back so that the cookies are set correctly - required on any change to the principal
|
||||
var interop = new Interop(JSRuntime);
|
||||
var fields = new { returnurl = "/" + NavigationManager.ToBaseRelativePath(_absoluteUri) };
|
||||
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
|
||||
{
|
||||
@ -163,9 +172,9 @@
|
||||
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);
|
||||
lastsyncdate = sync.SyncDate;
|
||||
if (sync.SyncEvents.Any())
|
||||
@ -243,105 +252,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
|
||||
if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList)))
|
||||
// edit mode
|
||||
if (user != null)
|
||||
{
|
||||
// edit mode
|
||||
if (user != null)
|
||||
if (querystring.ContainsKey("editmode") && querystring["edit"] == "true")
|
||||
{
|
||||
if (querystring.ContainsKey("editmode") && querystring["edit"] == "true")
|
||||
editmode = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
editmode = (page.PageId == ((user.Settings.ContainsKey("CP-editmode")) ? int.Parse(user.Settings["CP-editmode"], CultureInfo.InvariantCulture) : -1));
|
||||
if (!editmode)
|
||||
{
|
||||
editmode = true;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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
|
||||
(page, site.Modules) = ProcessModules(page, site.Modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias);
|
||||
// load additional metadata for current page
|
||||
page = ProcessPage(page, site, user, SiteState.Alias);
|
||||
|
||||
// populate page state (which acts as a client-side cache for subsequent requests)
|
||||
_pagestate = new PageState
|
||||
// load additional metadata for modules
|
||||
(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,
|
||||
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);
|
||||
var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl + route.Query;
|
||||
NavigationManager.NavigateTo(url, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
// 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)));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (route.PagePath != "404")
|
||||
{
|
||||
// redirect to 404 page
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "404", ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
// redirect to home page as a fallback
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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", ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
// redirect to home page as a fallback
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -476,6 +477,7 @@
|
||||
// retrieve module component resources
|
||||
var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
module.RenderMode = moduleobject.RenderMode;
|
||||
module.Prerender = moduleobject.Prerender;
|
||||
|
||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
||||
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
||||
@ -549,7 +551,7 @@
|
||||
{
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
if (resource.Level != ResourceLevel.Site)
|
||||
if (resource.ResourceType == ResourceType.Stylesheet || resource.Level != ResourceLevel.Site)
|
||||
{
|
||||
if (resource.Url.StartsWith("~"))
|
||||
{
|
||||
|
@ -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; }
|
||||
}
|
@ -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; }
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Version>5.1.0</Version>
|
||||
<Version>5.1.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Version>5.1.0</Version>
|
||||
<Version>5.1.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
@ -34,8 +34,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="EFCore.NamingConventions" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.3" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.5" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Version>5.1.0</Version>
|
||||
<Version>5.1.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
@ -33,7 +33,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Version>5.1.0</Version>
|
||||
<Version>5.1.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
@ -33,7 +33,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<!-- <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks> -->
|
||||
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
|
||||
<OutputType>Exe</OutputType>
|
||||
<Version>5.1.0</Version>
|
||||
<Version>5.1.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -14,7 +14,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane.Maui</RootNamespace>
|
||||
@ -31,7 +31,7 @@
|
||||
<ApplicationIdGuid>0E29FC31-1B83-48ED-B6E0-9F3C67B775D4</ApplicationIdGuid>
|
||||
|
||||
<!-- Versions -->
|
||||
<ApplicationDisplayVersion>5.1.0</ApplicationDisplayVersion>
|
||||
<ApplicationDisplayVersion>5.1.2</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>1</ApplicationVersion>
|
||||
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
|
||||
@ -65,15 +65,15 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.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.5" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.10" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="8.0.10" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.40" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.40" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="8.0.40" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Client</id>
|
||||
<version>5.1.0</version>
|
||||
<version>5.1.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Framework</id>
|
||||
<version>5.1.0</version>
|
||||
<version>5.1.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -11,8 +11,8 @@
|
||||
<copyright>.NET Foundation</copyright>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v5.1.0/Oqtane.Framework.5.1.0.Upgrade.zip</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</releaseNotes>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v5.1.2/Oqtane.Framework.5.1.2.Upgrade.zip</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane framework</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Server</id>
|
||||
<version>5.1.0</version>
|
||||
<version>5.1.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Shared</id>
|
||||
<version>5.1.0</version>
|
||||
<version>5.1.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Updater</id>
|
||||
<version>5.1.0</version>
|
||||
<version>5.1.2</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -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.2.Install.zip" -Force
|
@ -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.2.Upgrade.zip" -Force
|
@ -16,6 +16,7 @@
|
||||
@using Oqtane.Shared
|
||||
@using Oqtane.Themes
|
||||
@using Oqtane.Extensions
|
||||
@using System.Globalization
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IAntiforgery Antiforgery
|
||||
@inject IConfigManager ConfigManager
|
||||
@ -39,7 +40,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<base href="/" />
|
||||
<link rel="stylesheet" href="css/app.css" />
|
||||
@if (!string.IsNullOrEmpty(_PWAScript))
|
||||
@if (_scripts.Contains("PWA Manifest"))
|
||||
{
|
||||
<link id="app-manifest" rel="manifest" />
|
||||
}
|
||||
@ -68,20 +69,13 @@
|
||||
<Routes PageState="@_pageState" RenderMode="@_renderMode" Runtime="@_runtime" AntiForgeryToken="@_antiForgeryToken" AuthorizationToken="@_authorizationToken" Platform="@_platform" @rendermode="InteractiveRenderMode.GetInteractiveRenderMode(_runtime, _prerender)" />
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(_reconnectScript))
|
||||
{
|
||||
@((MarkupString)_reconnectScript)
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(_PWAScript))
|
||||
{
|
||||
@((MarkupString)_PWAScript)
|
||||
}
|
||||
@((MarkupString)_bodyResources)
|
||||
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
<script src="js/app.js"></script>
|
||||
<script src="js/loadjs.min.js"></script>
|
||||
<script src="js/interop.js"></script>
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
|
||||
@((MarkupString)_scripts)
|
||||
@((MarkupString)_bodyResources)
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -105,8 +99,7 @@
|
||||
private string _headResources = "";
|
||||
private string _bodyResources = "";
|
||||
private string _styleSheets = "";
|
||||
private string _PWAScript = "";
|
||||
private string _reconnectScript = "";
|
||||
private string _scripts = "";
|
||||
private string _message = "";
|
||||
private PageState _pageState;
|
||||
|
||||
@ -175,23 +168,25 @@
|
||||
CreateJwtToken(alias);
|
||||
}
|
||||
|
||||
// include stylesheets to prevent FOUC
|
||||
var resources = GetPageResources(alias, site, page, int.Parse(route.ModuleId), route.Action);
|
||||
// includes resources
|
||||
var resources = GetPageResources(alias, site, page, int.Parse(route.ModuleId, CultureInfo.InvariantCulture), route.Action);
|
||||
ManageStyleSheets(resources);
|
||||
ManageScripts(resources, alias);
|
||||
|
||||
// scripts
|
||||
if (_renderMode == RenderModes.Static)
|
||||
{
|
||||
ManageScripts(resources, alias);
|
||||
}
|
||||
// generate scripts
|
||||
if (_renderMode == RenderModes.Interactive && _runtime == Runtimes.Server)
|
||||
{
|
||||
_reconnectScript = CreateReconnectScript();
|
||||
_scripts += CreateReconnectScript();
|
||||
}
|
||||
if (site.PwaIsEnabled && site.PwaAppIconFileId != null && site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_PWAScript = CreatePWAScript(alias, site, route);
|
||||
_scripts += CreatePWAScript(alias, site, route);
|
||||
}
|
||||
@if (_renderMode == RenderModes.Static)
|
||||
{
|
||||
_scripts += CreateScrollPositionScript();
|
||||
}
|
||||
|
||||
_headResources += ParseScripts(site.HeadContent);
|
||||
_bodyResources += ParseScripts(site.BodyContent);
|
||||
|
||||
@ -329,14 +324,26 @@
|
||||
int? userid = Context.User.UserId();
|
||||
userid = (userid == -1) ? null : userid;
|
||||
|
||||
// check if cookie already exists
|
||||
// get cookie value
|
||||
var visitorCookieName = Constants.VisitorCookiePrefix + SiteId.ToString();
|
||||
var visitorCookieValue = Context.Request.Cookies[visitorCookieName];
|
||||
DateTime expiry = DateTime.MinValue;
|
||||
if (visitorCookieValue != null && visitorCookieValue.Contains("|"))
|
||||
{
|
||||
var values = visitorCookieValue.Split('|');
|
||||
int.TryParse(values[0], out _visitorId);
|
||||
DateTime.TryParse(values[1], out expiry);
|
||||
}
|
||||
else // legacy cookie format
|
||||
{
|
||||
int.TryParse(visitorCookieValue, out _visitorId);
|
||||
}
|
||||
bool setcookie = false;
|
||||
Visitor visitor = null;
|
||||
bool addcookie = false;
|
||||
var VisitorCookie = Constants.VisitorCookiePrefix + SiteId.ToString();
|
||||
if (!int.TryParse(Context.Request.Cookies[VisitorCookie], out _visitorId))
|
||||
|
||||
if (_visitorId <= 0)
|
||||
{
|
||||
// if enabled use IP Address correlation
|
||||
_visitorId = -1;
|
||||
var correlate = bool.Parse(settings.GetValue("VisitorCorrelation", "true"));
|
||||
if (correlate)
|
||||
{
|
||||
@ -344,12 +351,12 @@
|
||||
if (visitor != null)
|
||||
{
|
||||
_visitorId = visitor.VisitorId;
|
||||
addcookie = true;
|
||||
setcookie = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_visitorId == -1)
|
||||
if (_visitorId <= 0)
|
||||
{
|
||||
// create new visitor
|
||||
visitor = new Visitor();
|
||||
@ -365,52 +372,59 @@
|
||||
visitor.VisitedOn = DateTime.UtcNow;
|
||||
visitor = VisitorRepository.AddVisitor(visitor);
|
||||
_visitorId = visitor.VisitorId;
|
||||
addcookie = true;
|
||||
setcookie = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (visitor == null)
|
||||
// check expiry
|
||||
if (DateTime.UtcNow > expiry)
|
||||
{
|
||||
// get visitor if it was not previously loaded
|
||||
visitor = VisitorRepository.GetVisitor(_visitorId);
|
||||
}
|
||||
if (visitor != null)
|
||||
{
|
||||
// update visitor
|
||||
visitor.IPAddress = _remoteIPAddress;
|
||||
visitor.UserAgent = useragent;
|
||||
visitor.Language = language;
|
||||
visitor.Url = url;
|
||||
if (!string.IsNullOrEmpty(referrer))
|
||||
if (visitor == null)
|
||||
{
|
||||
visitor.Referrer = referrer;
|
||||
// get visitor if not previously loaded
|
||||
visitor = VisitorRepository.GetVisitor(_visitorId);
|
||||
}
|
||||
if (userid != null)
|
||||
if (visitor != null)
|
||||
{
|
||||
visitor.UserId = userid;
|
||||
// update visitor
|
||||
visitor.IPAddress = _remoteIPAddress;
|
||||
visitor.UserAgent = useragent;
|
||||
visitor.Language = language;
|
||||
visitor.Url = url;
|
||||
if (!string.IsNullOrEmpty(referrer))
|
||||
{
|
||||
visitor.Referrer = referrer;
|
||||
}
|
||||
if (userid != null)
|
||||
{
|
||||
visitor.UserId = userid;
|
||||
}
|
||||
visitor.Visits += 1;
|
||||
visitor.VisitedOn = DateTime.UtcNow;
|
||||
VisitorRepository.UpdateVisitor(visitor);
|
||||
setcookie = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove cookie if visitor does not exist
|
||||
Context.Response.Cookies.Delete(visitorCookieName);
|
||||
}
|
||||
visitor.Visits += 1;
|
||||
visitor.VisitedOn = DateTime.UtcNow;
|
||||
VisitorRepository.UpdateVisitor(visitor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove cookie if VisitorId does not exist
|
||||
Context.Response.Cookies.Delete(VisitorCookie);
|
||||
}
|
||||
}
|
||||
|
||||
// append cookie
|
||||
if (addcookie)
|
||||
// set cookie
|
||||
if (setcookie)
|
||||
{
|
||||
expiry = DateTime.UtcNow.AddMinutes(int.Parse(settings.GetValue("VisitorDuration", "5")));
|
||||
|
||||
Context.Response.Cookies.Append(
|
||||
VisitorCookie,
|
||||
_visitorId.ToString(),
|
||||
visitorCookieName,
|
||||
$"{_visitorId}|{expiry}",
|
||||
new CookieOptions()
|
||||
{
|
||||
Expires = DateTimeOffset.UtcNow.AddYears(1),
|
||||
IsEssential = true
|
||||
}
|
||||
{
|
||||
Expires = DateTimeOffset.UtcNow.AddYears(10),
|
||||
IsEssential = true
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -432,7 +446,7 @@
|
||||
|
||||
private string CreatePWAScript(Alias alias, Site site, Route route)
|
||||
{
|
||||
return
|
||||
return Environment.NewLine +
|
||||
"<script>" + Environment.NewLine +
|
||||
" // PWA Manifest" + Environment.NewLine +
|
||||
" setTimeout(() => {" + Environment.NewLine +
|
||||
@ -468,14 +482,14 @@
|
||||
" console.log('ServiceWorker Registration Failed ', err);" + Environment.NewLine +
|
||||
" });" + Environment.NewLine +
|
||||
" };" + Environment.NewLine +
|
||||
"</script>";
|
||||
"</script>" + Environment.NewLine;
|
||||
}
|
||||
|
||||
private string CreateReconnectScript()
|
||||
{
|
||||
return
|
||||
return Environment.NewLine +
|
||||
"<script>" + Environment.NewLine +
|
||||
" // Blazor Server Reconnect" + Environment.NewLine +
|
||||
" // Interactive Blazor Server Reconnect" + Environment.NewLine +
|
||||
" new MutationObserver((mutations, observer) => {" + Environment.NewLine +
|
||||
" if (document.querySelector('#components-reconnect-modal h5 a')) {" + Environment.NewLine +
|
||||
" async function attemptReload() {" + Environment.NewLine +
|
||||
@ -487,7 +501,26 @@
|
||||
" setInterval(attemptReload, 5000);" + Environment.NewLine +
|
||||
" }" + Environment.NewLine +
|
||||
" }).observe(document.body, { childList: true, subtree: true });" + Environment.NewLine +
|
||||
"</script>";
|
||||
"</script>" + Environment.NewLine;
|
||||
}
|
||||
|
||||
private string CreateScrollPositionScript()
|
||||
{
|
||||
return Environment.NewLine +
|
||||
"<script>" + Environment.NewLine +
|
||||
" // Blazor Static Rendering Scroll Position" + Environment.NewLine +
|
||||
" window.interceptNavigation = () => {" + Environment.NewLine +
|
||||
" let currentUrl = window.location.href;" + Environment.NewLine +
|
||||
" Blazor.addEventListener('enhancedload', () => {" + Environment.NewLine +
|
||||
" let newUrl = window.location.href;" + Environment.NewLine +
|
||||
" if (currentUrl != newUrl) {" + Environment.NewLine +
|
||||
" window.scrollTo({ top: 0, left: 0, behavior: 'instant' });" + Environment.NewLine +
|
||||
" }" + Environment.NewLine +
|
||||
" currentUrl = newUrl;" + Environment.NewLine +
|
||||
" });" + Environment.NewLine +
|
||||
" };" + Environment.NewLine +
|
||||
" document.onload += window.interceptNavigation();" + Environment.NewLine +
|
||||
"</script>" + Environment.NewLine;
|
||||
}
|
||||
|
||||
private string ParseScripts(string content)
|
||||
@ -536,7 +569,7 @@
|
||||
((!string.IsNullOrEmpty(resource.Integrity)) ? " integrity=\"" + resource.Integrity + "\"" : "") +
|
||||
((!string.IsNullOrEmpty(resource.CrossOrigin)) ? " crossorigin=\"" + resource.CrossOrigin + "\"" : "") +
|
||||
((resource.ES6Module) ? " type=\"module\"" : "") +
|
||||
" src =\"" + url + "\"></script>"; // src at end of element due to enhanced navigation patch algorithm
|
||||
" src=\"" + url + "\"></script>"; // src at end of element due to enhanced navigation patch algorithm
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -566,13 +599,13 @@
|
||||
var theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == themeType));
|
||||
if (theme != null)
|
||||
{
|
||||
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName));
|
||||
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName), site.RenderMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// fallback to default Oqtane theme
|
||||
theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == Constants.DefaultTheme));
|
||||
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName));
|
||||
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName), site.RenderMode);
|
||||
}
|
||||
var type = Type.GetType(themeType);
|
||||
if (type != null)
|
||||
@ -580,7 +613,7 @@
|
||||
var obj = Activator.CreateInstance(type) as IThemeControl;
|
||||
if (obj != null)
|
||||
{
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Page, alias, "Themes", type.Namespace);
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Page, alias, "Themes", type.Namespace, site.RenderMode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -589,7 +622,7 @@
|
||||
var typename = "";
|
||||
if (module.ModuleDefinition != null)
|
||||
{
|
||||
resources = AddResources(resources, module.ModuleDefinition.Resources, ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName));
|
||||
resources = AddResources(resources, module.ModuleDefinition.Resources, ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName), site.RenderMode);
|
||||
|
||||
// handle default action
|
||||
if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
|
||||
@ -635,7 +668,7 @@
|
||||
var obj = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
if (obj != null)
|
||||
{
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, site.RenderMode);
|
||||
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
||||
{
|
||||
// settings components are embedded within a framework settings module
|
||||
@ -643,7 +676,7 @@
|
||||
if (moduletype != null)
|
||||
{
|
||||
obj = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, site.RenderMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -656,32 +689,35 @@
|
||||
{
|
||||
if (module.ModuleDefinition?.Resources != null)
|
||||
{
|
||||
resources = AddResources(resources, module.ModuleDefinition.Resources.Where(item => item.Level == ResourceLevel.Site).ToList(), ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName));
|
||||
resources = AddResources(resources, module.ModuleDefinition.Resources.Where(item => item.ResourceType == ResourceType.Script && item.Level == ResourceLevel.Site).ToList(), ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName), site.RenderMode);
|
||||
}
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
private List<Resource> AddResources(List<Resource> pageresources, List<Resource> resources, ResourceLevel level, Alias alias, string type, string name)
|
||||
private List<Resource> AddResources(List<Resource> pageresources, List<Resource> resources, ResourceLevel level, Alias alias, string type, string name, string rendermode)
|
||||
{
|
||||
if (resources != null)
|
||||
{
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
if (resource.Url.StartsWith("~"))
|
||||
if (rendermode == RenderModes.Static || resource.ResourceType == ResourceType.Stylesheet || resource.Level == ResourceLevel.Site)
|
||||
{
|
||||
resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/");
|
||||
}
|
||||
if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
||||
{
|
||||
resource.Url = alias.BaseUrl + resource.Url;
|
||||
}
|
||||
if (resource.Url.StartsWith("~"))
|
||||
{
|
||||
resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/");
|
||||
}
|
||||
if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
||||
{
|
||||
resource.Url = alias.BaseUrl + resource.Url;
|
||||
}
|
||||
|
||||
// ensure resource does not exist already
|
||||
if (!pageresources.Exists(item => item.Url.ToLower() == resource.Url.ToLower()))
|
||||
{
|
||||
pageresources.Add(resource.Clone(level, name));
|
||||
// ensure resource does not exist already
|
||||
if (!pageresources.Exists(item => item.Url.ToLower() == resource.Url.ToLower()))
|
||||
{
|
||||
pageresources.Add(resource.Clone(level, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -692,6 +728,7 @@
|
||||
{
|
||||
if (resources != null)
|
||||
{
|
||||
// include stylesheets to prevent FOUC
|
||||
string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
|
||||
int count = 0;
|
||||
foreach (var resource in resources.Where(item => item.ResourceType == ResourceType.Stylesheet))
|
||||
|
@ -760,7 +760,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
if (!Directory.Exists(folderpath))
|
||||
{
|
||||
string path = "";
|
||||
string path = folderpath.StartsWith(Path.DirectorySeparatorChar) ? Path.DirectorySeparatorChar.ToString() : string.Empty;
|
||||
var separators = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
|
||||
string[] folders = folderpath.Split(separators, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string folder in folders)
|
||||
|
@ -76,5 +76,20 @@ namespace Oqtane.Controllers
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -365,8 +365,8 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
{ "FrameworkVersion", moduleDefinition.Version },
|
||||
{ "ClientReference", $"<PackageReference Include=\"Oqtane.Client\" Version=\"{moduleDefinition.Version}\" />" },
|
||||
{ "ServerReference", $"<PackageReference Include=\"Oqtane.Client\" Version=\"{moduleDefinition.Version}\" />" },
|
||||
{ "SharedReference", $"<PackageReference Include=\"Oqtane.Client\" Version=\"{moduleDefinition.Version}\" />" },
|
||||
{ "ServerReference", $"<PackageReference Include=\"Oqtane.Server\" Version=\"{moduleDefinition.Version}\" />" },
|
||||
{ "SharedReference", $"<PackageReference Include=\"Oqtane.Shared\" Version=\"{moduleDefinition.Version}\" />" },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ namespace Oqtane.Controllers
|
||||
case "environment":
|
||||
systeminfo.Add("CLRVersion", Environment.Version.ToString());
|
||||
systeminfo.Add("OSVersion", Environment.OSVersion.ToString());
|
||||
systeminfo.Add("Process", (Environment.Is64BitProcess) ? "64 Bit" : "32 Bit");
|
||||
systeminfo.Add("MachineName", Environment.MachineName);
|
||||
systeminfo.Add("WorkingSet", Environment.WorkingSet.ToString());
|
||||
systeminfo.Add("TickCount", Environment.TickCount64.ToString());
|
||||
|
@ -8,6 +8,7 @@ using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using System.Net;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
@ -33,7 +34,7 @@ namespace Oqtane.Controllers
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
return _visitors.GetVisitors(SiteId, DateTime.Parse(fromdate));
|
||||
return _visitors.GetVisitors(SiteId, DateTime.ParseExact(fromdate, "yyyy-MM-dd", CultureInfo.InvariantCulture));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Routing;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Antiforgery;
|
||||
|
||||
namespace OqtaneSSR.Extensions
|
||||
{
|
||||
@ -23,6 +24,7 @@ namespace OqtaneSSR.Extensions
|
||||
{
|
||||
routeEndpointBuilder.Metadata.Add(new RootComponentMetadata(typeof(App)));
|
||||
routeEndpointBuilder.Metadata.Add(new ComponentTypeMetadata(typeof(App)));
|
||||
routeEndpointBuilder.Metadata.Add(new RequireAntiforgeryTokenAttribute());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.ConfigureApplicationCookie(options =>
|
||||
{
|
||||
options.Cookie.HttpOnly = true;
|
||||
options.Cookie.SameSite = SameSiteMode.Strict;
|
||||
options.Cookie.SameSite = SameSiteMode.Lax;
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
|
||||
options.Events.OnRedirectToLogin = context =>
|
||||
{
|
||||
|
@ -539,6 +539,8 @@ namespace Oqtane.Infrastructure
|
||||
var identityUserManager = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>();
|
||||
|
||||
var tenant = tenants.GetTenants().FirstOrDefault(item => item.Name == install.TenantName);
|
||||
var rendermode = (!string.IsNullOrEmpty(install.RenderMode)) ? install.RenderMode : _configManager.GetSection("RenderMode").Value;
|
||||
var runtime = (!string.IsNullOrEmpty(install.Runtime)) ? install.Runtime : _configManager.GetSection("Runtime").Value;
|
||||
|
||||
site = new Site
|
||||
{
|
||||
@ -556,9 +558,9 @@ namespace Oqtane.Infrastructure
|
||||
DefaultContainerType = (!string.IsNullOrEmpty(install.DefaultContainer)) ? install.DefaultContainer : Constants.DefaultContainer,
|
||||
AdminContainerType = (!string.IsNullOrEmpty(install.DefaultAdminContainer)) ? install.DefaultAdminContainer : Constants.DefaultAdminContainer,
|
||||
SiteTemplateType = install.SiteTemplate,
|
||||
RenderMode = (!string.IsNullOrEmpty(install.RenderMode)) ? install.RenderMode : _configManager.GetSection("RenderMode").Value,
|
||||
Runtime = (!string.IsNullOrEmpty(install.Runtime)) ? install.Runtime : _configManager.GetSection("Runtime").Value,
|
||||
Prerender = true,
|
||||
RenderMode = rendermode,
|
||||
Runtime = runtime,
|
||||
Prerender = (rendermode == RenderModes.Interactive),
|
||||
Hybrid = false
|
||||
};
|
||||
site = sites.AddSite(site);
|
||||
|
@ -197,6 +197,12 @@ namespace Oqtane.Infrastructure
|
||||
string[] segments = entry.FullName.Split('/'); // ZipArchiveEntries always use unix path separator
|
||||
string filename = Path.Combine(folder, string.Join(Path.DirectorySeparatorChar, segments, ignoreLeadingSegments, segments.Length - ignoreLeadingSegments));
|
||||
|
||||
// validate path to prevent path traversal
|
||||
if (!Path.GetFullPath(filename).StartsWith(folder + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(Path.GetDirectoryName(filename)))
|
||||
@ -227,6 +233,7 @@ namespace Oqtane.Infrastructure
|
||||
// an error occurred extracting the file
|
||||
filename = "";
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,7 @@ namespace Oqtane.Infrastructure
|
||||
}
|
||||
|
||||
var result = new StringBuilder();
|
||||
source = source.Replace("[[", "[$_["); //avoid nested square bracket issue.
|
||||
foreach (Match match in this.TokenizerRegex.Matches(source))
|
||||
{
|
||||
var key = match.Result("${key}");
|
||||
@ -126,7 +127,7 @@ namespace Oqtane.Infrastructure
|
||||
result.Append(match.Result("${text}"));
|
||||
}
|
||||
}
|
||||
|
||||
result.Replace("[$_", "["); //restore the changes.
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
|
@ -201,56 +201,54 @@ namespace Oqtane.Managers
|
||||
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
||||
if (identityuser != null)
|
||||
{
|
||||
var valid = true;
|
||||
if (!string.IsNullOrEmpty(user.Password))
|
||||
{
|
||||
var validator = new PasswordValidator<IdentityUser>();
|
||||
var result = await validator.ValidateAsync(_identityUserManager, null, user.Password);
|
||||
valid = result.Succeeded;
|
||||
if (valid)
|
||||
if (result.Succeeded)
|
||||
{
|
||||
identityuser.PasswordHash = _identityUserManager.PasswordHasher.HashPassword(identityuser, user.Password);
|
||||
await _identityUserManager.UpdateAsync(identityuser);
|
||||
}
|
||||
}
|
||||
if (valid)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(user.Password))
|
||||
else
|
||||
{
|
||||
await _identityUserManager.UpdateAsync(identityuser); // requires password to be provided
|
||||
_logger.Log(user.SiteId, LogLevel.Error, this, LogFunction.Update, "Unable To Update User {Username}. Password Does Not Meet Complexity Requirements.", user.Username);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (user.Email != identityuser.Email)
|
||||
{
|
||||
await _identityUserManager.SetEmailAsync(identityuser, user.Email);
|
||||
|
||||
// if email address changed and user is not administrator, email verification is required for new email address
|
||||
if (!user.EmailConfirmed)
|
||||
{
|
||||
var alias = _tenantManager.GetAlias();
|
||||
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string body = "Dear " + user.DisplayName + ",\n\nIn Order To Verify The Email Address Associated To Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
|
||||
var notification = new Notification(user.SiteId, user, "User Account Verification", body);
|
||||
_notifications.AddNotification(notification);
|
||||
}
|
||||
else
|
||||
{
|
||||
var emailConfirmationToken = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
await _identityUserManager.ConfirmEmailAsync(identityuser, emailConfirmationToken);
|
||||
}
|
||||
}
|
||||
|
||||
user = _users.UpdateUser(user);
|
||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.User, user.UserId, SyncEventActions.Update);
|
||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.User, user.UserId, SyncEventActions.Reload);
|
||||
user.Password = ""; // remove sensitive information
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user);
|
||||
}
|
||||
else
|
||||
|
||||
if (user.Email != identityuser.Email)
|
||||
{
|
||||
_logger.Log(user.SiteId, LogLevel.Error, this, LogFunction.Update, "Unable To Update User {Username}. Password Does Not Meet Complexity Requirements.", user.Username);
|
||||
user = null;
|
||||
await _identityUserManager.SetEmailAsync(identityuser, user.Email);
|
||||
|
||||
// if email address changed and it is not confirmed, verification is required for new email address
|
||||
if (!user.EmailConfirmed)
|
||||
{
|
||||
var alias = _tenantManager.GetAlias();
|
||||
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string body = "Dear " + user.DisplayName + ",\n\nIn Order To Verify The Email Address Associated To Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
|
||||
var notification = new Notification(user.SiteId, user, "User Account Verification", body);
|
||||
_notifications.AddNotification(notification);
|
||||
}
|
||||
}
|
||||
|
||||
if (user.EmailConfirmed)
|
||||
{
|
||||
var emailConfirmationToken = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
await _identityUserManager.ConfirmEmailAsync(identityuser, emailConfirmationToken);
|
||||
}
|
||||
|
||||
user = _users.UpdateUser(user);
|
||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.User, user.UserId, SyncEventActions.Update);
|
||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.User, user.UserId, SyncEventActions.Reload);
|
||||
user.Password = ""; // remove sensitive information
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(user.SiteId, LogLevel.Error, this, LogFunction.Update, "Unable To Update User {Username}. User Does Not Exist.", user.Username);
|
||||
user = null;
|
||||
}
|
||||
|
||||
return user;
|
||||
|
@ -7,6 +7,7 @@ using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Migrations.Framework;
|
||||
using Oqtane.Documentation;
|
||||
using System.Linq;
|
||||
|
||||
// ReSharper disable ConvertToUsingDeclaration
|
||||
|
||||
@ -29,10 +30,11 @@ namespace Oqtane.Modules.HtmlText.Manager
|
||||
public string ExportModule(Module module)
|
||||
{
|
||||
string content = "";
|
||||
var htmlText = _htmlText.GetHtmlText(module.ModuleId);
|
||||
if (htmlText != null)
|
||||
var htmltexts = _htmlText.GetHtmlTexts(module.ModuleId);
|
||||
if (htmltexts != null && htmltexts.Any())
|
||||
{
|
||||
content = WebUtility.HtmlEncode(htmlText.Content);
|
||||
var htmltext = htmltexts.OrderByDescending(item => item.CreatedOn).First();
|
||||
content = WebUtility.HtmlEncode(htmltext.Content);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>5.1.0</Version>
|
||||
<Version>5.1.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -11,7 +11,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
@ -33,19 +33,19 @@
|
||||
<EmbeddedResource Include="Scripts\MigrateTenant.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.3">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.5" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="8.0.5" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.8" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -46,15 +46,27 @@ namespace Oqtane.Pages
|
||||
{
|
||||
var sitemap = new List<Sitemap>();
|
||||
|
||||
// internal pages which should not be indexed
|
||||
string[] internalPaths = { "login", "register", "reset", "404" };
|
||||
|
||||
// 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 pageModules = _pageModules.GetPageModules(_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) && !internalPaths.Contains(page.Path))
|
||||
{
|
||||
var rooturl = _alias.Protocol + (string.IsNullOrEmpty(_alias.Path) ? _alias.Name : _alias.Name.Substring(0, _alias.Name.IndexOf("/")));
|
||||
sitemap.Add(new Sitemap { Url = rooturl + Utilities.NavigateUrl(_alias.Path, page.Path, ""), ModifiedOn = DateTime.UtcNow });
|
||||
var pageurl = rooturl;
|
||||
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))
|
||||
{
|
||||
|
@ -59,14 +59,14 @@ namespace Oqtane.Repository
|
||||
// delete logs in batches of 100 records
|
||||
var count = 0;
|
||||
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();
|
||||
while (logs.Count > 0)
|
||||
{
|
||||
count += logs.Count;
|
||||
db.Log.RemoveRange(logs);
|
||||
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();
|
||||
}
|
||||
return count;
|
||||
|
@ -287,7 +287,9 @@ namespace Oqtane.Repository
|
||||
{
|
||||
ModuleDefinition moduledefinition;
|
||||
|
||||
Type[] moduletypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModule))).ToArray();
|
||||
Type[] modulecontroltypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModuleControl))).ToArray();
|
||||
|
||||
foreach (Type modulecontroltype in modulecontroltypes)
|
||||
{
|
||||
// Check if type should be ignored
|
||||
@ -299,12 +301,9 @@ namespace Oqtane.Repository
|
||||
int index = moduledefinitions.FindIndex(item => item.ModuleDefinitionName == qualifiedModuleType);
|
||||
if (index == -1)
|
||||
{
|
||||
// determine if this module implements IModule
|
||||
Type moduletype = assembly
|
||||
.GetTypes()
|
||||
.Where(item => item.Namespace != null)
|
||||
.Where(item => item.Namespace == modulecontroltype.Namespace || item.Namespace.StartsWith(modulecontroltype.Namespace + "."))
|
||||
.FirstOrDefault(item => item.GetInterfaces().Contains(typeof(IModule)));
|
||||
// determine if this component is part of a module which implements IModule
|
||||
Type moduletype = moduletypes.FirstOrDefault(item => item.Namespace == modulecontroltype.Namespace);
|
||||
|
||||
if (moduletype != null)
|
||||
{
|
||||
// get property values from IModule
|
||||
@ -399,6 +398,22 @@ namespace Oqtane.Repository
|
||||
moduledefinitions[index] = moduledefinition;
|
||||
}
|
||||
|
||||
// process modules without UI components
|
||||
foreach (var moduletype in moduletypes.Where(m1 => !modulecontroltypes.Any(m2 => m1.Namespace == m2.Namespace)))
|
||||
{
|
||||
// get property values from IModule
|
||||
var moduleobject = Activator.CreateInstance(moduletype) as IModule;
|
||||
moduledefinition = moduleobject.ModuleDefinition;
|
||||
moduledefinition.ModuleDefinitionName = moduletype.Namespace + ", " + moduletype.Assembly.GetName().Name;
|
||||
moduledefinition.AssemblyName = assembly.GetName().Name;
|
||||
moduledefinition.Categories = "Headless";
|
||||
moduledefinition.PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.Utilize, RoleNames.Host, true)
|
||||
};
|
||||
moduledefinitions.Add(moduledefinition);
|
||||
}
|
||||
|
||||
return moduledefinitions;
|
||||
}
|
||||
|
||||
|
@ -165,22 +165,23 @@ namespace Oqtane.Repository
|
||||
if (!serverstate.IsInitialized)
|
||||
{
|
||||
var site = GetSite(alias.SiteId);
|
||||
|
||||
// initialize theme Assemblies
|
||||
site.Themes = _themeRepository.GetThemes().ToList();
|
||||
|
||||
// initialize module Assemblies
|
||||
var moduleDefinitions = _moduleDefinitionRepository.GetModuleDefinitions(alias.SiteId);
|
||||
|
||||
// execute migrations
|
||||
var version = ProcessSiteMigrations(alias, site);
|
||||
version = ProcessPageTemplates(alias, site, moduleDefinitions, version);
|
||||
if (site.Version != version)
|
||||
if (site != null)
|
||||
{
|
||||
site.Version = version;
|
||||
UpdateSite(site);
|
||||
}
|
||||
// initialize theme Assemblies
|
||||
site.Themes = _themeRepository.GetThemes().ToList();
|
||||
|
||||
// initialize module Assemblies
|
||||
var moduleDefinitions = _moduleDefinitionRepository.GetModuleDefinitions(alias.SiteId);
|
||||
|
||||
// execute migrations
|
||||
var version = ProcessSiteMigrations(alias, site);
|
||||
version = ProcessPageTemplates(alias, site, moduleDefinitions, version);
|
||||
if (site.Version != version)
|
||||
{
|
||||
site.Version = version;
|
||||
UpdateSite(site);
|
||||
}
|
||||
}
|
||||
serverstate.IsInitialized = true;
|
||||
}
|
||||
}
|
||||
@ -411,7 +412,7 @@ namespace Oqtane.Repository
|
||||
}
|
||||
else
|
||||
{
|
||||
parent = pages.FirstOrDefault(item => item.Path.ToLower() == pageTemplate.Parent.ToLower());
|
||||
parent = pages.FirstOrDefault(item => item.Path.ToLower() == ((pageTemplate.Parent == "/") ? "" : pageTemplate.Parent.ToLower()));
|
||||
}
|
||||
page.ParentId = (parent != null) ? parent.PageId : null;
|
||||
page.Path = page.Path.ToLower();
|
||||
@ -487,7 +488,11 @@ namespace Oqtane.Repository
|
||||
pageModule.Order = (pageTemplateModule.Order == 0) ? 1 : pageTemplateModule.Order;
|
||||
pageModule.ContainerType = pageTemplateModule.ContainerType;
|
||||
pageModule.IsDeleted = pageTemplateModule.IsDeleted;
|
||||
pageModule.Module.PermissionList = pageTemplateModule.PermissionList;
|
||||
pageModule.Module.PermissionList = new List<Permission>();
|
||||
foreach (var permission in pageTemplateModule.PermissionList)
|
||||
{
|
||||
pageModule.Module.PermissionList.Add(permission.Clone(permission));
|
||||
}
|
||||
pageModule.Module.AllPages = false;
|
||||
pageModule.Module.IsDeleted = false;
|
||||
try
|
||||
@ -539,8 +544,11 @@ namespace Oqtane.Repository
|
||||
try
|
||||
{
|
||||
var module = _moduleRepository.GetModule(pageModule.ModuleId);
|
||||
var moduleobject = ActivatorUtilities.CreateInstance(_serviceProvider, moduletype);
|
||||
((IPortable)moduleobject).ImportModule(module, pageTemplateModule.Content, moduleDefinition.Version);
|
||||
if (module != null)
|
||||
{
|
||||
var moduleobject = ActivatorUtilities.CreateInstance(_serviceProvider, moduletype);
|
||||
((IPortable)moduleobject).ImportModule(module, pageTemplateModule.Content, moduleDefinition.Version);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ using Oqtane.Shared;
|
||||
using Oqtane.Themes;
|
||||
using System.Reflection.Metadata;
|
||||
using Oqtane.Migrations.Master;
|
||||
using Oqtane.Modules;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
@ -224,9 +225,11 @@ namespace Oqtane.Repository
|
||||
private List<Theme> LoadThemesFromAssembly(List<Theme> themes, Assembly assembly)
|
||||
{
|
||||
Theme theme;
|
||||
List<Type> themeTypes = new List<Type>();
|
||||
|
||||
Type[] themeTypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ITheme))).ToArray();
|
||||
Type[] themeControlTypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IThemeControl))).ToArray();
|
||||
Type[] containerControlTypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IContainerControl))).ToArray();
|
||||
|
||||
foreach (Type themeControlType in themeControlTypes)
|
||||
{
|
||||
// Check if type should be ignored
|
||||
@ -240,16 +243,9 @@ namespace Oqtane.Repository
|
||||
int index = themes.FindIndex(item => item.ThemeName == qualifiedThemeType);
|
||||
if (index == -1)
|
||||
{
|
||||
// Find all types in the assembly with the same namespace root
|
||||
themeTypes = assembly.GetTypes()
|
||||
.Where(item => !item.IsOqtaneIgnore())
|
||||
.Where(item => item.Namespace != null)
|
||||
.Where(item => item.Namespace == themeControlType.Namespace || item.Namespace.StartsWith(themeControlType.Namespace + "."))
|
||||
.ToList();
|
||||
// determine if this component is part of a theme which implements ITheme
|
||||
Type themetype = themeTypes.FirstOrDefault(item => item.Namespace == themeControlType.Namespace);
|
||||
|
||||
// determine if this theme implements ITheme
|
||||
Type themetype = themeTypes
|
||||
.FirstOrDefault(item => item.GetInterfaces().Contains(typeof(ITheme)));
|
||||
if (themetype != null)
|
||||
{
|
||||
var themeobject = Activator.CreateInstance(themetype) as ITheme;
|
||||
@ -285,6 +281,7 @@ namespace Oqtane.Repository
|
||||
}
|
||||
theme = themes[index];
|
||||
|
||||
// add theme control
|
||||
var themecontrolobject = Activator.CreateInstance(themeControlType) as IThemeControl;
|
||||
theme.Themes.Add(
|
||||
new ThemeControl
|
||||
@ -296,14 +293,12 @@ namespace Oqtane.Repository
|
||||
}
|
||||
);
|
||||
|
||||
// containers
|
||||
Type[] containertypes = themeTypes
|
||||
.Where(item => item.GetInterfaces().Contains(typeof(IContainerControl))).ToArray();
|
||||
foreach (Type containertype in containertypes)
|
||||
if (!theme.Containers.Any())
|
||||
{
|
||||
var containerobject = Activator.CreateInstance(containertype) as IThemeControl;
|
||||
if (theme.Containers.FirstOrDefault(item => item.TypeName == containertype.FullName + ", " + themeControlType.Assembly.GetName().Name) == null)
|
||||
// add container controls
|
||||
foreach (Type containertype in containerControlTypes.Where(item => item.Namespace == themeControlType.Namespace))
|
||||
{
|
||||
var containerobject = Activator.CreateInstance(containertype) as IThemeControl;
|
||||
theme.Containers.Add(
|
||||
new ThemeControl
|
||||
{
|
||||
|
@ -22,6 +22,7 @@ using Oqtane.UI;
|
||||
using OqtaneSSR.Extensions;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Oqtane.Providers;
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
|
||||
namespace Oqtane
|
||||
{
|
||||
@ -135,7 +136,7 @@ namespace Oqtane
|
||||
{
|
||||
// allow .NET MAUI client cross origin calls
|
||||
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.
|
||||
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))
|
||||
{
|
||||
@ -198,7 +199,16 @@ namespace Oqtane
|
||||
app.UseOqtaneLocalization();
|
||||
|
||||
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.UseTenantResolution();
|
||||
app.UseJwtAuthorization();
|
||||
@ -206,6 +216,7 @@ namespace Oqtane
|
||||
app.UseCors();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseAntiforgery();
|
||||
|
||||
if (_useSwagger)
|
||||
{
|
||||
|
@ -13,9 +13,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.5" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
||||
|
@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<AccelerateBuildsInVisualStudio>false</AccelerateBuildsInVisualStudio>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -19,10 +19,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -108,12 +108,12 @@
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
if (_login != "-")
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login, true);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -12,9 +12,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<AccelerateBuildsInVisualStudio>false</AccelerateBuildsInVisualStudio>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -35,6 +35,9 @@ app {
|
||||
}
|
||||
|
||||
/* Action Dialog */
|
||||
.app-actiondialog{
|
||||
position: absolute;
|
||||
}
|
||||
.app-actiondialog .modal {
|
||||
position: fixed; /* Stay in place */
|
||||
z-index: 9999; /* Sit on top */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user