Compare commits
122 Commits
Author | SHA1 | Date | |
---|---|---|---|
a84b497fae | |||
c33d1bcd3c | |||
4071e14a7e | |||
b5b3f190b7 | |||
d43a3e132c | |||
a90c21f80a | |||
2b768165e5 | |||
e8425ba03a | |||
b0a6f402e9 | |||
02e86a940b | |||
79d03eb43e | |||
b564955f85 | |||
5aed64f614 | |||
a823a4d9b7 | |||
4eed2193f4 | |||
48e7a41af6 | |||
bba5caecf7 | |||
ede6a45f15 | |||
9c65d23229 | |||
5dedfe9295 | |||
95d8c368c8 | |||
49fbfb8bbc | |||
aa3d2a5289 | |||
48ae6df4b7 | |||
c635351a12 | |||
d9ff77fd9a | |||
e1a7954307 | |||
efe6421133 | |||
79b62f4407 | |||
9d17804ac7 | |||
5986355504 | |||
192e6fde92 | |||
ad090e62cc | |||
5c072fea62 | |||
fd01a40810 | |||
7b9a83a273 | |||
f964e0e502 | |||
22acb7c74b | |||
6a99e81e75 | |||
93b6de1caf | |||
1fbab5db2b | |||
950e852dee | |||
826898e3fe | |||
1268149d83 | |||
908299970f | |||
861dde8627 | |||
cc9802a0d8 | |||
69d1f3aa53 | |||
ea4587d842 | |||
fb4c95f945 | |||
95a27af5f2 | |||
9d7b25ade6 | |||
3a8f4199cd | |||
11002efc02 | |||
367c1c3568 | |||
9e04230d99 | |||
21304db7c9 | |||
f4f6e98045 | |||
ad41eff38a | |||
dbd6cc4148 | |||
dda71e5ccd | |||
cfe8059176 | |||
8b00784ecc | |||
9bcc6bbad0 | |||
ce7995966d | |||
cea5f86df4 | |||
0912253b1b | |||
5aecc4be03 | |||
e09178c14c | |||
477ded6a4a | |||
311c48becb | |||
ec924a7ddf | |||
e39416a786 | |||
51b356cc0e | |||
66b13bdb8b | |||
4ade58da01 | |||
efcfc0783c | |||
aa22db7fe5 | |||
5e0f008b65 | |||
eaf840e1da | |||
fc9e47778b | |||
35edf78aed | |||
07718f0449 | |||
6759156519 | |||
e2688e6feb | |||
65ba6423b1 | |||
a2f8fe3694 | |||
5273a17ab6 | |||
f7c1e7b706 | |||
45bbc4c681 | |||
6af5682548 | |||
24ed06626d | |||
eeff4af167 | |||
17f46afe14 | |||
224618cf21 | |||
ea93ab2a83 | |||
b9f7c39550 | |||
86b4b8e43a | |||
f54d07548e | |||
037db8a3e4 | |||
8f00e85abd | |||
9ccc4c4059 | |||
8408f98693 | |||
cde271fd5b | |||
c21a097fd2 | |||
83c32d4963 | |||
22c2d56da0 | |||
bd8d6e0480 | |||
825eb700b1 | |||
e59ee70f88 | |||
1173a29ed5 | |||
6a2ff369ea | |||
e22606ae79 | |||
bf56c2a9fa | |||
6567b55ea3 | |||
20e90c0de4 | |||
2892d5ec6f | |||
e034811e92 | |||
ee18bbd145 | |||
e3ebbde767 | |||
6a57980439 | |||
765760f3a5 |
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2021 .NET Foundation
|
||||
Copyright (c) 2018-2022 .NET Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -30,38 +30,38 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string AntiForgeryToken { get; set; }
|
||||
[Parameter]
|
||||
public string AntiForgeryToken { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Runtime { get; set; }
|
||||
[Parameter]
|
||||
public string Runtime { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
|
||||
private bool _initialized = false;
|
||||
private string _display = "display: none;";
|
||||
private Installation _installation = new Installation { Success = false, Message = "" };
|
||||
[Parameter]
|
||||
public string RemoteIPAddress { get; set; }
|
||||
|
||||
private PageState PageState { get; set; }
|
||||
private bool _initialized = false;
|
||||
private string _display = "display: none;";
|
||||
private Installation _installation = new Installation { Success = false, Message = "" };
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
SiteState.AntiForgeryToken = AntiForgeryToken;
|
||||
InstallationService.SetAntiForgeryTokenHeader(AntiForgeryToken);
|
||||
private PageState PageState { get; set; }
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
SiteState.RemoteIPAddress = RemoteIPAddress;
|
||||
SiteState.AntiForgeryToken = AntiForgeryToken;
|
||||
InstallationService.SetAntiForgeryTokenHeader(AntiForgeryToken);
|
||||
|
||||
_installation = await InstallationService.IsInstalled();
|
||||
if (_installation.Alias != null)
|
||||
{
|
||||
SiteState.Alias = _installation.Alias;
|
||||
}
|
||||
else
|
||||
{
|
||||
_installation.Message = "Site Not Configured Correctly - No Matching Alias Exists For Host Name";
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,6 @@
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
|
||||
_pages = PageState.Pages.Where(item => item.ParentId == admin?.PageId).ToList();
|
||||
_pages = PageState.Pages.Where(item => item.ParentId == admin?.PageId && !item.IsDeleted).ToList();
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,9 @@
|
||||
<option value="m">@Localizer["Minute(s)"]</option>
|
||||
<option value="H">@Localizer["Hour(s)"]</option>
|
||||
<option value="d">@Localizer["Day(s)"]</option>
|
||||
<option value="w">@Localizer["Week(s)"]</option>
|
||||
<option value="M">@Localizer["Month(s)"]</option>
|
||||
<option value="O">@Localizer["Once"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@ -95,82 +97,89 @@
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private int _jobId;
|
||||
private string _name = string.Empty;
|
||||
private string _jobType = string.Empty;
|
||||
private string _isEnabled = "True";
|
||||
private string _interval = string.Empty;
|
||||
private string _frequency = string.Empty;
|
||||
private DateTime? _startDate = null;
|
||||
private string _startTime = string.Empty;
|
||||
private DateTime? _endDate = null;
|
||||
private string _endTime = string.Empty;
|
||||
private string _retentionHistory = string.Empty;
|
||||
private DateTime? _nextDate = null;
|
||||
private string _nextTime = string.Empty;
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private int _jobId;
|
||||
private string _name = string.Empty;
|
||||
private string _jobType = string.Empty;
|
||||
private string _isEnabled = "True";
|
||||
private string _interval = string.Empty;
|
||||
private string _frequency = string.Empty;
|
||||
private DateTime? _startDate = null;
|
||||
private string _startTime = string.Empty;
|
||||
private DateTime? _endDate = null;
|
||||
private string _endTime = string.Empty;
|
||||
private string _retentionHistory = string.Empty;
|
||||
private DateTime? _nextDate = null;
|
||||
private string _nextTime = string.Empty;
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_jobId = Int32.Parse(PageState.QueryString["id"]);
|
||||
Job job = await JobService.GetJobAsync(_jobId);
|
||||
if (job != null)
|
||||
{
|
||||
_name = job.Name;
|
||||
_jobType = job.JobType;
|
||||
_isEnabled = job.IsEnabled.ToString();
|
||||
_interval = job.Interval.ToString();
|
||||
_frequency = job.Frequency;
|
||||
_startDate = job.StartDate;
|
||||
if (job.StartDate != null && job.StartDate.Value.TimeOfDay.TotalSeconds != 0)
|
||||
{
|
||||
_startTime = job.StartDate.Value.ToString("HH:mm");
|
||||
}
|
||||
_endDate = job.EndDate;
|
||||
if (job.EndDate != null && job.EndDate.Value.TimeOfDay.TotalSeconds != 0)
|
||||
{
|
||||
_endTime = job.EndDate.Value.ToString("HH:mm");
|
||||
}
|
||||
_retentionHistory = job.RetentionHistory.ToString();
|
||||
_nextDate = job.NextExecution;
|
||||
if (job.NextExecution != null && job.NextExecution.Value.TimeOfDay.TotalSeconds != 0)
|
||||
{
|
||||
_nextTime = job.NextExecution.Value.ToString("HH:mm");
|
||||
}
|
||||
createdby = job.CreatedBy;
|
||||
createdon = job.CreatedOn;
|
||||
modifiedby = job.ModifiedBy;
|
||||
modifiedon = job.ModifiedOn;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Job {JobId} {Error}", _jobId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Job.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_jobId = Int32.Parse(PageState.QueryString["id"]);
|
||||
Job job = await JobService.GetJobAsync(_jobId);
|
||||
if (job != null)
|
||||
{
|
||||
_name = job.Name;
|
||||
_jobType = job.JobType;
|
||||
_isEnabled = job.IsEnabled.ToString();
|
||||
_interval = job.Interval.ToString();
|
||||
_frequency = job.Frequency;
|
||||
_startDate = job.StartDate;
|
||||
if (job.StartDate != null && job.StartDate.Value.TimeOfDay.TotalSeconds != 0)
|
||||
{
|
||||
_startTime = job.StartDate.Value.ToString("HH:mm");
|
||||
}
|
||||
_endDate = job.EndDate;
|
||||
if (job.EndDate != null && job.EndDate.Value.TimeOfDay.TotalSeconds != 0)
|
||||
{
|
||||
_endTime = job.EndDate.Value.ToString("HH:mm");
|
||||
}
|
||||
_retentionHistory = job.RetentionHistory.ToString();
|
||||
_nextDate = job.NextExecution;
|
||||
if (job.NextExecution != null && job.NextExecution.Value.TimeOfDay.TotalSeconds != 0)
|
||||
{
|
||||
_nextTime = job.NextExecution.Value.ToString("HH:mm");
|
||||
}
|
||||
createdby = job.CreatedBy;
|
||||
createdon = job.CreatedOn;
|
||||
modifiedby = job.ModifiedBy;
|
||||
modifiedon = job.ModifiedOn;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Job {JobId} {Error}", _jobId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Job.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveJob()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
var job = await JobService.GetJobAsync(_jobId);
|
||||
job.Name = _name;
|
||||
job.JobType = _jobType;
|
||||
job.IsEnabled = Boolean.Parse(_isEnabled);
|
||||
job.Frequency = _frequency;
|
||||
job.Interval = int.Parse(_interval);
|
||||
private async Task SaveJob()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
var job = await JobService.GetJobAsync(_jobId);
|
||||
job.Name = _name;
|
||||
job.JobType = _jobType;
|
||||
job.IsEnabled = Boolean.Parse(_isEnabled);
|
||||
job.Frequency = _frequency;
|
||||
if (job.Frequency == "O") // once
|
||||
{
|
||||
job.Interval = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
job.Interval = int.Parse(_interval);
|
||||
}
|
||||
job.StartDate = _startDate;
|
||||
if (job.StartDate != null)
|
||||
{
|
||||
|
@ -36,75 +36,75 @@ else
|
||||
<td>@context.NextExecution</td>
|
||||
<td>
|
||||
@if (context.IsStarted)
|
||||
{
|
||||
{
|
||||
<button type="button" class="btn btn-danger" @onclick="(async () => await StopJob(context.JobId))">@Localizer["Stop"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick="(async () => await StartJob(context.JobId))">@Localizer["Start"]</button>
|
||||
}
|
||||
}
|
||||
</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<Job> _jobs;
|
||||
private List<Job> _jobs;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
|
||||
public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } }
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
}
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
}
|
||||
|
||||
private string DisplayStatus(bool isEnabled, bool isExecuting)
|
||||
{
|
||||
var status = string.Empty;
|
||||
if (!isEnabled)
|
||||
{
|
||||
status = Localizer["Disabled"];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isExecuting)
|
||||
{
|
||||
status = Localizer["Executing"];
|
||||
}
|
||||
else
|
||||
{
|
||||
status = Localizer["Idle"];
|
||||
}
|
||||
}
|
||||
private string DisplayStatus(bool isEnabled, bool isExecuting)
|
||||
{
|
||||
var status = string.Empty;
|
||||
if (!isEnabled)
|
||||
{
|
||||
status = Localizer["Disabled"];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isExecuting)
|
||||
{
|
||||
status = Localizer["Executing"];
|
||||
}
|
||||
else
|
||||
{
|
||||
status = Localizer["Idle"];
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
private string DisplayFrequency(int interval, string frequency)
|
||||
{
|
||||
var result = $"{Localizer["Every"]} {interval.ToString()} ";
|
||||
switch (frequency)
|
||||
{
|
||||
case "m":
|
||||
result += Localizer["Minute"];
|
||||
break;
|
||||
case "H":
|
||||
result += Localizer["Hour"];
|
||||
break;
|
||||
case "d":
|
||||
result += Localizer["Day"];
|
||||
break;
|
||||
case "M":
|
||||
result += Localizer["Month"];
|
||||
break;
|
||||
}
|
||||
|
||||
if (interval > 1)
|
||||
{
|
||||
result += Localizer["s"];
|
||||
}
|
||||
|
||||
private string DisplayFrequency(int interval, string frequency)
|
||||
{
|
||||
var result = "";
|
||||
switch (frequency)
|
||||
{
|
||||
case "m":
|
||||
result = $"{Localizer["Every"]} {interval.ToString()} " + Localizer["Minute"];
|
||||
break;
|
||||
case "H":
|
||||
result = $"{Localizer["Every"]} {interval.ToString()} " + Localizer["Hour"];
|
||||
break;
|
||||
case "d":
|
||||
result = $"{Localizer["Every"]} {interval.ToString()} " + Localizer["Day"];
|
||||
break;
|
||||
case "w":
|
||||
result = $"{Localizer["Every"]} {interval.ToString()} " + Localizer["Week"];
|
||||
break;
|
||||
case "M":
|
||||
result = $"{Localizer["Every"]} {interval.ToString()} " + Localizer["Month"];
|
||||
break;
|
||||
case "O":
|
||||
result = Localizer["Once"];
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -114,6 +114,7 @@ else
|
||||
{
|
||||
await JobService.DeleteJobAsync(job.JobId);
|
||||
await logger.LogInformation("Job Deleted {Job}", job);
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -125,12 +126,36 @@ else
|
||||
|
||||
private async Task StartJob(int jobId)
|
||||
{
|
||||
await JobService.StartJobAsync(jobId);
|
||||
try
|
||||
{
|
||||
await JobService.StartJobAsync(jobId);
|
||||
await logger.LogInformation("Job Started {JobId}", jobId);
|
||||
AddModuleMessage(Localizer["Message.Job.Start"], MessageType.Success);
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Starting Job {JobId} {Error}", jobId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Job.Start"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StopJob(int jobId)
|
||||
{
|
||||
await JobService.StopJobAsync(jobId);
|
||||
try
|
||||
{
|
||||
await JobService.StopJobAsync(jobId);
|
||||
await logger.LogInformation("Job Stopped {JobId}", jobId);
|
||||
AddModuleMessage(Localizer["Message.Job.Stop"], MessageType.Success);
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Stopping Job {JobId} {Error}", jobId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Job.Stop"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Refresh()
|
||||
|
@ -177,17 +177,17 @@
|
||||
{
|
||||
await UserService.ForgotPasswordAsync(user);
|
||||
await logger.LogInformation(LogFunction.Security, "Password Reset Notification Sent For Username {Username}", _username);
|
||||
_message = "Please Check The Email Address Associated To Your User Account For A Password Reset Notification";
|
||||
_message = Localizer["Message.ForgotUser"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = "User Does Not Exist";
|
||||
_message = Localizer["Message.UserDoesNotExist"];
|
||||
_type = MessageType.Warning;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = "Please Enter The Username Related To Your Account And Then Select The Forgot Password Option Again";
|
||||
_message = Localizer["Message.ForgotPassword"];
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
|
@ -9,86 +9,88 @@
|
||||
@inject IStringLocalizer<Detail> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="dateTime" HelpText="The date and time of this log" ResourceKey="DateTime">Date/Time: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="dateTime" class="form-control" @bind="@_logDate" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="level" HelpText="The level of this log" ResourceKey="Level">Level: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="level" class="form-control" @bind="@_level" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="feature" HelpText="The feature that was affected" ResourceKey="Feature">Feature: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="feature" class="form-control" @bind="@_feature" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="function" HelpText="The function that was performed" ResourceKey="Function">Function: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="function" class="form-control" @bind="@_function" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="category" HelpText="The categories that were affected" ResourceKey="Category">Category: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="category" class="form-control" @bind="@_category" readonly />
|
||||
</div>
|
||||
</div>
|
||||
@if (_pageName != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="page" HelpText="The page that was affected" ResourceKey="Page">Page: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="page" class="form-control" @bind="@_pageName" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (_moduleTitle != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="module" HelpText="The module that was affected" ResourceKey="Module">Module: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="module" class="form-control" @bind="@_moduleTitle" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (_username != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="user" HelpText="The user that caused this log" ResourceKey="User">User: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="user" class="form-control" @bind="@_username" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The url the log comes from" ResourceKey="Url">Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="template" HelpText="What the log is about" ResourceKey="Template">Template: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="template" class="form-control" @bind="@_template" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="message" HelpText="The message that the system generated" ResourceKey="Message">Message: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="message" class="form-control" @bind="@_message" rows="5" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
@if (!string.IsNullOrEmpty(_exception))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="exception" HelpText="The exceptions generated by the system" ResourceKey="Exception">Exception: </Label>
|
||||
@if (_initialized)
|
||||
{
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="dateTime" HelpText="The date and time of this log" ResourceKey="DateTime">Date/Time: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="dateTime" class="form-control" @bind="@_logDate" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="level" HelpText="The level of this log" ResourceKey="Level">Level: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="level" class="form-control" @bind="@_level" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="feature" HelpText="The feature that was affected" ResourceKey="Feature">Feature: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="feature" class="form-control" @bind="@_feature" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="function" HelpText="The function that was performed" ResourceKey="Function">Function: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="function" class="form-control" @bind="@_function" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="category" HelpText="The categories that were affected" ResourceKey="Category">Category: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="category" class="form-control" @bind="@_category" readonly />
|
||||
</div>
|
||||
</div>
|
||||
@if (_pageName != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="page" HelpText="The page that was affected" ResourceKey="Page">Page: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="page" class="form-control" @bind="@_pageName" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (_moduleTitle != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="module" HelpText="The module that was affected" ResourceKey="Module">Module: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="module" class="form-control" @bind="@_moduleTitle" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (_username != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="user" HelpText="The user that caused this log" ResourceKey="User">User: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="user" class="form-control" @bind="@_username" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The url the log comes from" ResourceKey="Url">Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="template" HelpText="What the log is about" ResourceKey="Template">Template: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="template" class="form-control" @bind="@_template" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="message" HelpText="The message that the system generated" ResourceKey="Message">Message: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="message" class="form-control" @bind="@_message" rows="5" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
@if (!string.IsNullOrEmpty(_exception))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="exception" HelpText="The exceptions generated by the system" ResourceKey="Exception">Exception: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="exception" class="form-control" @bind="@_exception" rows="5" readonly></textarea>
|
||||
</div>
|
||||
@ -107,81 +109,95 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<NavLink class="btn btn-secondary" href="@CloseUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
private int _logId;
|
||||
private string _logDate = string.Empty;
|
||||
private string _level = string.Empty;
|
||||
private string _feature = string.Empty;
|
||||
private string _function = string.Empty;
|
||||
private string _category = string.Empty;
|
||||
private string _pageName = string.Empty;
|
||||
private string _moduleTitle = string.Empty;
|
||||
private string _username = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private string _template = string.Empty;
|
||||
private string _message = string.Empty;
|
||||
private string _exception = string.Empty;
|
||||
private string _properties = string.Empty;
|
||||
private string _server = string.Empty;
|
||||
|
||||
@code {
|
||||
private int _logId;
|
||||
private string _logDate = string.Empty;
|
||||
private string _level = string.Empty;
|
||||
private string _feature = string.Empty;
|
||||
private string _function = string.Empty;
|
||||
private string _category = string.Empty;
|
||||
private string _pageName = string.Empty;
|
||||
private string _moduleTitle = string.Empty;
|
||||
private string _username = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private string _template = string.Empty;
|
||||
private string _message = string.Empty;
|
||||
private string _exception = string.Empty;
|
||||
private string _properties = string.Empty;
|
||||
private string _server = string.Empty;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
_logId = Int32.Parse(PageState.QueryString["id"]);
|
||||
var log = await LogService.GetLogAsync(_logId);
|
||||
if (log != null)
|
||||
{
|
||||
_logId = Int32.Parse(PageState.QueryString["id"]);
|
||||
var log = await LogService.GetLogAsync(_logId);
|
||||
if (log != null)
|
||||
_logDate = log.LogDate.ToString(CultureInfo.CurrentCulture);
|
||||
_level = log.Level;
|
||||
_feature = log.Feature;
|
||||
_function = log.Function;
|
||||
_category = log.Category;
|
||||
|
||||
if (log.PageId != null)
|
||||
{
|
||||
_logDate = log.LogDate.ToString(CultureInfo.CurrentCulture);
|
||||
_level = log.Level;
|
||||
_feature = log.Feature;
|
||||
_function = log.Function;
|
||||
_category = log.Category;
|
||||
|
||||
if (log.PageId != null)
|
||||
var page = await PageService.GetPageAsync(log.PageId.Value);
|
||||
if (page != null)
|
||||
{
|
||||
var page = await PageService.GetPageAsync(log.PageId.Value);
|
||||
if (page != null)
|
||||
{
|
||||
_pageName = page.Name;
|
||||
}
|
||||
_pageName = page.Name;
|
||||
}
|
||||
|
||||
if (log.PageId != null && log.ModuleId != null)
|
||||
{
|
||||
var pagemodule = await PageModuleService.GetPageModuleAsync(log.PageId.Value, log.ModuleId.Value);
|
||||
if (pagemodule != null)
|
||||
{
|
||||
_moduleTitle = pagemodule.Title;
|
||||
}
|
||||
}
|
||||
|
||||
if (log.UserId != null)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(log.UserId.Value, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
_username = user.Username;
|
||||
}
|
||||
}
|
||||
|
||||
_url = log.Url;
|
||||
_template = log.MessageTemplate;
|
||||
_message = log.Message;
|
||||
_exception = log.Exception;
|
||||
_properties = log.Properties;
|
||||
_server = log.Server;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Log {LogId} {Error}", _logId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Log.Load"], MessageType.Error);
|
||||
|
||||
if (log.PageId != null && log.ModuleId != null)
|
||||
{
|
||||
var pagemodule = await PageModuleService.GetPageModuleAsync(log.PageId.Value, log.ModuleId.Value);
|
||||
if (pagemodule != null)
|
||||
{
|
||||
_moduleTitle = pagemodule.Title;
|
||||
}
|
||||
}
|
||||
|
||||
if (log.UserId != null)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(log.UserId.Value, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
_username = user.Username;
|
||||
}
|
||||
}
|
||||
|
||||
_url = log.Url;
|
||||
_template = log.MessageTemplate;
|
||||
_message = log.Message;
|
||||
_exception = log.Exception;
|
||||
_properties = log.Properties;
|
||||
_server = log.Server;
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Log {LogId} {Error}", _logId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Log.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private string CloseUrl()
|
||||
{
|
||||
if (!PageState.QueryString.ContainsKey("level"))
|
||||
{
|
||||
return NavigateUrl();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NavigateUrl(PageState.Page.Path, "level=" + PageState.QueryString["level"] + "&function=" + PageState.QueryString["function"] + "&rows=" + PageState.QueryString["rows"] + "&page=" + PageState.QueryString["page"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
@namespace Oqtane.Modules.Admin.Logs
|
||||
@inherits ModuleBase
|
||||
@inject ILogService LogService
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@ -10,73 +11,92 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="container g-0">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-4">
|
||||
<Label For="level" HelpText="Select the log level for event log items" ResourceKey="Level">Level: </Label><br /><br />
|
||||
<select id="level" class="form-select" @onchange="(e => LevelChanged(e))">
|
||||
<option value="-"><@Localizer["AllLevels"]></option>
|
||||
<option value="Trace">@Localizer["Trace"]</option>
|
||||
<option value="Debug">@Localizer["Debug"]</option>
|
||||
<option value="Information">@Localizer["Information"]</option>
|
||||
<option value="Warning">@Localizer["Warning"]</option>
|
||||
<option value="Error">@Localizer["Error"]</option>
|
||||
<option value="Critical">@Localizer["Critical"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<Label For="function" HelpText="Select the function for event log items" ResourceKey="Function">Function: </Label><br /><br />
|
||||
<select id="function" class="form-select" @onchange="(e => FunctionChanged(e))">
|
||||
<option value="-"><@Localizer["AllFunctions"]></option>
|
||||
<option value="Create">@Localizer["Create"]</option>
|
||||
<option value="Read">@Localizer["Read"]</option>
|
||||
<option value="Update">@SharedLocalizer["Update"]</option>
|
||||
<option value="Delete">@SharedLocalizer["Delete"]</option>
|
||||
<option value="Security">@Localizer["Security"]</option>
|
||||
<option value="Other">@Localizer["Other"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<Label For="rows" HelpText="Select the maximum number of event log items to review. Please note that if you choose more than 10 items the information will be split into pages." ResourceKey="Rows">Maximum Items: </Label><br /><br />
|
||||
<select id="rows" class="form-select" @onchange="(e => RowsChanged(e))">
|
||||
<option value="10">10</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TabStrip>
|
||||
<TabPanel Name="Events" Heading="Events" ResourceKey="Events">
|
||||
<div class="container g-0">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-4">
|
||||
<Label For="level" HelpText="Select the log level for event log items" ResourceKey="Level">Level: </Label><br /><br />
|
||||
<select id="level" class="form-select" value="@_level" @onchange="(e => LevelChanged(e))">
|
||||
<option value="-"><@Localizer["AllLevels"]></option>
|
||||
<option value="Trace">@Localizer["Trace"]</option>
|
||||
<option value="Debug">@Localizer["Debug"]</option>
|
||||
<option value="Information">@Localizer["Information"]</option>
|
||||
<option value="Warning">@Localizer["Warning"]</option>
|
||||
<option value="Error">@Localizer["Error"]</option>
|
||||
<option value="Critical">@Localizer["Critical"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<Label For="function" HelpText="Select the function for event log items" ResourceKey="Function">Function: </Label><br /><br />
|
||||
<select id="function" class="form-select" value="@_function" @onchange="(e => FunctionChanged(e))">
|
||||
<option value="-"><@Localizer["AllFunctions"]></option>
|
||||
<option value="Create">@Localizer["Create"]</option>
|
||||
<option value="Read">@Localizer["Read"]</option>
|
||||
<option value="Update">@SharedLocalizer["Update"]</option>
|
||||
<option value="Delete">@SharedLocalizer["Delete"]</option>
|
||||
<option value="Security">@Localizer["Security"]</option>
|
||||
<option value="Other">@Localizer["Other"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<Label For="rows" HelpText="Select the maximum number of event log items to review. Please note that if you choose more than 10 items the information will be split into pages." ResourceKey="Rows">Maximum Items: </Label><br /><br />
|
||||
<select id="rows" class="form-select" value="@_rows" @onchange="(e => RowsChanged(e))">
|
||||
<option value="10">10</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
@if (_logs.Any())
|
||||
{
|
||||
<Pager Items="@_logs">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Date"]</th>
|
||||
<th>@Localizer["Level"]</th>
|
||||
<th>@Localizer["Feature"]</th>
|
||||
<th>@Localizer["Function"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"id=" + context.LogId.ToString())" 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>
|
||||
<td class="@GetClass(context.Function)">@context.Function</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p><em>@Localizer["NoLogs"]</em></p>
|
||||
}
|
||||
@if (_logs.Any())
|
||||
{
|
||||
<Pager Items="@_logs" CurrentPage="@_page.ToString()" OnPageChange="OnPageChange">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Date"]</th>
|
||||
<th>@Localizer["Level"]</th>
|
||||
<th>@Localizer["Feature"]</th>
|
||||
<th>@Localizer["Function"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"id=" + context.LogId.ToString() + "&level=" + _level + "&function=" + _function + "&rows=" + _rows + "&page=" + _page.ToString())" 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>
|
||||
<td class="@GetClass(context.Function)">@context.Function</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p><em>@Localizer["NoLogs"]</em></p>
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of events to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="retention" class="form-control" @bind="@_retention" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _level = "-";
|
||||
private string _function = "-";
|
||||
private string _rows = "10";
|
||||
private int _page = 1;
|
||||
private List<Log> _logs;
|
||||
private string _retention = "";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
@ -84,7 +104,27 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("level"))
|
||||
{
|
||||
_level = PageState.QueryString["level"];
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("function"))
|
||||
{
|
||||
_function = PageState.QueryString["function"];
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("rows"))
|
||||
{
|
||||
_rows = PageState.QueryString["rows"];
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("page") && int.TryParse(PageState.QueryString["page"], out int page))
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
|
||||
await GetLogs();
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_retention = SettingService.GetSetting(settings, "LogRetention", "30");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -170,4 +210,27 @@ else
|
||||
}
|
||||
return classname;
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "LogRetention", _retention, 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);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPageChange(int page)
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ else
|
||||
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference };
|
||||
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
||||
|
||||
var settings = ModuleState.Settings;
|
||||
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||
SettingService.SetSetting(settings, "ModuleDefinitionName", moduleDefinition.ModuleDefinitionName);
|
||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||
|
||||
|
@ -37,7 +37,7 @@ else
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Version</td>
|
||||
<td>
|
||||
@if(context.AssemblyName == "Oqtane.Client" || PageState.Modules.Where(m => m.ModuleDefinition.ModuleDefinitionId == context.ModuleDefinitionId).Count() > 0)
|
||||
@if(context.AssemblyName == "Oqtane.Client" || PageState.Modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
|
||||
{
|
||||
<span>@SharedLocalizer["Yes"]</span>
|
||||
}
|
||||
|
@ -95,6 +95,12 @@
|
||||
<input id="title" class="form-control" @bind="@_title" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="meta" HelpText="Optionally enter meta tags (in exactly the form you want them to be included in the page output)." ResourceKey="Meta">Meta: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="meta" class="form-control" @bind="@_meta" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -156,220 +162,222 @@
|
||||
</form>
|
||||
|
||||
@code {
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
private List<Theme> _themeList;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private List<Page> _pageList;
|
||||
private string _name;
|
||||
private string _title;
|
||||
private string _path = string.Empty;
|
||||
private string _parentid = "-1";
|
||||
private string _insert = ">>";
|
||||
private List<Page> _children;
|
||||
private int _childid = -1;
|
||||
private string _isnavigation = "True";
|
||||
private string _isclickable = "True";
|
||||
private string _url;
|
||||
private string _ispersonalizable = "False";
|
||||
private string _themetype = string.Empty;
|
||||
private string _containertype = string.Empty;
|
||||
private string _icon = string.Empty;
|
||||
private string _permissions = string.Empty;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _themeSettingsType;
|
||||
private object _themeSettings;
|
||||
private RenderFragment ThemeSettingsComponent { get; set; }
|
||||
private bool _refresh = false;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private List<Theme> _themeList;
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private List<Page> _pageList;
|
||||
private string _name;
|
||||
private string _title;
|
||||
private string _meta;
|
||||
private string _path = string.Empty;
|
||||
private string _parentid = "-1";
|
||||
private string _insert = ">>";
|
||||
private List<Page> _children;
|
||||
private int _childid = -1;
|
||||
private string _isnavigation = "True";
|
||||
private string _isclickable = "True";
|
||||
private string _url;
|
||||
private string _ispersonalizable = "False";
|
||||
private string _themetype = string.Empty;
|
||||
private string _containertype = string.Empty;
|
||||
private string _icon = string.Empty;
|
||||
private string _permissions = string.Empty;
|
||||
private PermissionGrid _permissionGrid;
|
||||
private Type _themeSettingsType;
|
||||
private object _themeSettings;
|
||||
private RenderFragment ThemeSettingsComponent { get; set; }
|
||||
private bool _refresh = false;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
_themetype = PageState.Site.DefaultThemeType;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = PageState.Site.DefaultContainerType;
|
||||
_pageList = PageState.Pages;
|
||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||
_permissions = string.Empty;
|
||||
ThemeSettings();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Initializing Page {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Page.Initialize"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
_themetype = PageState.Site.DefaultThemeType;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = PageState.Site.DefaultContainerType;
|
||||
_pageList = PageState.Pages;
|
||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||
_permissions = string.Empty;
|
||||
ThemeSettings();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Initializing Page {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Page.Initialize"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void ParentChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_parentid = (string)e.Value;
|
||||
_children = new List<Page>();
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private async void ParentChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_parentid = (string)e.Value;
|
||||
_children = new List<Page>();
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = "-";
|
||||
ThemeSettings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = "-";
|
||||
ThemeSettings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThemeSettings()
|
||||
{
|
||||
_themeSettingsType = null;
|
||||
var theme = _themeList.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.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
_refresh = true;
|
||||
}
|
||||
}
|
||||
private void ThemeSettings()
|
||||
{
|
||||
_themeSettingsType = null;
|
||||
var theme = _themeList.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.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
_refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SavePage()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
Page page = null;
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
||||
{
|
||||
page = new Page();
|
||||
page.SiteId = PageState.Page.SiteId;
|
||||
page.Name = _name;
|
||||
page.Title = _title;
|
||||
private async Task SavePage()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
Page page = null;
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
||||
{
|
||||
page = new Page();
|
||||
page.SiteId = PageState.Page.SiteId;
|
||||
page.Name = _name;
|
||||
page.Title = _title;
|
||||
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
_path = _name;
|
||||
}
|
||||
if (_path.Contains("/"))
|
||||
{
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
_path = _name;
|
||||
}
|
||||
if (_path.Contains("/"))
|
||||
{
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
page.ParentId = null;
|
||||
page.Path = Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
page.ParentId = Int32.Parse(_parentid);
|
||||
var parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
|
||||
if (parent.Path == string.Empty)
|
||||
{
|
||||
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
}
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
page.ParentId = null;
|
||||
page.Path = Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
page.ParentId = Int32.Parse(_parentid);
|
||||
var parent = PageState.Pages.Where(item => item.PageId == page.ParentId).FirstOrDefault();
|
||||
if (parent.Path == string.Empty)
|
||||
{
|
||||
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
page.Path = parent.Path + "/" + Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
}
|
||||
|
||||
if(PagePathIsDeleted(page.Path, page.SiteId, _pageList))
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Message.Page.Deleted"], _path), MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
if(PagePathIsDeleted(page.Path, page.SiteId, _pageList))
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Message.Page.Deleted"], _path), MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PagePathIsUnique(page.Path, page.SiteId, _pageList))
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
if (!PagePathIsUnique(page.Path, page.SiteId, _pageList))
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
Page child;
|
||||
switch (_insert)
|
||||
{
|
||||
case "<<":
|
||||
page.Order = 0;
|
||||
break;
|
||||
case "<":
|
||||
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
||||
page.Order = child.Order - 1;
|
||||
break;
|
||||
case ">":
|
||||
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
||||
page.Order = child.Order + 1;
|
||||
break;
|
||||
case ">>":
|
||||
page.Order = int.MaxValue;
|
||||
break;
|
||||
}
|
||||
Page child;
|
||||
switch (_insert)
|
||||
{
|
||||
case "<<":
|
||||
page.Order = 0;
|
||||
break;
|
||||
case "<":
|
||||
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
||||
page.Order = child.Order - 1;
|
||||
break;
|
||||
case ">":
|
||||
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
||||
page.Order = child.Order + 1;
|
||||
break;
|
||||
case ">>":
|
||||
page.Order = int.MaxValue;
|
||||
break;
|
||||
}
|
||||
|
||||
page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation));
|
||||
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
|
||||
page.Url = _url;
|
||||
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
||||
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
||||
{
|
||||
page.ThemeType = string.Empty;
|
||||
}
|
||||
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
||||
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
||||
{
|
||||
page.DefaultContainerType = string.Empty;
|
||||
}
|
||||
page.Icon = (_icon == null ? string.Empty : _icon);
|
||||
page.Permissions = _permissionGrid.GetPermissions();
|
||||
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
||||
page.UserId = null;
|
||||
page.IsNavigation = (_isnavigation == null ? true : Boolean.Parse(_isnavigation));
|
||||
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
|
||||
page.Url = _url;
|
||||
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
||||
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
||||
{
|
||||
page.ThemeType = string.Empty;
|
||||
}
|
||||
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
||||
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
||||
{
|
||||
page.DefaultContainerType = string.Empty;
|
||||
}
|
||||
page.Icon = (_icon == null ? string.Empty : _icon);
|
||||
page.Permissions = _permissionGrid.GetPermissions();
|
||||
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
||||
page.UserId = null;
|
||||
page.Meta = _meta;
|
||||
|
||||
page = await PageService.AddPageAsync(page);
|
||||
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
|
||||
|
@ -102,6 +102,12 @@
|
||||
<input id="title" class="form-control" @bind="@_title" maxlength="200"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="meta" HelpText="Optionally enter meta tags (in exactly the form you want them to be included in the page output)." ResourceKey="Meta">Meta: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="meta" class="form-control" @bind="@_meta" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -200,6 +206,7 @@
|
||||
private int _pageId;
|
||||
private string _name;
|
||||
private string _title;
|
||||
private string _meta;
|
||||
private string _path;
|
||||
private string _currentparentid;
|
||||
private string _parentid = "-1";
|
||||
@ -243,6 +250,7 @@
|
||||
{
|
||||
_name = page.Name;
|
||||
_title = page.Title;
|
||||
_meta = page.Meta;
|
||||
_path = page.Path;
|
||||
_pageModules = PageState.Modules.Where(m => m.PageId == page.PageId && m.IsDeleted == false).ToList();
|
||||
|
||||
@ -313,183 +321,187 @@
|
||||
_pageModules.RemoveAll(item => item.PageModuleId == pagemodule.PageModuleId);
|
||||
StateHasChanged();
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri + "&tab=PageModules");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Module {Title} {Error}", module.Title, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Module {Title} {Error}", module.Title, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void ParentChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_parentid = (string)e.Value;
|
||||
_children = new List<Page>();
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_parentid == _currentparentid)
|
||||
{
|
||||
_insert = "=";
|
||||
}
|
||||
else
|
||||
{
|
||||
_insert = ">>";
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private async void ParentChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_parentid = (string)e.Value;
|
||||
_children = new List<Page>();
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||
{
|
||||
_children.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_parentid == _currentparentid)
|
||||
{
|
||||
_insert = "=";
|
||||
}
|
||||
else
|
||||
{
|
||||
_insert = ">>";
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Child Pages For Parent {PageId} {Error}", _parentid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.ChildPage.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = "-";
|
||||
ThemeSettings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private async void ThemeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_themetype = (string)e.Value;
|
||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||
_containertype = "-";
|
||||
ThemeSettings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Pane.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThemeSettings()
|
||||
{
|
||||
_themeSettingsType = null;
|
||||
var theme = _themeList.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.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
_refresh = true;
|
||||
}
|
||||
}
|
||||
private void ThemeSettings()
|
||||
{
|
||||
_themeSettingsType = null;
|
||||
if (PageState.QueryString.ContainsKey("cp")) // can only be displayed if invoked from Control Panel
|
||||
{
|
||||
var theme = _themeList.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.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
_refresh = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SavePage()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
Page page = null;
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
||||
{
|
||||
page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
||||
string currentPath = page.Path;
|
||||
private async Task SavePage()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
Page page = null;
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
||||
{
|
||||
page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
||||
string currentPath = page.Path;
|
||||
|
||||
page.Name = _name;
|
||||
page.Title = _title;
|
||||
page.Name = _name;
|
||||
page.Title = _title;
|
||||
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
_path = _name;
|
||||
}
|
||||
if (_path.Contains("/"))
|
||||
{
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
_path = _name;
|
||||
}
|
||||
if (_path.Contains("/"))
|
||||
{
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
page.ParentId = null;
|
||||
page.Path = Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
page.ParentId = Int32.Parse(_parentid);
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
page.ParentId = null;
|
||||
page.Path = Utilities.GetFriendlyUrl(_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
page.ParentId = Int32.Parse(_parentid);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (!PagePathIsUnique(page.Path, page.SiteId, page.PageId, _pageList))
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
if (!PagePathIsUnique(page.Path, page.SiteId, page.PageId, _pageList))
|
||||
{
|
||||
AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_insert != "=")
|
||||
{
|
||||
Page child;
|
||||
switch (_insert)
|
||||
{
|
||||
case "<<":
|
||||
page.Order = 0;
|
||||
break;
|
||||
case "<":
|
||||
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
|
||||
if (child != null) page.Order = child.Order - 1;
|
||||
break;
|
||||
case ">":
|
||||
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
|
||||
if (child != null) page.Order = child.Order + 1;
|
||||
break;
|
||||
case ">>":
|
||||
page.Order = int.MaxValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
page.IsNavigation = (_isnavigation == null || Boolean.Parse(_isnavigation));
|
||||
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
|
||||
page.Url = _url;
|
||||
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
||||
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
||||
{
|
||||
page.ThemeType = string.Empty;
|
||||
}
|
||||
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
||||
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
||||
{
|
||||
page.DefaultContainerType = string.Empty;
|
||||
}
|
||||
page.Icon = _icon ?? string.Empty;
|
||||
page.Permissions = _permissionGrid.GetPermissions();
|
||||
page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
|
||||
page.UserId = null;
|
||||
if (_insert != "=")
|
||||
{
|
||||
Page child;
|
||||
switch (_insert)
|
||||
{
|
||||
case "<<":
|
||||
page.Order = 0;
|
||||
break;
|
||||
case "<":
|
||||
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
|
||||
if (child != null) page.Order = child.Order - 1;
|
||||
break;
|
||||
case ">":
|
||||
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
|
||||
if (child != null) page.Order = child.Order + 1;
|
||||
break;
|
||||
case ">>":
|
||||
page.Order = int.MaxValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
page.IsNavigation = (_isnavigation == null || Boolean.Parse(_isnavigation));
|
||||
page.IsClickable = (_isclickable == null ? true : Boolean.Parse(_isclickable));
|
||||
page.Url = _url;
|
||||
page.ThemeType = (_themetype != "-") ? _themetype : string.Empty;
|
||||
if (!string.IsNullOrEmpty(page.ThemeType) && page.ThemeType == PageState.Site.DefaultThemeType)
|
||||
{
|
||||
page.ThemeType = string.Empty;
|
||||
}
|
||||
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
|
||||
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
|
||||
{
|
||||
page.DefaultContainerType = string.Empty;
|
||||
}
|
||||
page.Icon = _icon ?? string.Empty;
|
||||
page.Permissions = _permissionGrid.GetPermissions();
|
||||
page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
|
||||
page.UserId = null;
|
||||
page.Meta = _meta;
|
||||
|
||||
page = await PageService.UpdatePageAsync(page);
|
||||
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
|
||||
|
@ -25,7 +25,7 @@
|
||||
<th>@Localizer["DeletedOn"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-info" title="Restore">Restore</button></td>
|
||||
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-success" title="Restore">Restore</button></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>@context.Name</td>
|
||||
<td>@context.DeletedBy</td>
|
||||
@ -56,7 +56,7 @@
|
||||
<th>@Localizer["DeletedOn"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><button type="button" @onclick="@(() => RestoreModule(context))" class="btn btn-info" title="Restore">@Localizer["Restore"]</button></td>
|
||||
<td><button type="button" @onclick="@(() => RestoreModule(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
|
||||
<td><ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete"], context.Title)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
||||
<td>@PageState.Pages.Find(item => item.PageId == context.PageId).Name</td>
|
||||
<td>@context.Title</td>
|
||||
|
@ -7,41 +7,49 @@
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="form-group">
|
||||
<label for="Username" class="control-label">@SharedLocalizer["Username"] </label>
|
||||
<input type="text" class="form-control" placeholder="Username" @bind="@_username" readonly id="Username" />
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="username" HelpText="Your username will be populated from the link you received in the password reset notification" ResourceKey="Username">Username: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="username" type="text" class="form-control" @bind="@_username" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="Password" class="control-label">@SharedLocalizer["Password"] </label>
|
||||
<input type="password" class="form-control" placeholder="Password" @bind="@_password" id="Password" required />
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="password" HelpText="The new password. It must satisfy complexity rules for the site." ResourceKey="Password">Password: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="password" type="password" class="form-control" @bind="@_password" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="Confirm" class="control-label">@Localizer["Password.Confirm"] </label>
|
||||
<input type="password" class="form-control" placeholder="Password" @bind="@_confirm" id="Confirm" required />
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="confirm" HelpText="Enter the password again. It must exactly match the password entered above." ResourceKey="Confirm">Confirm: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="confirm" type="password" class="form-control" @bind="@_confirm" required />
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" @onclick="Reset">@Localizer["Password.Reset"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-primary" @onclick="Reset">@Localizer["Password.Reset"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private string _username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _confirm = string.Empty;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private string _username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _confirm = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("name") && PageState.QueryString.ContainsKey("token"))
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("name") && PageState.QueryString.ContainsKey("token"))
|
||||
{
|
||||
_username = PageState.QueryString["name"];
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(string.Empty));
|
||||
await logger.LogError(LogFunction.Security, "Invalid Attempt To Access User Password Reset");
|
||||
NavigationManager.NavigateTo(NavigateUrl("")); // home page
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,12 +53,14 @@ else
|
||||
<Pager Items="@userroles">
|
||||
<Header>
|
||||
<th>@Localizer["Users"]</th>
|
||||
<th>@SharedLocalizer["Username"]</th>
|
||||
<th>@Localizer["Effective"]</th>
|
||||
<th>@Localizer["Expiry"]</th>
|
||||
<th> </th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td>@context.User.DisplayName</td>
|
||||
<td>@context.User.Username</td>
|
||||
<td>@context.EffectiveDate</td>
|
||||
<td>@context.ExpiryDate</td>
|
||||
<td>
|
||||
|
@ -1,5 +1,6 @@
|
||||
@namespace Oqtane.Modules.Admin.Site
|
||||
@inherits ModuleBase
|
||||
@using System.Text.RegularExpressions
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ISiteService SiteService
|
||||
@inject ITenantService TenantService
|
||||
@ -22,81 +23,64 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="alias" HelpText="The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder). If a site has multiple aliases they should be separated by commas." ResourceKey="Aliases">Aliases: </Label>
|
||||
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
||||
<div class="col-sm-9">
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" required></textarea>
|
||||
}
|
||||
else
|
||||
{
|
||||
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" readonly></textarea>
|
||||
}
|
||||
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Is Deleted? </Label>
|
||||
<Label Class="col-sm-3" For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultTheme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
|
||||
<option value="-"><@Localizer["Theme.Select"]></option>
|
||||
@foreach (var theme in _themes)
|
||||
{
|
||||
<option value="@theme.TypeName">@theme.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultTheme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
|
||||
<option value="-"><@Localizer["Theme.Select"]></option>
|
||||
@foreach (var theme in _themes)
|
||||
{
|
||||
<option value="@theme.TypeName">@theme.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultContainer" class="form-select" @bind="@_containertype" required>
|
||||
<option value="-"><@Localizer["Container.Select"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultAdminContainer" class="form-select" @bind="@_admincontainertype" required>
|
||||
<option value="-"><@Localizer["Container.Select"]></option>
|
||||
<option value="@Constants.DefaultAdminContainer"><@Localizer["DefaultAdminContainer"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultContainer" class="form-select" @bind="@_containertype" required>
|
||||
<option value="-"><@Localizer["Container.Select"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultAdminContainer" class="form-select" @bind="@_admincontainertype" required>
|
||||
<option value="-"><@Localizer["Container.Select"]></option>
|
||||
<option value="@Constants.DefaultAdminContainer"><@Localizer["DefaultAdminContainer"]></option>
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Deleted? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -174,8 +158,29 @@
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
@if (_aliases != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="alias" HelpText="The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder). If a site has multiple aliases they should be separated by commas." ResourceKey="Aliases">Aliases: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultalias" HelpText="The default alias for the site. Requests for non-default aliases will be redirected to the default alias." ResourceKey="DefaultAlias">Default Alias: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultalias" class="form-select" @bind="@_defaultalias" required>
|
||||
@foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray())
|
||||
{
|
||||
<option value="@name">@name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -238,7 +243,8 @@
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _name = string.Empty;
|
||||
private List<Alias> _aliasList;
|
||||
private List<Alias> _aliases;
|
||||
private string _defaultalias = string.Empty;
|
||||
private string _urls = string.Empty;
|
||||
private string _runtime = "";
|
||||
private string _prerender = "";
|
||||
@ -288,13 +294,7 @@
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_aliasList = await AliasService.GetAliasesAsync();
|
||||
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
|
||||
{
|
||||
_urls += alias.Name + ",";
|
||||
}
|
||||
_urls = _urls.Substring(0, _urls.Length - 1);
|
||||
|
||||
await GetAliases();
|
||||
}
|
||||
|
||||
if (site.LogoFileId != null)
|
||||
@ -322,7 +322,7 @@
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||
@ -398,13 +398,17 @@
|
||||
var unique = true;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
_urls = Regex.Replace(_urls, @"\r\n?|\n", ","); // convert line breaks to commas
|
||||
var aliases = await AliasService.GetAliasesAsync();
|
||||
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray())
|
||||
{
|
||||
if (_aliasList.Exists(item => item.Name == name && item.SiteId != PageState.Alias.SiteId && item.TenantId != PageState.Alias.TenantId))
|
||||
var alias = aliases.Where(item => item.Name == name).FirstOrDefault();
|
||||
if (alias != null && unique)
|
||||
{
|
||||
unique = false;
|
||||
unique = (alias.TenantId == PageState.Site.TenantId && alias.SiteId == PageState.Site.SiteId);
|
||||
}
|
||||
}
|
||||
if (unique && string.IsNullOrEmpty(_defaultalias)) unique = false;
|
||||
}
|
||||
|
||||
if (unique)
|
||||
@ -422,7 +426,6 @@
|
||||
{
|
||||
site.Runtime = _runtime;
|
||||
site.RenderMode = _runtime + _prerender;
|
||||
refresh = true;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
}
|
||||
@ -461,145 +464,173 @@
|
||||
int? pwaappiconfileid = _pwaappiconfilemanager.GetFileId();
|
||||
if (pwaappiconfileid == -1) pwaappiconfileid = null;
|
||||
if (site.PwaAppIconFileId != pwaappiconfileid)
|
||||
{
|
||||
site.PwaAppIconFileId = pwaappiconfileid;
|
||||
{
|
||||
site.PwaAppIconFileId = pwaappiconfileid;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
int? pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId();
|
||||
}
|
||||
int? pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId();
|
||||
if (pwasplashiconfileid == -1) pwasplashiconfileid = null;
|
||||
if (site.PwaSplashIconFileId != pwasplashiconfileid)
|
||||
{
|
||||
site.PwaSplashIconFileId = pwasplashiconfileid;
|
||||
if (site.PwaSplashIconFileId != pwasplashiconfileid)
|
||||
{
|
||||
site.PwaSplashIconFileId = pwasplashiconfileid;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
}
|
||||
|
||||
site = await SiteService.UpdateSiteAsync(site);
|
||||
site = await SiteService.UpdateSiteAsync(site);
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
SettingService.SetSetting(settings, "SMTPHost", _smtphost);
|
||||
SettingService.SetSetting(settings, "SMTPPort", _smtpport);
|
||||
SettingService.SetSetting(settings, "SMTPSSL", _smtpssl);
|
||||
SettingService.SetSetting(settings, "SMTPUsername", _smtpusername);
|
||||
SettingService.SetSetting(settings, "SMTPPassword", _smtppassword);
|
||||
SettingService.SetSetting(settings, "SMTPSender", _smtpsender);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||
SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||
SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||
SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||
SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||
SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
|
||||
{
|
||||
if (!names.Contains(alias.Name))
|
||||
{
|
||||
await AliasService.DeleteAliasAsync(alias.AliasId);
|
||||
}
|
||||
}
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(sValue => sValue.Trim()).ToArray();
|
||||
foreach (Alias alias in _aliases)
|
||||
{
|
||||
if (!names.Contains(alias.Name.Trim()))
|
||||
{
|
||||
await AliasService.DeleteAliasAsync(alias.AliasId);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string name in names)
|
||||
{
|
||||
if (!_aliasList.Exists(item => item.Name == name))
|
||||
{
|
||||
Alias alias = new Alias();
|
||||
alias.Name = name;
|
||||
alias.TenantId = site.TenantId;
|
||||
alias.SiteId = site.SiteId;
|
||||
await AliasService.AddAliasAsync(alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (string name in names)
|
||||
{
|
||||
var alias = _aliases.Find(item => item.Name.Trim() == name);
|
||||
if (alias == null)
|
||||
{
|
||||
alias = new Alias();
|
||||
alias.Name = name;
|
||||
alias.TenantId = site.TenantId;
|
||||
alias.SiteId = site.SiteId;
|
||||
alias.IsDefault = (name == _defaultalias);
|
||||
await AliasService.AddAliasAsync(alias);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (alias.Name != name || alias.IsDefault != (alias.Name.Trim() == _defaultalias))
|
||||
{
|
||||
alias.Name = name;
|
||||
alias.IsDefault = (name == _defaultalias);
|
||||
await AliasService.UpdateAliasAsync(alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
await GetAliases();
|
||||
}
|
||||
|
||||
await logger.LogInformation("Site Settings Saved {Site}", site);
|
||||
await logger.LogInformation("Site Settings Saved {Site}", site);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(true), reload); // refresh/reload
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Required.SiteName"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSite"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
if (refresh || reload)
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(true), reload); // refresh/reload
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success);
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
}
|
||||
}
|
||||
else // deuplicate alias or default alias not specified
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Required.SiteName"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSite"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteSite()
|
||||
{
|
||||
try
|
||||
{
|
||||
var sites = await SiteService.GetSitesAsync();
|
||||
if (sites.Count > 1)
|
||||
{
|
||||
await SiteService.DeleteSiteAsync(PageState.Site.SiteId);
|
||||
await logger.LogInformation("Site Deleted {SiteId}", PageState.Site.SiteId);
|
||||
private async Task DeleteSite()
|
||||
{
|
||||
try
|
||||
{
|
||||
var sites = await SiteService.GetSitesAsync();
|
||||
if (sites.Count > 1)
|
||||
{
|
||||
await SiteService.DeleteSiteAsync(PageState.Site.SiteId);
|
||||
await logger.LogInformation("Site Deleted {SiteId}", PageState.Site.SiteId);
|
||||
|
||||
var aliases = await AliasService.GetAliasesAsync();
|
||||
foreach (Alias a in aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId))
|
||||
{
|
||||
await AliasService.DeleteAliasAsync(a.AliasId);
|
||||
}
|
||||
var aliases = await AliasService.GetAliasesAsync();
|
||||
foreach (Alias a in aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId))
|
||||
{
|
||||
await AliasService.DeleteAliasAsync(a.AliasId);
|
||||
}
|
||||
|
||||
NavigationManager.NavigateTo(NavigateUrl("admin/sites"));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.FailAuth.DeleteSite"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.DeleteSite"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
NavigationManager.NavigateTo(NavigateUrl("admin/sites"));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.FailAuth.DeleteSite"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.DeleteSite"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendEmail()
|
||||
{
|
||||
if (_smtphost != "" && _smtpport != "" && _smtpsender != "")
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
SettingService.SetSetting(settings, "SMTPHost", _smtphost);
|
||||
SettingService.SetSetting(settings, "SMTPPort", _smtpport);
|
||||
SettingService.SetSetting(settings, "SMTPSSL", _smtpssl);
|
||||
SettingService.SetSetting(settings, "SMTPUsername", _smtpusername);
|
||||
SettingService.SetSetting(settings, "SMTPPassword", _smtppassword);
|
||||
SettingService.SetSetting(settings, "SMTPSender", _smtpsender);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||
await logger.LogInformation("Site SMTP Settings Saved");
|
||||
private async Task SendEmail()
|
||||
{
|
||||
if (_smtphost != "" && _smtpport != "" && _smtpsender != "")
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||
SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||
SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||
SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||
SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||
SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||
await logger.LogInformation("Site SMTP Settings Saved");
|
||||
|
||||
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User.DisplayName, PageState.User.Email, PageState.User.DisplayName, PageState.User.Email, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
||||
AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Testing SMTP Configuration");
|
||||
AddModuleMessage(Localizer["Error.Smtp.TestConfig"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.required.Smtp"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User.DisplayName, PageState.User.Email, PageState.User.DisplayName, PageState.User.Email, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
||||
AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Testing SMTP Configuration");
|
||||
AddModuleMessage(Localizer["Error.Smtp.TestConfig"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.required.Smtp"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetAliases()
|
||||
{
|
||||
_urls = string.Empty;
|
||||
_defaultalias = string.Empty;
|
||||
_aliases = await AliasService.GetAliasesAsync();
|
||||
_aliases = _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId).OrderBy(item => item.AliasId).ToList();
|
||||
foreach (Alias alias in _aliases)
|
||||
{
|
||||
_urls += (_urls == string.Empty) ? alias.Name.Trim() : ", " + alias.Name.Trim();
|
||||
if (alias.IsDefault && string.IsNullOrEmpty(_defaultalias)) _defaultalias = alias.Name.Trim();
|
||||
}
|
||||
if (string.IsNullOrEmpty(_defaultalias)) _defaultalias = _aliases.First().Name.Trim();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
@namespace Oqtane.Modules.Admin.Sites
|
||||
@using Oqtane.Interfaces
|
||||
@using System.Text.RegularExpressions
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ITenantService TenantService
|
||||
@ -282,6 +283,7 @@ else
|
||||
{
|
||||
if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-" && _sitetemplatetype != "-")
|
||||
{
|
||||
_urls = Regex.Replace(_urls, @"\r\n?|\n", ",");
|
||||
var duplicates = new List<string>();
|
||||
var aliases = await AliasService.GetAliasesAsync();
|
||||
foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
@ -370,8 +372,7 @@ else
|
||||
if (installation.Success)
|
||||
{
|
||||
var aliasname = config.Aliases.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
|
||||
var uri = new Uri(NavigationManager.Uri);
|
||||
NavigationManager.NavigateTo(uri.Scheme + "://" + aliasname, true);
|
||||
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + aliasname, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -30,20 +30,16 @@ else
|
||||
|
||||
@code {
|
||||
private List<Alias> _sites;
|
||||
private string _scheme;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
var uri = new Uri(NavigationManager.Uri);
|
||||
_scheme = uri.Scheme + "://";
|
||||
|
||||
var aliases = await AliasService.GetAliasesAsync();
|
||||
_sites = new List<Alias>();
|
||||
foreach (Alias alias in aliases)
|
||||
{
|
||||
if (!_sites.Exists(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId))
|
||||
if (alias.IsDefault && !_sites.Exists(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId))
|
||||
{
|
||||
_sites.Add(alias);
|
||||
}
|
||||
@ -52,16 +48,11 @@ else
|
||||
|
||||
private void Edit(string name)
|
||||
{
|
||||
if (name.Equals("*"))
|
||||
{
|
||||
var uri = new Uri(NavigationManager.Uri);
|
||||
name = uri.Authority;
|
||||
}
|
||||
NavigationManager.NavigateTo(_scheme + name + "/admin/site/?reload");
|
||||
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name + "/admin/site", true);
|
||||
}
|
||||
|
||||
private void Browse(string name)
|
||||
{
|
||||
NavigationManager.NavigateTo(_scheme + name + "/?reload");
|
||||
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name, true);
|
||||
}
|
||||
}
|
||||
|
@ -57,22 +57,20 @@ else
|
||||
{
|
||||
@if (_results.Count > 0)
|
||||
{
|
||||
<div class="table-responsive">
|
||||
<Pager Class="table table-bordered" Items="@_results">
|
||||
<Header>
|
||||
@foreach (KeyValuePair<string, string> kvp in _results.First())
|
||||
{
|
||||
<th>@kvp.Key</th>
|
||||
}
|
||||
</Header>
|
||||
<Row>
|
||||
@foreach (KeyValuePair<string, string> kvp in context)
|
||||
{
|
||||
<td>@kvp.Value</td>
|
||||
}
|
||||
</Row>
|
||||
</Pager>
|
||||
</div>
|
||||
<Pager Class="table table-bordered" Items="@_results">
|
||||
<Header>
|
||||
@foreach (KeyValuePair<string, string> kvp in _results.First())
|
||||
{
|
||||
<th>@kvp.Key</th>
|
||||
}
|
||||
</Header>
|
||||
<Row>
|
||||
@foreach (KeyValuePair<string, string> kvp in context)
|
||||
{
|
||||
<td>@kvp.Value</td>
|
||||
}
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -33,7 +33,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="servertime" HelpText="Server Time" ResourceKey="ServerTime">Server Time: </Label>
|
||||
<Label Class="col-sm-3" For="servertime" HelpText="Server Date/Time (in UTC)" ResourceKey="ServerTime">Server Date/Time: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="servertime" class="form-control" @bind="@_servertime" readonly />
|
||||
</div>
|
||||
@ -99,32 +99,32 @@
|
||||
</TabStrip>
|
||||
|
||||
@code {
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
private string _version = string.Empty;
|
||||
private string _clrversion = string.Empty;
|
||||
private string _osversion = string.Empty;
|
||||
private string _serverpath = string.Empty;
|
||||
private string _servertime = string.Empty;
|
||||
private string _installationid = string.Empty;
|
||||
private string _version = string.Empty;
|
||||
private string _clrversion = string.Empty;
|
||||
private string _osversion = string.Empty;
|
||||
private string _serverpath = string.Empty;
|
||||
private string _servertime = string.Empty;
|
||||
private string _installationid = string.Empty;
|
||||
|
||||
private string _detailederrors = string.Empty;
|
||||
private string _logginglevel = string.Empty;
|
||||
private string _swagger = string.Empty;
|
||||
private string _packageservice = string.Empty;
|
||||
private string _detailederrors = string.Empty;
|
||||
private string _logginglevel = string.Empty;
|
||||
private string _swagger = string.Empty;
|
||||
private string _packageservice = string.Empty;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_version = Constants.Version;
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_version = Constants.Version;
|
||||
|
||||
Dictionary<string, string> systeminfo = await SystemService.GetSystemInfoAsync();
|
||||
if (systeminfo != null)
|
||||
{
|
||||
_clrversion = systeminfo["clrversion"];
|
||||
_osversion = systeminfo["osversion"];
|
||||
_serverpath = systeminfo["serverpath"];
|
||||
_servertime = systeminfo["servertime"];
|
||||
_installationid = systeminfo["installationid"];
|
||||
Dictionary<string, string> systeminfo = await SystemService.GetSystemInfoAsync();
|
||||
if (systeminfo != null)
|
||||
{
|
||||
_clrversion = systeminfo["clrversion"];
|
||||
_osversion = systeminfo["osversion"];
|
||||
_serverpath = systeminfo["serverpath"];
|
||||
_servertime = systeminfo["servertime"] + " UTC";
|
||||
_installationid = systeminfo["installationid"];
|
||||
|
||||
_detailederrors = systeminfo["detailederrors"];
|
||||
_logginglevel = systeminfo["logginglevel"];
|
||||
|
@ -40,28 +40,46 @@
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
var route = new Route(_url, PageState.Alias.Path);
|
||||
var url = route.SiteUrl + "/" + route.PagePath;
|
||||
if (_url != _mappedurl)
|
||||
{
|
||||
var url = PageState.Uri.Scheme + "://" + PageState.Uri.Authority + "/";
|
||||
url = url + (!string.IsNullOrEmpty(PageState.Alias.Path) ? PageState.Alias.Path + "/" : "");
|
||||
|
||||
var urlmapping = new UrlMapping();
|
||||
urlmapping.SiteId = PageState.Site.SiteId;
|
||||
urlmapping.Url = url;
|
||||
urlmapping.MappedUrl = _mappedurl;
|
||||
urlmapping.Requests = 0;
|
||||
urlmapping.CreatedOn = DateTime.UtcNow;
|
||||
urlmapping.RequestedOn = DateTime.UtcNow;
|
||||
_url = (_url.StartsWith("/")) ? _url.Substring(1) : _url;
|
||||
_url = (!_url.StartsWith("http")) ? url + _url : _url;
|
||||
|
||||
try
|
||||
{
|
||||
urlmapping = await UrlMappingService.AddUrlMappingAsync(urlmapping);
|
||||
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving UrlMapping {UrlMapping} {Error}", urlmapping, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveUrlMapping"], MessageType.Error);
|
||||
}
|
||||
if (_url.StartsWith(url))
|
||||
{
|
||||
var urlmapping = new UrlMapping();
|
||||
urlmapping.SiteId = PageState.Site.SiteId;
|
||||
var route = new Route(_url, PageState.Alias.Path);
|
||||
urlmapping.Url = route.PagePath;
|
||||
urlmapping.MappedUrl = _mappedurl.Replace(url, "");
|
||||
urlmapping.Requests = 0;
|
||||
urlmapping.CreatedOn = DateTime.UtcNow;
|
||||
urlmapping.RequestedOn = DateTime.UtcNow;
|
||||
|
||||
try
|
||||
{
|
||||
urlmapping = await UrlMappingService.AddUrlMappingAsync(urlmapping);
|
||||
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving UrlMapping {UrlMapping} {Error}", urlmapping, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.SaveUrlMapping"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.DuplicateUrlMapping"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -26,55 +26,64 @@
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
|
||||
private int _urlmappingid;
|
||||
private string _url = string.Empty;
|
||||
private string _mappedurl = string.Empty;
|
||||
private int _urlmappingid;
|
||||
private string _url = string.Empty;
|
||||
private string _mappedurl = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_urlmappingid = Int32.Parse(PageState.QueryString["id"]);
|
||||
var urlmapping = await UrlMappingService.GetUrlMappingAsync(_urlmappingid);
|
||||
if (urlmapping != null)
|
||||
{
|
||||
_url = urlmapping.Url;
|
||||
_mappedurl = urlmapping.MappedUrl;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading UrlMapping {UrlMappingId} {Error}", _urlmappingid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_urlmappingid = Int32.Parse(PageState.QueryString["id"]);
|
||||
var urlmapping = await UrlMappingService.GetUrlMappingAsync(_urlmappingid);
|
||||
if (urlmapping != null)
|
||||
{
|
||||
_url = urlmapping.Url;
|
||||
_mappedurl = urlmapping.MappedUrl;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading UrlMapping {UrlMappingId} {Error}", _urlmappingid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveUrlMapping()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
var urlmapping = await UrlMappingService.GetUrlMappingAsync(_urlmappingid);
|
||||
urlmapping.MappedUrl = _mappedurl;
|
||||
private async Task SaveUrlMapping()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
if (_url != _mappedurl)
|
||||
{
|
||||
try
|
||||
{
|
||||
var url = PageState.Uri.Scheme + "://" + PageState.Uri.Authority + "/";
|
||||
url = url + (!string.IsNullOrEmpty(PageState.Alias.Path) ? PageState.Alias.Path + "/" : "");
|
||||
|
||||
try
|
||||
{
|
||||
urlmapping = await UrlMappingService.UpdateUrlMappingAsync(urlmapping);
|
||||
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving UrlMapping {UrlMapping} {Error}", urlmapping, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
var urlmapping = await UrlMappingService.GetUrlMappingAsync(_urlmappingid);
|
||||
urlmapping.MappedUrl = _mappedurl.Replace(url, "");
|
||||
urlmapping = await UrlMappingService.UpdateUrlMappingAsync(urlmapping);
|
||||
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving UrlMapping {UrlMappingId} {Error}", _urlmappingid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.DuplicateUrlMapping"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
|
@ -40,10 +40,10 @@ else
|
||||
<td><ActionLink Action="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="" onclick="@(() => BrowseUrl(context.Url))">@context.Url</a>
|
||||
<a href="@Utilities.TenantUrl(PageState.Alias, context.Url)">@context.Url</a>
|
||||
@if (_mapped)
|
||||
{
|
||||
@((MarkupString)"<br />>> ")<a href="" onclick="@(() => BrowseUrl(context.MappedUrl))">@context.MappedUrl</a>
|
||||
@((MarkupString)"<br />>> ")<a href="@((context.MappedUrl.StartsWith("http") ? context.MappedUrl : Utilities.TenantUrl(PageState.Alias, context.MappedUrl)))">@context.MappedUrl</a>
|
||||
}
|
||||
</td>
|
||||
<td>@context.Requests</td>
|
||||
@ -96,11 +96,6 @@ else
|
||||
}
|
||||
}
|
||||
|
||||
private void BrowseUrl(string url)
|
||||
{
|
||||
NavigationManager.NavigateTo(url, true);
|
||||
}
|
||||
|
||||
private async Task DeleteUrlMapping(UrlMapping urlMapping)
|
||||
{
|
||||
try
|
||||
|
@ -13,7 +13,7 @@
|
||||
<Label Class="col-sm-3" For="to" HelpText="Enter the username you wish to send a message to" ResourceKey="To">To: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="to" class="form-control" @bind="@username" />
|
||||
</div> >
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="subject" HelpText="Enter the subject of the message" ResourceKey="Subject">Subject: </Label>
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
@if (PageState.User != null && photo != null)
|
||||
{
|
||||
<img src="@ImageUrl(photofileid, 400, 400, "crop")" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
|
||||
<img src="@ImageUrl(photofileid, 400, 400)" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -36,6 +36,7 @@ else
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@SharedLocalizer["Username"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td>
|
||||
@ -48,6 +49,7 @@ else
|
||||
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="Roles" />
|
||||
</td>
|
||||
<td>@context.User.DisplayName</td>
|
||||
<td>@context.User.Username</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
</TabPanel>
|
||||
@ -89,7 +91,7 @@ else
|
||||
{
|
||||
var results = allroles.Where(item => item.Role.Name == RoleNames.Registered || (item.Role.Name == RoleNames.Host && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)));
|
||||
|
||||
if (string.IsNullOrEmpty(_search))
|
||||
if (!string.IsNullOrEmpty(_search))
|
||||
{
|
||||
results = results.Where(item =>
|
||||
(
|
||||
|
@ -7,69 +7,73 @@
|
||||
@inject IStringLocalizer<Detail> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="ip" HelpText="The last recorded IP address for this visitor" ResourceKey="IP">IP Address: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="ip" class="form-control" @bind="@_ip" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="language" HelpText="The last recorded language for this visitor" ResourceKey="Language">Language: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="language" class="form-control" @bind="@_language" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="useragent" HelpText="The last recorded user agent for this visitor" ResourceKey="UserAgent">User Agent: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="useragent" class="form-control" @bind="@_useragent" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The last recorded url for this visitor" ResourceKey="Url">Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="referrer" HelpText="The last recorded referrer for this visitor" ResourceKey="Referrer">Referrer: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="referrer" class="form-control" @bind="@_referrer" readonly />
|
||||
</div>
|
||||
</div>
|
||||
@if (_user != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="user" HelpText="The last recorded user associated with this visitor" ResourceKey="User">User: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="user" class="form-control" @bind="@_user" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visits" HelpText="The total number of visits by this visitor all time" ResourceKey="Visits">Visits: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="visits" class="form-control" @bind="@_visits" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visited" HelpText="The last recorded date/time when the visitor visited the site" ResourceKey="Visited">Visited: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="visited" class="form-control" @bind="@_visited" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="created" HelpText="The first recorded date/time when this visitor visited the site" ResourceKey="Created">Created: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="created" class="form-control" @bind="@_created" readonly />
|
||||
</div>
|
||||
</div>
|
||||
@if (_initialized)
|
||||
{
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="ip" HelpText="The last recorded IP address for this visitor" ResourceKey="IP">IP Address: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="ip" class="form-control" @bind="@_ip" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="language" HelpText="The last recorded language for this visitor" ResourceKey="Language">Language: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="language" class="form-control" @bind="@_language" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="useragent" HelpText="The last recorded user agent for this visitor" ResourceKey="UserAgent">User Agent: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="useragent" class="form-control" @bind="@_useragent" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The last recorded url for this visitor" ResourceKey="Url">Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="referrer" HelpText="The last recorded referrer for this visitor" ResourceKey="Referrer">Referrer: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="referrer" class="form-control" @bind="@_referrer" readonly />
|
||||
</div>
|
||||
</div>
|
||||
@if (_user != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="user" HelpText="The last recorded user associated with this visitor" ResourceKey="User">User: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="user" class="form-control" @bind="@_user" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visits" HelpText="The total number of visits by this visitor all time" ResourceKey="Visits">Visits: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="visits" class="form-control" @bind="@_visits" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visited" HelpText="The last recorded date/time when the visitor visited the site" ResourceKey="Visited">Visited: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="visited" class="form-control" @bind="@_visited" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="created" HelpText="The first recorded date/time when this visitor visited the site" ResourceKey="Created">Created: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="created" class="form-control" @bind="@_created" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
<NavLink class="btn btn-secondary" href="@CloseUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
private int _visitorId;
|
||||
private string _ip = string.Empty;
|
||||
private string _language = string.Empty;
|
||||
@ -108,6 +112,7 @@
|
||||
_user = user.DisplayName;
|
||||
}
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -120,4 +125,16 @@
|
||||
AddModuleMessage(Localizer["Error.LoadVisitor"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string CloseUrl()
|
||||
{
|
||||
if (!PageState.QueryString.ContainsKey("type"))
|
||||
{
|
||||
return NavigateUrl();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NavigateUrl(PageState.Page.Path, "type=" + PageState.QueryString["type"] + "&days=" + PageState.QueryString["days"] + "&page=" + PageState.QueryString["page"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
@inherits ModuleBase
|
||||
@inject IVisitorService VisitorService
|
||||
@inject ISiteService SiteService
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@ -16,13 +17,13 @@ else
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-6">
|
||||
<select id="type" class="form-select custom-select" @onchange="(e => TypeChanged(e))">
|
||||
<option value="false">@Localizer["AllVisitors"]</option>
|
||||
<option value="true">@Localizer["UsersOnly"]</option>
|
||||
<select id="type" class="form-select custom-select" value="@_type" @onchange="(e => TypeChanged(e))">
|
||||
<option value="visitors">@Localizer["AllVisitors"]</option>
|
||||
<option value="users">@Localizer["UsersOnly"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<select id="type" class="form-select custom-select" @onchange="(e => DateChanged(e))">
|
||||
<select id="days" class="form-select custom-select" value="@_days" @onchange="(e => DaysChanged(e))">
|
||||
<option value="1">@Localizer["PastDay"]</option>
|
||||
<option value="7">@Localizer["PastWeek"]</option>
|
||||
<option value="30">@Localizer["PastMonth"]</option>
|
||||
@ -31,7 +32,7 @@ else
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<Pager Items="@_visitors">
|
||||
<Pager Items="@_visitors" CurrentPage="@_page.ToString()" OnPageChange="OnPageChange">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["IP"]</th>
|
||||
@ -42,7 +43,7 @@ else
|
||||
<th>@Localizer["Created"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Detail" Parameters="@($"id=" + context.VisitorId.ToString())" ResourceKey="Details" /></td>
|
||||
<td><ActionLink Action="Detail" Parameters="@($"id=" + context.VisitorId.ToString() + "&type=" + _type.ToString() + "&days=" + _days.ToString() + "&page=" + _page.ToString())" ResourceKey="Details" /></td>
|
||||
<td>@context.IPAddress</td>
|
||||
<td>
|
||||
@if (context.UserId != null)
|
||||
@ -56,18 +57,39 @@ else
|
||||
<td>@context.CreatedOn</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
</TabPanel>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visitortracking" HelpText="Specify if visitor tracking is enabled" ResourceKey="VisitorTracking">Visitor Tracking Enabled? </Label>
|
||||
<Label Class="col-sm-3" For="tracking" HelpText="Specify if visitor tracking is enabled" ResourceKey="Tracking">Tracking Enabled? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="visitortracking" class="form-select" @bind="@_visitortracking" >
|
||||
<select id="tracking" class="form-select" @bind="@_tracking" >
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="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>
|
||||
<div class="col-sm-9">
|
||||
<input id="retention" class="form-control" @bind="@_retention" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="correlation" HelpText="Indicate if new visitors to this site should be correlated based on their IP Address" ResourceKey="Correlation">Correlate Visitors? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="correlation" class="form-select" @bind="@_correlation">
|
||||
<option value="true">@SharedLocalizer["True"]</option>
|
||||
<option value="false">@SharedLocalizer["False"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||
@ -76,24 +98,46 @@ else
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool _users = false;
|
||||
private string _type = "visitors";
|
||||
private int _days = 1;
|
||||
private int _page = 1;
|
||||
private List<Visitor> _visitors;
|
||||
private string _visitortracking;
|
||||
private string _tracking;
|
||||
private string _filter = "";
|
||||
private string _retention = "";
|
||||
private string _correlation = "true";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("type"))
|
||||
{
|
||||
_type = PageState.QueryString["type"];
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("days") && int.TryParse(PageState.QueryString["days"], out int days))
|
||||
{
|
||||
_days = days;
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("page") && int.TryParse(PageState.QueryString["page"], out int page))
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
|
||||
await GetVisitors();
|
||||
_visitortracking = PageState.Site.VisitorTracking.ToString();
|
||||
|
||||
_tracking = PageState.Site.VisitorTracking.ToString();
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
|
||||
_retention = SettingService.GetSetting(settings, "VisitorRetention", "30");
|
||||
_correlation = SettingService.GetSetting(settings, "VisitorCorrelation", "true");
|
||||
}
|
||||
|
||||
private async void TypeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_users = bool.Parse(e.Value.ToString());
|
||||
_type = e.Value.ToString();
|
||||
await GetVisitors();
|
||||
StateHasChanged();
|
||||
}
|
||||
@ -103,7 +147,7 @@ else
|
||||
}
|
||||
}
|
||||
|
||||
private async void DateChanged(ChangeEventArgs e)
|
||||
private async void DaysChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -120,19 +164,26 @@ else
|
||||
private async Task GetVisitors()
|
||||
{
|
||||
_visitors = await VisitorService.GetVisitorsAsync(PageState.Site.SiteId, DateTime.UtcNow.AddDays(-_days));
|
||||
if (_users)
|
||||
if (_type == "users")
|
||||
{
|
||||
_visitors = _visitors.Where(item => item.UserId != null).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var site = PageState.Site;
|
||||
site.VisitorTracking = bool.Parse(_visitortracking);
|
||||
site.VisitorTracking = bool.Parse(_tracking);
|
||||
await SiteService.UpdateSiteAsync(site);
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
|
||||
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention, true);
|
||||
settings = SettingService.SetSetting(settings, "VisitorCorrelation", _correlation, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||
|
||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -141,4 +192,9 @@ else
|
||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPageChange(int page)
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ else
|
||||
[Parameter]
|
||||
public string HelpText { get; set; } // optional - tooltip for this label
|
||||
|
||||
private string _spanclass = "app-tooltip";
|
||||
private string _labelclass = "form-label";
|
||||
private string _spanclass;
|
||||
private string _labelclass;
|
||||
private string _helptext = string.Empty;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
@ -36,11 +36,15 @@ else
|
||||
if (!string.IsNullOrEmpty(HelpText))
|
||||
{
|
||||
_helptext = Localize(nameof(HelpText), HelpText);
|
||||
_spanclass += (!string.IsNullOrEmpty(Class)) ? " " + Class : "";
|
||||
_labelclass = "form-label";
|
||||
|
||||
var spanclass = (!string.IsNullOrEmpty(Class)) ? " " + Class : "";
|
||||
_spanclass = "app-tooltip" + spanclass;
|
||||
}
|
||||
else
|
||||
{
|
||||
_labelclass += (!string.IsNullOrEmpty(Class)) ? " " + Class : "";
|
||||
var labelclass = (!string.IsNullOrEmpty(Class)) ? " " + Class : "";
|
||||
_labelclass = "form-label" + labelclass;
|
||||
}
|
||||
|
||||
var text = Localize("Text", String.Empty);
|
||||
|
@ -13,6 +13,9 @@ namespace Oqtane.Modules.Controls
|
||||
[Parameter]
|
||||
public string ResourceKey { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string ResourceType { get; set; }
|
||||
|
||||
protected bool IsLocalizable { get; private set; }
|
||||
|
||||
protected string Localize(string name) => _localizer?[name] ?? name;
|
||||
@ -50,9 +53,14 @@ namespace Oqtane.Modules.Controls
|
||||
{
|
||||
IsLocalizable = false;
|
||||
|
||||
if (!String.IsNullOrEmpty(ResourceKey) && ModuleState?.ModuleType != null)
|
||||
if (string.IsNullOrEmpty(ResourceType))
|
||||
{
|
||||
var moduleType = Type.GetType(ModuleState.ModuleType);
|
||||
ResourceType = ModuleState?.ModuleType;
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(ResourceKey) && !string.IsNullOrEmpty(ResourceType))
|
||||
{
|
||||
var moduleType = Type.GetType(ResourceType);
|
||||
if (moduleType != null)
|
||||
{
|
||||
using (var scope = ServiceActivator.GetScope())
|
||||
|
@ -54,47 +54,58 @@
|
||||
}
|
||||
@if (Format == "Table" && Row != null)
|
||||
{
|
||||
<table class="@Class">
|
||||
<thead>
|
||||
<tr>@Header</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in ItemList)
|
||||
{
|
||||
<tr>@Row(item)</tr>
|
||||
@if (Detail != null)
|
||||
{
|
||||
<tr>@Detail(item)</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="table-responsive">
|
||||
<table class="@Class">
|
||||
<thead>
|
||||
<tr class="@RowClass">@Header</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in ItemList)
|
||||
{
|
||||
<tr class="@RowClass">@Row(item)</tr>
|
||||
@if (Detail != null)
|
||||
{
|
||||
<tr>@Detail(item)</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
@if (Format == "Grid" && Row != null)
|
||||
{
|
||||
int count = 0;
|
||||
if (ItemList != null)
|
||||
int rows = 0;
|
||||
int cols = 0;
|
||||
if (ItemList != null)
|
||||
{
|
||||
count = (int)Math.Ceiling(ItemList.Count() / (decimal)_columns) * _columns;
|
||||
if (_columns == 0)
|
||||
{
|
||||
count = ItemList.Count();
|
||||
rows = 1;
|
||||
cols = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = (int)Math.Ceiling(ItemList.Count() / (decimal)_columns) * _columns;
|
||||
rows = count / _columns;
|
||||
cols = _columns;
|
||||
}
|
||||
}
|
||||
<div class="@Class">
|
||||
@if (Header != null)
|
||||
@for (int row = 0; row < rows; row++)
|
||||
{
|
||||
<div class="row"><div class="col">@Header</div></div>
|
||||
}
|
||||
@for (int row = 0; row < (count / _columns); row++)
|
||||
{
|
||||
<div class="row">
|
||||
@for (int col = 0; col < _columns; col++)
|
||||
<div class="@RowClass">
|
||||
@for (int col = 0; col < cols; col++)
|
||||
{
|
||||
int index = (row * _columns) + col;
|
||||
if (index < ItemList.Count())
|
||||
{
|
||||
<div class="col">@Row(ItemList.ElementAt(index))</div>
|
||||
<div class="@ColumnClass">@Row(ItemList.ElementAt(index))</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="col"> </div>
|
||||
<div> </div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@ -107,8 +118,8 @@
|
||||
<li class="page-item@((_page > 1) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages)
|
||||
{
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_page > _displayPages) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@ -135,7 +146,7 @@
|
||||
<li class="page-item@((_page < _pages) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages)
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_endPage < _pages) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
@ -145,7 +156,7 @@
|
||||
<a class="page-link" @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">Page @_page of @_pages</a>
|
||||
<a class="page-link" style="white-space: nowrap;">Page @_page of @_pages</a>
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
@ -158,7 +169,7 @@
|
||||
private int _displayPages = 5;
|
||||
private int _startPage = 0;
|
||||
private int _endPage = 0;
|
||||
private int _columns = 1;
|
||||
private int _columns = 0;
|
||||
|
||||
[Parameter]
|
||||
public string Format { get; set; } // Table or Grid
|
||||
@ -167,10 +178,10 @@
|
||||
public string Toolbar { get; set; } // Top, Bottom or Both
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment Header { get; set; } = null;
|
||||
public RenderFragment Header { get; set; } = null; // only applicable to Table layouts
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment<TableItem> Row { get; set; } = null;
|
||||
public RenderFragment<TableItem> Row { get; set; } = null; // required
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment<TableItem> Detail { get; set; } = null; // only applicable to Table layouts
|
||||
@ -182,16 +193,25 @@
|
||||
public string PageSize { get; set; } // number of items to display on a page
|
||||
|
||||
[Parameter]
|
||||
public string Columns { get; set; } // only applicable to Grid layouts
|
||||
public string Columns { get; set; } // only applicable to Grid layouts - default is zero indicating use responsive behavior
|
||||
|
||||
[Parameter]
|
||||
public string CurrentPage { get; set; } // optional property to set the initial page to display
|
||||
public string CurrentPage { get; set; } // sets the initial page to display
|
||||
|
||||
[Parameter]
|
||||
public string DisplayPages { get; set; } // maximum number of page numbers to display for user selection
|
||||
|
||||
[Parameter]
|
||||
public string Class { get; set; }
|
||||
public string Class { get; set; } // class for the containing element - ie. <table> for Table or <div> for Grid
|
||||
|
||||
[Parameter]
|
||||
public string RowClass { get; set; } // class for row element - ie. <tr> for Table or <div> for Grid
|
||||
|
||||
[Parameter]
|
||||
public string ColumnClass { get; set; } // class for column element - only applicable to Grid format
|
||||
|
||||
[Parameter]
|
||||
public Action<int> OnPageChange { get; set; } // a method to be executed in the calling component when the page changes
|
||||
|
||||
private IEnumerable<TableItem> ItemList { get; set; }
|
||||
|
||||
@ -215,11 +235,35 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
Class = "container-fluid px-0";
|
||||
Class = "container-fluid";
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(PageSize))
|
||||
if (string.IsNullOrEmpty(RowClass))
|
||||
{
|
||||
if (Format == "Table")
|
||||
{
|
||||
RowClass = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
RowClass = "row";
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(ColumnClass))
|
||||
{
|
||||
if (Format == "Table")
|
||||
{
|
||||
ColumnClass = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
ColumnClass = "col";
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(PageSize))
|
||||
{
|
||||
_maxItems = int.Parse(PageSize);
|
||||
}
|
||||
@ -266,6 +310,7 @@
|
||||
{
|
||||
_endPage = _pages;
|
||||
}
|
||||
OnPageChange?.Invoke(_page);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
@ -100,160 +100,172 @@
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _permissionnames = string.Empty;
|
||||
private List<Role> _roles;
|
||||
private List<PermissionString> _permissions;
|
||||
private List<User> _users = new List<User>();
|
||||
private string _username = string.Empty;
|
||||
private string _message = string.Empty;
|
||||
private string _permissionnames = string.Empty;
|
||||
private List<Role> _roles;
|
||||
private List<PermissionString> _permissions;
|
||||
private List<User> _users = new List<User>();
|
||||
private string _username = string.Empty;
|
||||
private string _message = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string EntityName { get; set; }
|
||||
[Parameter]
|
||||
public string EntityName { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string PermissionNames { get; set; }
|
||||
[Parameter]
|
||||
public string PermissionNames { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Permissions { get; set; }
|
||||
[Parameter]
|
||||
public string Permissions { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (string.IsNullOrEmpty(PermissionNames))
|
||||
{
|
||||
_permissionnames = Shared.PermissionNames.View + "," + Shared.PermissionNames.Edit;
|
||||
}
|
||||
else
|
||||
{
|
||||
_permissionnames = PermissionNames;
|
||||
}
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (string.IsNullOrEmpty(PermissionNames))
|
||||
{
|
||||
_permissionnames = Shared.PermissionNames.View + "," + Shared.PermissionNames.Edit;
|
||||
}
|
||||
else
|
||||
{
|
||||
_permissionnames = PermissionNames;
|
||||
}
|
||||
|
||||
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId);
|
||||
_roles.Insert(0, new Role { Name = RoleNames.Everyone });
|
||||
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId);
|
||||
_roles.Insert(0, new Role { Name = RoleNames.Everyone });
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_roles.Add(new Role { Name = RoleNames.Host });
|
||||
}
|
||||
|
||||
_permissions = new List<PermissionString>();
|
||||
_permissions = new List<PermissionString>();
|
||||
|
||||
foreach (string permissionname in _permissionnames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
// initialize with admin role
|
||||
_permissions.Add(new PermissionString { PermissionName = permissionname, Permissions = RoleNames.Admin });
|
||||
}
|
||||
foreach (string permissionname in _permissionnames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
// initialize with admin role
|
||||
_permissions.Add(new PermissionString { PermissionName = permissionname, Permissions = RoleNames.Admin });
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Permissions))
|
||||
{
|
||||
// populate permissions
|
||||
foreach (PermissionString permissionstring in UserSecurity.GetPermissionStrings(Permissions))
|
||||
{
|
||||
if (_permissions.Find(item => item.PermissionName == permissionstring.PermissionName) != null)
|
||||
{
|
||||
_permissions[_permissions.FindIndex(item => item.PermissionName == permissionstring.PermissionName)].Permissions = permissionstring.Permissions;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Permissions))
|
||||
{
|
||||
// populate permissions
|
||||
foreach (PermissionString permissionstring in UserSecurity.GetPermissionStrings(Permissions))
|
||||
{
|
||||
if (_permissions.Find(item => item.PermissionName == permissionstring.PermissionName) != null)
|
||||
{
|
||||
_permissions[_permissions.FindIndex(item => item.PermissionName == permissionstring.PermissionName)].Permissions = permissionstring.Permissions;
|
||||
}
|
||||
|
||||
if (permissionstring.Permissions.Contains("["))
|
||||
{
|
||||
foreach (string user in permissionstring.Permissions.Split(new char[] { '[' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (user.Contains("]"))
|
||||
{
|
||||
var userid = int.Parse(user.Substring(0, user.IndexOf("]")));
|
||||
if (_users.Where(item => item.UserId == userid).FirstOrDefault() == null)
|
||||
{
|
||||
_users.Add(await UserService.GetUserAsync(userid, ModuleState.SiteId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (permissionstring.Permissions.Contains("["))
|
||||
{
|
||||
foreach (string user in permissionstring.Permissions.Split(new char[] { '[' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (user.Contains("]"))
|
||||
{
|
||||
var userid = int.Parse(user.Substring(0, user.IndexOf("]")));
|
||||
if (_users.Where(item => item.UserId == userid).FirstOrDefault() == null)
|
||||
{
|
||||
_users.Add(await UserService.GetUserAsync(userid, ModuleState.SiteId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool? GetPermissionValue(string permissions, string securityKey)
|
||||
{
|
||||
if ((";" + permissions + ";").Contains(";" + "!" + securityKey + ";"))
|
||||
{
|
||||
return false; // deny permission
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((";" + permissions + ";").Contains(";" + securityKey + ";"))
|
||||
{
|
||||
return true; // grant permission
|
||||
}
|
||||
else
|
||||
{
|
||||
return null; // not specified
|
||||
}
|
||||
}
|
||||
}
|
||||
private bool? GetPermissionValue(string permissions, string securityKey)
|
||||
{
|
||||
if ((";" + permissions + ";").Contains(";" + "!" + securityKey + ";"))
|
||||
{
|
||||
return false; // deny permission
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((";" + permissions + ";").Contains(";" + securityKey + ";"))
|
||||
{
|
||||
return true; // grant permission
|
||||
}
|
||||
else
|
||||
{
|
||||
return null; // not specified
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool GetPermissionDisabled(string roleName)
|
||||
=> roleName == RoleNames.Admin
|
||||
? true
|
||||
: false;
|
||||
private bool GetPermissionDisabled(string roleName)
|
||||
=> (roleName == RoleNames.Admin && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) ? true : false;
|
||||
|
||||
private async Task AddUser()
|
||||
{
|
||||
if (_users.Where(item => item.Username == _username).FirstOrDefault() == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await UserService.GetUserAsync(_username, ModuleState.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
_users.Add(user);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
_message = Localizer["Message.Username.DontExist"];
|
||||
}
|
||||
}
|
||||
private async Task AddUser()
|
||||
{
|
||||
if (_users.Where(item => item.Username == _username).FirstOrDefault() == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await UserService.GetUserAsync(_username, ModuleState.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
_users.Add(user);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
_message = Localizer["Message.Username.DontExist"];
|
||||
}
|
||||
}
|
||||
|
||||
_username = string.Empty;
|
||||
}
|
||||
_username = string.Empty;
|
||||
}
|
||||
|
||||
private void PermissionChanged(bool? value, string permissionName, string securityId)
|
||||
{
|
||||
var selected = value;
|
||||
var permission = _permissions.Find(item => item.PermissionName == permissionName);
|
||||
if (permission != null)
|
||||
{
|
||||
var ids = permission.Permissions.Split(';').ToList();
|
||||
private void PermissionChanged(bool? value, string permissionName, string securityId)
|
||||
{
|
||||
var selected = value;
|
||||
var permission = _permissions.Find(item => item.PermissionName == permissionName);
|
||||
if (permission != null)
|
||||
{
|
||||
var ids = permission.Permissions.Split(';').ToList();
|
||||
|
||||
ids.Remove(securityId); // remove grant permission
|
||||
ids.Remove("!" + securityId); // remove deny permission
|
||||
ids.Remove(securityId); // remove grant permission
|
||||
ids.Remove("!" + securityId); // remove deny permission
|
||||
|
||||
switch (selected)
|
||||
{
|
||||
case true:
|
||||
ids.Add(securityId); // add grant permission
|
||||
break;
|
||||
case false:
|
||||
ids.Add("!" + securityId); // add deny permission
|
||||
break;
|
||||
case null:
|
||||
break; // permission not specified
|
||||
}
|
||||
switch (selected)
|
||||
{
|
||||
case true:
|
||||
ids.Add(securityId); // add grant permission
|
||||
break;
|
||||
case false:
|
||||
ids.Add("!" + securityId); // add deny permission
|
||||
break;
|
||||
case null:
|
||||
break; // permission not specified
|
||||
}
|
||||
|
||||
_permissions[_permissions.FindIndex(item => item.PermissionName == permissionName)].Permissions = string.Join(";", ids.ToArray());
|
||||
}
|
||||
}
|
||||
_permissions[_permissions.FindIndex(item => item.PermissionName == permissionName)].Permissions = string.Join(";", ids.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public string GetPermissions()
|
||||
{
|
||||
ValidatePermissions();
|
||||
return UserSecurity.SetPermissionStrings(_permissions);
|
||||
}
|
||||
public string GetPermissions()
|
||||
{
|
||||
ValidatePermissions();
|
||||
return UserSecurity.SetPermissionStrings(_permissions);
|
||||
}
|
||||
|
||||
private void ValidatePermissions()
|
||||
{
|
||||
PermissionString permission;
|
||||
for (int i = 0; i < _permissions.Count; i++)
|
||||
{
|
||||
permission = _permissions[i];
|
||||
List<string> ids = permission.Permissions.Split(';').ToList();
|
||||
ids.Remove("!" + RoleNames.Everyone); // remove deny all users
|
||||
ids.Remove("!" + RoleNames.Registered); // remove deny registered users
|
||||
permission.Permissions = string.Join(";", ids.ToArray());
|
||||
private void ValidatePermissions()
|
||||
{
|
||||
PermissionString permission;
|
||||
for (int i = 0; i < _permissions.Count; i++)
|
||||
{
|
||||
permission = _permissions[i];
|
||||
List<string> ids = permission.Permissions.Split(';').ToList();
|
||||
ids.Remove("!" + RoleNames.Everyone); // remove deny all users
|
||||
ids.Remove("!" + RoleNames.Registered); // remove deny registered users
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
ids.Remove("!" + RoleNames.Admin); // remove deny administrators
|
||||
ids.Remove("!" + RoleNames.Host); // remove deny host users
|
||||
if (!ids.Contains(RoleNames.Host) && !ids.Contains(RoleNames.Admin))
|
||||
{
|
||||
// add administrators role if host user role is not assigned
|
||||
ids.Add(RoleNames.Admin);
|
||||
}
|
||||
}
|
||||
permission.Permissions = string.Join(";", ids.ToArray());
|
||||
_permissions[i] = permission;
|
||||
}
|
||||
}
|
||||
|
@ -71,11 +71,11 @@
|
||||
</div>
|
||||
@if (ReadOnly)
|
||||
{
|
||||
<textarea class="form-control" placeholder="@Placeholder" @bind="@_content" rows="10" readonly></textarea>
|
||||
<textarea class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10" readonly></textarea>
|
||||
}
|
||||
else
|
||||
{
|
||||
<textarea class="form-control" placeholder="@Placeholder" @bind="@_content" rows="10"></textarea>
|
||||
<textarea class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10"></textarea>
|
||||
}
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
@ -83,110 +83,121 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private ElementReference _editorElement;
|
||||
private ElementReference _toolBar;
|
||||
private bool _filemanagervisible = false;
|
||||
private FileManager _fileManager;
|
||||
private string _content = string.Empty;
|
||||
private string _original = string.Empty;
|
||||
private string _message = string.Empty;
|
||||
private ElementReference _editorElement;
|
||||
private ElementReference _toolBar;
|
||||
private bool _filemanagervisible = false;
|
||||
private FileManager _fileManager;
|
||||
private string _richhtml = string.Empty;
|
||||
private string _originalrichhtml = string.Empty;
|
||||
private string _rawhtml = string.Empty;
|
||||
private string _originalrawhtml = string.Empty;
|
||||
private string _message = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string Content { get; set; }
|
||||
[Parameter]
|
||||
public string Content { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool ReadOnly { get; set; } = false;
|
||||
[Parameter]
|
||||
public bool ReadOnly { get; set; } = false;
|
||||
|
||||
[Parameter]
|
||||
public string Placeholder { get; set; } = "Enter Your Content...";
|
||||
[Parameter]
|
||||
public string Placeholder { get; set; } = "Enter Your Content...";
|
||||
|
||||
// parameters only applicable to rich text editor
|
||||
[Parameter]
|
||||
public RenderFragment ToolbarContent { get; set; }
|
||||
// parameters only applicable to rich text editor
|
||||
[Parameter]
|
||||
public RenderFragment ToolbarContent { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string Theme { get; set; } = "snow";
|
||||
[Parameter]
|
||||
public string Theme { get; set; } = "snow";
|
||||
|
||||
[Parameter]
|
||||
public string DebugLevel { get; set; } = "info";
|
||||
[Parameter]
|
||||
public string DebugLevel { get; set; } = "info";
|
||||
|
||||
[Parameter]
|
||||
public bool AllowFileManagement { get; set; } = true;
|
||||
[Parameter]
|
||||
public bool AllowFileManagement { get; set; } = true;
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill1.3.7.min.js" },
|
||||
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" }
|
||||
};
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_content = Content; // raw HTML
|
||||
}
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_richhtml = Content;
|
||||
_rawhtml = Content;
|
||||
_originalrawhtml = _rawhtml; // preserve for comparison later
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
|
||||
await interop.CreateEditor(
|
||||
_editorElement,
|
||||
_toolBar,
|
||||
ReadOnly,
|
||||
Placeholder,
|
||||
Theme,
|
||||
DebugLevel);
|
||||
}
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
|
||||
await interop.LoadEditorContent(_editorElement, Content);
|
||||
if (firstRender)
|
||||
{
|
||||
await interop.CreateEditor(
|
||||
_editorElement,
|
||||
_toolBar,
|
||||
ReadOnly,
|
||||
Placeholder,
|
||||
Theme,
|
||||
DebugLevel);
|
||||
|
||||
_content = Content; // raw HTML
|
||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
||||
|
||||
// preserve a copy of the rich text content ( Quill sanitizes content so we need to retrieve it from the editor )
|
||||
_original = await interop.GetHtml(_editorElement);
|
||||
// preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor)
|
||||
_originalrichhtml = await interop.GetHtml(_editorElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public void CloseFileManager()
|
||||
{
|
||||
_filemanagervisible = false;
|
||||
_message = string.Empty;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public void CloseFileManager()
|
||||
{
|
||||
_filemanagervisible = false;
|
||||
_message = string.Empty;
|
||||
StateHasChanged();
|
||||
}
|
||||
public void RefreshRichText()
|
||||
{
|
||||
_richhtml = _rawhtml;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public async Task RefreshRichText()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
await interop.LoadEditorContent(_editorElement, _content);
|
||||
}
|
||||
public async Task RefreshRawHtml()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
_rawhtml = await interop.GetHtml(_editorElement);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public async Task RefreshRawHtml()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
_content = await interop.GetHtml(_editorElement);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public async Task<string> GetHtml()
|
||||
{
|
||||
// get rich text content
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
string content = await interop.GetHtml(_editorElement);
|
||||
|
||||
if (_original != content)
|
||||
{
|
||||
// rich text content has changed - return it
|
||||
return content;
|
||||
}
|
||||
else
|
||||
{
|
||||
// return raw html content
|
||||
return _content;
|
||||
}
|
||||
public async Task<string> GetHtml()
|
||||
{
|
||||
// evaluate raw html content as first priority
|
||||
if (_rawhtml != _originalrawhtml)
|
||||
{
|
||||
return _rawhtml;
|
||||
}
|
||||
else
|
||||
{
|
||||
// return rich text content if it has changed
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
var richhtml = await interop.GetHtml(_editorElement);
|
||||
if (richhtml != _originalrichhtml)
|
||||
{
|
||||
return richhtml;
|
||||
}
|
||||
else
|
||||
{
|
||||
// return original raw html content
|
||||
return _originalrawhtml;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InsertImage()
|
||||
@ -212,23 +223,4 @@
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
// other rich text editor methods which can be used by developers
|
||||
public async Task<string> GetText()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
return await interop.GetText(_editorElement);
|
||||
}
|
||||
|
||||
public async Task<string> GetContent()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
return await interop.GetContent(_editorElement);
|
||||
}
|
||||
|
||||
public async Task EnableEditor(bool mode)
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
await interop.EnableEditor(_editorElement, mode);
|
||||
}
|
||||
}
|
||||
|
@ -9,95 +9,186 @@
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_content != null)
|
||||
{
|
||||
<RichTextEditor Content="@_content" AllowFileManagement="@_allowfilemanagement" @ref="@RichTextEditorHtml"></RichTextEditor>
|
||||
<button type="button" class="btn btn-success" @onclick="SaveContent">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
@if (!string.IsNullOrEmpty(_content))
|
||||
{
|
||||
<br />
|
||||
<br />
|
||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
||||
}
|
||||
}
|
||||
<TabStrip>
|
||||
<TabPanel Name="Edit" Heading="Edit" ResourceKey="Edit">
|
||||
@if (_content != null)
|
||||
{
|
||||
<RichTextEditor Content="@_content" AllowFileManagement="@_allowfilemanagement" @ref="@RichTextEditorHtml"></RichTextEditor>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveContent">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
@if (!string.IsNullOrEmpty(_content))
|
||||
{
|
||||
<br />
|
||||
<br />
|
||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
||||
}
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Versions" Heading="Versions" ResourceKey="Versions">
|
||||
<Pager Items="@_htmltexts">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["CreatedOn"]</th>
|
||||
<th>@SharedLocalizer["CreatedBy"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="View" Security="SecurityAccessLevel.Edit" OnClick="@(async () => await View(context))" ResourceKey="View" /></td>
|
||||
<td><ActionDialog Header="Restore Version" Message="@string.Format(Localizer["Confirm.Restore"], context.CreatedOn)" Action="Restore" Security="SecurityAccessLevel.Edit" Class="btn btn-success" OnClick="@(async () => await Restore(context))" ResourceKey="Restore" /></td>
|
||||
<td><ActionDialog Header="Delete Version" Message="@string.Format(Localizer["Confirm.Delete"], context.CreatedOn)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" ResourceKey="Delete" /></td>
|
||||
<td>@context.CreatedOn</td>
|
||||
<td>@context.CreatedBy</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
@((MarkupString)_view)
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
|
||||
@code {
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
|
||||
public override string Title => "Edit Html/Text";
|
||||
public override string Title => "Edit Html/Text";
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.7.bubble.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.7.snow.css" }
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.bubble.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" }
|
||||
};
|
||||
|
||||
private RichTextEditor RichTextEditorHtml;
|
||||
private bool _allowfilemanagement;
|
||||
private string _content = null;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private RichTextEditor RichTextEditorHtml;
|
||||
private bool _allowfilemanagement;
|
||||
private string _content = null;
|
||||
private string _createdby;
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private List<Models.HtmlText> _htmltexts;
|
||||
private string _view = "";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
|
||||
await LoadContent();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
_content = htmltext.Content;
|
||||
_content = Utilities.FormatContent(_content, PageState.Alias, "render");
|
||||
_createdby = htmltext.CreatedBy;
|
||||
_createdon = htmltext.CreatedOn;
|
||||
_modifiedby = htmltext.ModifiedBy;
|
||||
_modifiedon = htmltext.ModifiedOn;
|
||||
}
|
||||
else
|
||||
{
|
||||
_content = string.Empty;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private async Task LoadContent()
|
||||
{
|
||||
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
_content = htmltext.Content;
|
||||
_content = Utilities.FormatContent(_content, PageState.Alias, "render");
|
||||
_createdby = htmltext.CreatedBy;
|
||||
_createdon = htmltext.CreatedOn;
|
||||
_modifiedby = htmltext.ModifiedBy;
|
||||
_modifiedon = htmltext.ModifiedOn;
|
||||
}
|
||||
else
|
||||
{
|
||||
_content = string.Empty;
|
||||
}
|
||||
|
||||
private async Task SaveContent()
|
||||
{
|
||||
string content = await RichTextEditorHtml.GetHtml();
|
||||
content = Utilities.FormatContent(content, PageState.Alias, "save");
|
||||
_htmltexts = await HtmlTextService.GetHtmlTextsAsync(ModuleState.ModuleId);
|
||||
_htmltexts = _htmltexts.OrderByDescending(item => item.CreatedOn).ToList();
|
||||
|
||||
try
|
||||
{
|
||||
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
htmltext.Content = content;
|
||||
await HtmlTextService.UpdateHtmlTextAsync(htmltext);
|
||||
}
|
||||
else
|
||||
{
|
||||
htmltext = new HtmlText();
|
||||
htmltext.ModuleId = ModuleState.ModuleId;
|
||||
htmltext.Content = content;
|
||||
await HtmlTextService.AddHtmlTextAsync(htmltext);
|
||||
}
|
||||
_view = "";
|
||||
}
|
||||
|
||||
await logger.LogInformation("Content Saved {HtmlText}", htmltext);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Save"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private async Task SaveContent()
|
||||
{
|
||||
string content = await RichTextEditorHtml.GetHtml();
|
||||
content = Utilities.FormatContent(content, PageState.Alias, "save");
|
||||
|
||||
try
|
||||
{
|
||||
var htmltext = new HtmlText();
|
||||
htmltext.ModuleId = ModuleState.ModuleId;
|
||||
htmltext.Content = content;
|
||||
await HtmlTextService.AddHtmlTextAsync(htmltext);
|
||||
|
||||
await logger.LogInformation("Content Saved {HtmlText}", htmltext);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Save"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task View(Models.HtmlText htmltext)
|
||||
{
|
||||
try
|
||||
{
|
||||
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
_view = htmltext.Content;
|
||||
_view = Utilities.FormatContent(_view, PageState.Alias, "render");
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Viewing Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.View"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Restore(Models.HtmlText htmltext)
|
||||
{
|
||||
try
|
||||
{
|
||||
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
var content = htmltext.Content;
|
||||
htmltext = new HtmlText();
|
||||
htmltext.ModuleId = ModuleState.ModuleId;
|
||||
htmltext.Content = content;
|
||||
await HtmlTextService.AddHtmlTextAsync(htmltext);
|
||||
await logger.LogInformation("Content Restored {HtmlText}", htmltext);
|
||||
AddModuleMessage(Localizer["Message.Content.Restored"], MessageType.Success);
|
||||
await LoadContent();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Restoring Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Restore"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Delete(Models.HtmlText htmltext)
|
||||
{
|
||||
try
|
||||
{
|
||||
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
await HtmlTextService.DeleteHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
|
||||
await logger.LogInformation("Content Deleted {HtmlText}", htmltext);
|
||||
AddModuleMessage(Localizer["Message.Content.Deleted"], MessageType.Success);
|
||||
await LoadContent();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Documentation;
|
||||
@ -13,24 +15,29 @@ namespace Oqtane.Modules.HtmlText.Services
|
||||
|
||||
private string ApiUrl => CreateApiUrl("HtmlText");
|
||||
|
||||
public async Task<List<Models.HtmlText>> GetHtmlTextsAsync(int moduleId)
|
||||
{
|
||||
return await GetJsonAsync<List<Models.HtmlText>>(CreateAuthorizationPolicyUrl($"{ApiUrl}?moduleid={moduleId}", EntityNames.Module, moduleId));
|
||||
}
|
||||
|
||||
public async Task<Models.HtmlText> GetHtmlTextAsync(int moduleId)
|
||||
{
|
||||
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
|
||||
}
|
||||
|
||||
public async Task<Models.HtmlText> GetHtmlTextAsync(int htmlTextId, int moduleId)
|
||||
{
|
||||
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId));
|
||||
}
|
||||
|
||||
public async Task AddHtmlTextAsync(Models.HtmlText htmlText)
|
||||
{
|
||||
await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", EntityNames.Module, htmlText.ModuleId), htmlText);
|
||||
}
|
||||
|
||||
public async Task UpdateHtmlTextAsync(Models.HtmlText htmlText)
|
||||
public async Task DeleteHtmlTextAsync(int htmlTextId, int moduleId)
|
||||
{
|
||||
await PutJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlText.HtmlTextId}", EntityNames.Module, htmlText.ModuleId), htmlText);
|
||||
}
|
||||
|
||||
public async Task DeleteHtmlTextAsync(int moduleId)
|
||||
{
|
||||
await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
|
||||
await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Modules.HtmlText.Models;
|
||||
|
||||
namespace Oqtane.Modules.HtmlText.Services
|
||||
{
|
||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||
public interface IHtmlTextService
|
||||
{
|
||||
Task<Models.HtmlText> GetHtmlTextAsync(int ModuleId);
|
||||
Task<List<Models.HtmlText>> GetHtmlTextsAsync(int moduleId);
|
||||
|
||||
Task<Models.HtmlText> GetHtmlTextAsync(int moduleId);
|
||||
|
||||
Task<Models.HtmlText> GetHtmlTextAsync(int htmlTextId, int moduleId);
|
||||
|
||||
Task AddHtmlTextAsync(Models.HtmlText htmltext);
|
||||
|
||||
Task UpdateHtmlTextAsync(Models.HtmlText htmltext);
|
||||
|
||||
Task DeleteHtmlTextAsync(int ModuleId);
|
||||
Task DeleteHtmlTextAsync(int htmlTextId, int moduleId);
|
||||
}
|
||||
}
|
||||
|
@ -5,44 +5,45 @@
|
||||
@inject IStringLocalizer<Settings> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="files" ResourceKey="Allow File Management" HelpText="Specify If Editors Can Upload and Select Files">Allow File Management: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="files" class="form-select" @bind="@_allowfilemanagement">
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="files" ResourceKey="AllowFileManagement" ResourceType="@resourceType" HelpText="Specify If Editors Can Upload and Select Files">Allow File Management: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="files" class="form-select" @bind="@_allowfilemanagement">
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private string _allowfilemanagement;
|
||||
@code {
|
||||
private string resourceType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client"; // for localization
|
||||
private string _allowfilemanagement;
|
||||
|
||||
protected override void OnInitialized()
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
_allowfilemanagement = SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
_allowfilemanagement = SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true");
|
||||
}
|
||||
|
||||
public async Task UpdateSettings()
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = ModuleState.Settings;
|
||||
settings = SettingService.SetSetting(settings, "AllowFileManagement", _allowfilemanagement);
|
||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||
settings = SettingService.SetSetting(settings, "AllowFileManagement", _allowfilemanagement);
|
||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,14 +134,19 @@ namespace Oqtane.Modules
|
||||
return Utilities.ContentUrl(PageState.Alias, fileid, asAttachment);
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode)
|
||||
public string ImageUrl(int fileid, int width, int height)
|
||||
{
|
||||
return ImageUrl(fileid, width, height, mode, 0);
|
||||
return ImageUrl(fileid, width, height, "");
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode, int rotate)
|
||||
public string ImageUrl(int fileid, int width, int height, string mode)
|
||||
{
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, rotate);
|
||||
return ImageUrl(fileid, width, height, mode, "", "", 0, false);
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode, string position, string background, int rotate, bool recreate)
|
||||
{
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, position, background, rotate, recreate);
|
||||
}
|
||||
|
||||
public virtual Dictionary<string, string> GetUrlParameters(string parametersTemplate = "")
|
||||
|
@ -5,7 +5,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.0.3</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -13,7 +13,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
|
@ -186,4 +186,10 @@
|
||||
<data name="NextExecution.Text" xml:space="preserve">
|
||||
<value>Next Execution: </value>
|
||||
</data>
|
||||
<data name="Week(s)" xml:space="preserve">
|
||||
<value>Week(s)</value>
|
||||
</data>
|
||||
<data name="Once" xml:space="preserve">
|
||||
<value>Execute Once</value>
|
||||
</data>
|
||||
</root>
|
@ -133,19 +133,16 @@
|
||||
<value>Every</value>
|
||||
</data>
|
||||
<data name="Minute" xml:space="preserve">
|
||||
<value>Minute</value>
|
||||
<value>Minute(s)</value>
|
||||
</data>
|
||||
<data name="Hour" xml:space="preserve">
|
||||
<value>Hour</value>
|
||||
<value>Hour(s)</value>
|
||||
</data>
|
||||
<data name="Day" xml:space="preserve">
|
||||
<value>Day</value>
|
||||
<value>Day(s)</value>
|
||||
</data>
|
||||
<data name="Month" xml:space="preserve">
|
||||
<value>Month</value>
|
||||
</data>
|
||||
<data name="s" xml:space="preserve">
|
||||
<value>s</value>
|
||||
<value>Month(s)</value>
|
||||
</data>
|
||||
<data name="Error.Job.Delete" xml:space="preserve">
|
||||
<value>Error Deleting Job</value>
|
||||
@ -177,4 +174,22 @@
|
||||
<data name="JobLog.Text" xml:space="preserve">
|
||||
<value>Log</value>
|
||||
</data>
|
||||
<data name="Error.Job.Start" xml:space="preserve">
|
||||
<value>An error occurred when starting the job</value>
|
||||
</data>
|
||||
<data name="Error.Job.Stop" xml:space="preserve">
|
||||
<value>An error occurred when stopping the job</value>
|
||||
</data>
|
||||
<data name="Message.Job.Start" xml:space="preserve">
|
||||
<value>The process responsible for executing this job has been started. The next execution will be based on the schedule criteria for the job.</value>
|
||||
</data>
|
||||
<data name="Message.Job.Stop" xml:space="preserve">
|
||||
<value>The process responsible for executing this job has been stopped. In order to restart the process you will need to use the Start button or restart the application.</value>
|
||||
</data>
|
||||
<data name="Week" xml:space="preserve">
|
||||
<value>Week(s)</value>
|
||||
</data>
|
||||
<data name="Once" xml:space="preserve">
|
||||
<value>Execute Once</value>
|
||||
</data>
|
||||
</root>
|
@ -138,4 +138,13 @@
|
||||
<data name="Info.SignedIn" xml:space="preserve">
|
||||
<value>You Are Already Signed In</value>
|
||||
</data>
|
||||
<data name="Message.ForgotPassword" xml:space="preserve">
|
||||
<value>Please Enter The Username Related To Your Account And Then Select The Forgot Password Option Again</value>
|
||||
</data>
|
||||
<data name="Message.ForgotUser" xml:space="preserve">
|
||||
<value>Please Check The Email Address Associated To Your User Account For A Password Reset Notification</value>
|
||||
</data>
|
||||
<data name="Message.UserDoesNotExist" xml:space="preserve">
|
||||
<value>User Does Not Exist</value>
|
||||
</data>
|
||||
</root>
|
@ -192,4 +192,22 @@
|
||||
<data name="LogDetails.Text" xml:space="preserve">
|
||||
<value>Details</value>
|
||||
</data>
|
||||
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Error Saving Settings</value>
|
||||
</data>
|
||||
<data name="Events.Heading" xml:space="preserve">
|
||||
<value>Events</value>
|
||||
</data>
|
||||
<data name="Retention.HelpText" xml:space="preserve">
|
||||
<value>Number of days of events to retain</value>
|
||||
</data>
|
||||
<data name="Retention.Text" xml:space="preserve">
|
||||
<value>Retention (Days):</value>
|
||||
</data>
|
||||
<data name="Settings.Heading" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Success.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Settings Saved Successfully</value>
|
||||
</data>
|
||||
</root>
|
@ -231,4 +231,10 @@
|
||||
<data name="Message.Page.Deleted" xml:space="preserve">
|
||||
<value>A page with path {0} already exists for the selected parent page in the Recycle Bin. Either recover the page or remove from the Recycle Bin and create it again.</value>
|
||||
</data>
|
||||
<data name="Meta.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter meta tags (in exactly the form you want them to be included in the page output).</value>
|
||||
</data>
|
||||
<data name="Meta.Text" xml:space="preserve">
|
||||
<value>Meta:</value>
|
||||
</data>
|
||||
</root>
|
@ -258,13 +258,16 @@
|
||||
<data name="ThemeSettings.Heading" xml:space="preserve">
|
||||
<value>Theme Settings</value>
|
||||
</data>
|
||||
<data name="Appearance.Hea" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Clickable.HelpText" xml:space="preserve">
|
||||
<value>Select whether the link in the site navigation is enabled or disabled</value>
|
||||
</data>
|
||||
<data name="Clickable.Text" xml:space="preserve">
|
||||
<value>Clickable?</value>
|
||||
</data>
|
||||
<data name="Meta.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter meta tags (in exactly the form you want them to be included in the page output).</value>
|
||||
</data>
|
||||
<data name="Meta.Text" xml:space="preserve">
|
||||
<value>Meta:</value>
|
||||
</data>
|
||||
</root>
|
@ -117,22 +117,37 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Password.Confirm" xml:space="preserve">
|
||||
<value>Confirm Password:</value>
|
||||
</data>
|
||||
<data name="Message.Password.NoMatch" xml:space="preserve">
|
||||
<value>Passwords Entered Do Not Match</value>
|
||||
</data>
|
||||
<data name="Message.Required.UserInfo" xml:space="preserve">
|
||||
<value>You Must Provide A Username, Password, and Email Address</value>
|
||||
<value>You Must Provide The Password And Confirmation</value>
|
||||
</data>
|
||||
<data name="Password.Reset" xml:space="preserve">
|
||||
<value>Reset Password</value>
|
||||
</data>
|
||||
<data name="Error.Password.ResetInfo" xml:space="preserve">
|
||||
<value>Error Resetting User Password. Please Ensure Password Meets Complexity Requirements.</value>
|
||||
<value>Error Resetting User Password. Please Ensure The Request To Reset Your Password Was Made Within The Past 24 Hours And The New Password Meets The Complexity Requirements.</value>
|
||||
</data>
|
||||
<data name="Error.Password.Reset" xml:space="preserve">
|
||||
<value>Error Resetting User Password</value>
|
||||
</data>
|
||||
<data name="Confirm.Text" xml:space="preserve">
|
||||
<value>Confirm:</value>
|
||||
</data>
|
||||
<data name="Conform.HelpText" xml:space="preserve">
|
||||
<value>Enter the password again. It must exactly match the password entered above.</value>
|
||||
</data>
|
||||
<data name="Password.HelpText" xml:space="preserve">
|
||||
<value>The new password. It must satisfy complexity rules for the site.</value>
|
||||
</data>
|
||||
<data name="Password.Text" xml:space="preserve">
|
||||
<value>Password:</value>
|
||||
</data>
|
||||
<data name="Username.HelpText" xml:space="preserve">
|
||||
<value>Your username will be populated from the link you received in the password reset notification</value>
|
||||
</data>
|
||||
<data name="Username.Text" xml:space="preserve">
|
||||
<value>Username:</value>
|
||||
</data>
|
||||
</root>
|
@ -129,9 +129,6 @@
|
||||
<data name="DefaultContainer.Text" xml:space="preserve">
|
||||
<value>Default Container: </value>
|
||||
</data>
|
||||
<data name="Appearance.Heading" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
</data>
|
||||
<data name="DefaultAdminContainer" xml:space="preserve">
|
||||
<value>Default Admin Container</value>
|
||||
</data>
|
||||
@ -145,7 +142,7 @@
|
||||
<value>Site Settings Saved</value>
|
||||
</data>
|
||||
<data name="Message.Aliases.Taken" xml:space="preserve">
|
||||
<value>An Alias Specified Has Already Been Used For Another Site</value>
|
||||
<value>The Default Alias Has Not Been Specified Or An Alias Was Specified That Has Already Been Used For Another Site</value>
|
||||
</data>
|
||||
<data name="Message.Required.SiteName" xml:space="preserve">
|
||||
<value>You Must Provide A Site Name, Alias, And Default Theme/Container</value>
|
||||
@ -223,7 +220,7 @@
|
||||
<value>Aliases: </value>
|
||||
</data>
|
||||
<data name="IsDeleted.Text" xml:space="preserve">
|
||||
<value>Is Deleted? </value>
|
||||
<value>Deleted? </value>
|
||||
</data>
|
||||
<data name="Logo.Text" xml:space="preserve">
|
||||
<value>Logo: </value>
|
||||
@ -318,4 +315,13 @@
|
||||
<data name="DeleteSite.Text" xml:space="preserve">
|
||||
<value>Delete Site</value>
|
||||
</data>
|
||||
<data name="DefaultAlias.HelpText" xml:space="preserve">
|
||||
<value>The default alias for the site. Requests for non-default aliases will be redirected to the default alias.</value>
|
||||
</data>
|
||||
<data name="DefaultAlias.Text" xml:space="preserve">
|
||||
<value>Default Alias: </value>
|
||||
</data>
|
||||
<data name="Aliases.Heading" xml:space="preserve">
|
||||
<value>Aliases</value>
|
||||
</data>
|
||||
</root>
|
@ -133,7 +133,7 @@
|
||||
<value>Server Path</value>
|
||||
</data>
|
||||
<data name="ServerTime.HelpText" xml:space="preserve">
|
||||
<value>Server Time</value>
|
||||
<value>Server Date/Time (in UTC)</value>
|
||||
</data>
|
||||
<data name="FrameworkVersion.Text" xml:space="preserve">
|
||||
<value>Framework Version: </value>
|
||||
@ -148,7 +148,7 @@
|
||||
<value>Server Path: </value>
|
||||
</data>
|
||||
<data name="ServerTime.Text" xml:space="preserve">
|
||||
<value>Server Time: </value>
|
||||
<value>Server Date/Time: </value>
|
||||
</data>
|
||||
<data name="RestartApplication.Header" xml:space="preserve">
|
||||
<value>Restart Application</value>
|
||||
|
@ -121,10 +121,10 @@
|
||||
<value>Redirect To:</value>
|
||||
</data>
|
||||
<data name="MappedUrl.HelpText" xml:space="preserve">
|
||||
<value>A fully qualified Url where the user will be redirected</value>
|
||||
<value>A relative or absolute Url where the user will be redirected</value>
|
||||
</data>
|
||||
<data name="Url.HelpText" xml:space="preserve">
|
||||
<value>A fully qualified Url for this site</value>
|
||||
<value>An absolute Url identifying a path to a specific page in the site</value>
|
||||
</data>
|
||||
<data name="Url.Text" xml:space="preserve">
|
||||
<value>Url:</value>
|
||||
@ -135,4 +135,10 @@
|
||||
<data name="Message.InfoRequired" xml:space="preserve">
|
||||
<value>Please Provide All Required Information</value>
|
||||
</data>
|
||||
<data name="Message.DuplicateUrlMapping" xml:space="preserve">
|
||||
<value>The Url and Redirect To cannot be the same</value>
|
||||
</data>
|
||||
<data name="Message.SaveUrlMapping" xml:space="preserve">
|
||||
<value>The Url must belong to the current site</value>
|
||||
</data>
|
||||
</root>
|
@ -121,10 +121,10 @@
|
||||
<value>Redirect To:</value>
|
||||
</data>
|
||||
<data name="MappedUrl.HelpText" xml:space="preserve">
|
||||
<value>A fully qualified Url where the user will be redirected</value>
|
||||
<value>A relative or absolute Url where the user will be redirected</value>
|
||||
</data>
|
||||
<data name="Url.HelpText" xml:space="preserve">
|
||||
<value>A fully qualified Url for this site</value>
|
||||
<value>A relative Url identifying a path to a specific page in the site</value>
|
||||
</data>
|
||||
<data name="Url.Text" xml:space="preserve">
|
||||
<value>Url:</value>
|
||||
@ -138,4 +138,7 @@
|
||||
<data name="Message.InfoRequired" xml:space="preserve">
|
||||
<value>Please Provide All Required Information</value>
|
||||
</data>
|
||||
<data name="Message.DuplicateUrlMapping" xml:space="preserve">
|
||||
<value>The Url and Redirect To cannot be the same</value>
|
||||
</data>
|
||||
</root>
|
@ -156,11 +156,11 @@
|
||||
<data name="Visitors.Heading" xml:space="preserve">
|
||||
<value>Visitors</value>
|
||||
</data>
|
||||
<data name="VisitorTracking.HelpText" xml:space="preserve">
|
||||
<data name="Tracking.HelpText" xml:space="preserve">
|
||||
<value>Specify if visitor tracking is enabled</value>
|
||||
</data>
|
||||
<data name="VisitorTracking.Text" xml:space="preserve">
|
||||
<value>Visitor Tracking Enabled?</value>
|
||||
<data name="Tracking.Text" xml:space="preserve">
|
||||
<value>Tracking Enabled?</value>
|
||||
</data>
|
||||
<data name="IP" xml:space="preserve">
|
||||
<value>IP</value>
|
||||
@ -171,4 +171,25 @@
|
||||
<data name="Created" xml:space="preserve">
|
||||
<value>Created</value>
|
||||
</data>
|
||||
<data name="Details.Text" xml:space="preserve">
|
||||
<value>Details</value>
|
||||
</data>
|
||||
<data name="Filter.HelpText" xml:space="preserve">
|
||||
<value>Comma delimited list of terms which may exist in IP addresses, user agents, or languages identifying visitors which should not be tracked</value>
|
||||
</data>
|
||||
<data name="Filter.Text" xml:space="preserve">
|
||||
<value>Filter:</value>
|
||||
</data>
|
||||
<data name="Retention.HelpText" xml:space="preserve">
|
||||
<value>Number of days of visitor activity to retain</value>
|
||||
</data>
|
||||
<data name="Retention.Text" xml:space="preserve">
|
||||
<value>Retention (Days):</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>
|
||||
</data>
|
||||
<data name="Correlation.Text" xml:space="preserve">
|
||||
<value>Correlate Visitors?</value>
|
||||
</data>
|
||||
</root>
|
@ -117,10 +117,52 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Confirm.Delete" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Delete The {0} Version?</value>
|
||||
</data>
|
||||
<data name="Confirm.Restore" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Restore The {0} Version?</value>
|
||||
</data>
|
||||
<data name="CreatedBy" xml:space="preserve">
|
||||
<value>Created By</value>
|
||||
</data>
|
||||
<data name="CreatedOn" xml:space="preserve">
|
||||
<value>Created On</value>
|
||||
</data>
|
||||
<data name="Delete.Header" xml:space="preserve">
|
||||
<value>Delete Version</value>
|
||||
</data>
|
||||
<data name="Delete.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="Error.Content.Delete" xml:space="preserve">
|
||||
<value>Error Deleting Version</value>
|
||||
</data>
|
||||
<data name="Error.Content.Load" xml:space="preserve">
|
||||
<value>An Error Occurred Loading Content</value>
|
||||
</data>
|
||||
<data name="Error.Content.Restore" xml:space="preserve">
|
||||
<value>Error Restoring Version</value>
|
||||
</data>
|
||||
<data name="Error.Content.Save" xml:space="preserve">
|
||||
<value>An Error Occurred Saving Content</value>
|
||||
</data>
|
||||
<data name="Error.Content.View" xml:space="preserve">
|
||||
<value>Error Viewing Version</value>
|
||||
</data>
|
||||
<data name="Message.Content.Deleted" xml:space="preserve">
|
||||
<value>Version Deleted</value>
|
||||
</data>
|
||||
<data name="Message.Content.Restored" xml:space="preserve">
|
||||
<value>Version Restored</value>
|
||||
</data>
|
||||
<data name="Restore.Header" xml:space="preserve">
|
||||
<value>Restore Version</value>
|
||||
</data>
|
||||
<data name="Restore.Text" xml:space="preserve">
|
||||
<value>Restore</value>
|
||||
</data>
|
||||
<data name="View.Text" xml:space="preserve">
|
||||
<value>View</value>
|
||||
</data>
|
||||
</root>
|
@ -259,7 +259,7 @@
|
||||
<value>Upgrade</value>
|
||||
</data>
|
||||
<data name="Username" xml:space="preserve">
|
||||
<value>Username:</value>
|
||||
<value>Username</value>
|
||||
</data>
|
||||
<data name="Version" xml:space="preserve">
|
||||
<value>Version</value>
|
||||
|
@ -177,4 +177,13 @@
|
||||
<data name="System.Update" xml:space="preserve">
|
||||
<value>Check For System Updates</value>
|
||||
</data>
|
||||
<data name="Visibility" xml:space="preserve">
|
||||
<value>Visibility:</value>
|
||||
</data>
|
||||
<data name="VisibilityEdit" xml:space="preserve">
|
||||
<value>Page Editors Only</value>
|
||||
</data>
|
||||
<data name="VisibilityView" xml:space="preserve">
|
||||
<value>Same As Page</value>
|
||||
</data>
|
||||
</root>
|
@ -1,65 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
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.
|
||||
|
||||
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 xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
|
||||
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>
|
@ -121,7 +121,7 @@
|
||||
<value>Specify if a Footer pane should always be displayed in a fixed location at the bottom of the page.</value>
|
||||
</data>
|
||||
<data name="Footer.Text" xml:space="preserve">
|
||||
<value>Display Footer?</value>
|
||||
<value>Display Fixed Footer?</value>
|
||||
</data>
|
||||
<data name="Login.HelpText" xml:space="preserve">
|
||||
<value>Specify if a Login option should be displayed, Note that this option does not prevent the login page from being accessible via a direct url.</value>
|
@ -206,7 +206,7 @@ namespace Oqtane.Services
|
||||
/// <returns></returns>
|
||||
Dictionary<string, string> SetSetting(Dictionary<string, string> settings, string settingName, string settingValue);
|
||||
|
||||
Dictionary<string, string> SetSetting(Dictionary<string, string> settings, string settingName, string settingValue, bool isPublic);
|
||||
Dictionary<string, string> SetSetting(Dictionary<string, string> settings, string settingName, string settingValue, bool isPrivate);
|
||||
|
||||
Dictionary<string, string> MergeSettings(Dictionary<string, string> settings1, Dictionary<string, string> settings2);
|
||||
|
||||
|
@ -24,6 +24,14 @@ namespace Oqtane.Services
|
||||
/// <returns></returns>
|
||||
Task<UrlMapping> GetUrlMappingAsync(int urlMappingId);
|
||||
|
||||
/// <summary>
|
||||
/// Get one specific <see cref="UrlMapping"/>
|
||||
/// </summary>
|
||||
/// <param name="siteId">ID-reference of a <see cref="Site"/></param>
|
||||
/// <param name="url">A url</param>
|
||||
/// <returns></returns>
|
||||
Task<UrlMapping> GetUrlMappingAsync(int siteId, string url);
|
||||
|
||||
/// <summary>
|
||||
/// Add / save a new <see cref="UrlMapping"/> to the database.
|
||||
/// </summary>
|
||||
|
@ -131,14 +131,21 @@ namespace Oqtane.Services
|
||||
foreach (KeyValuePair<string, string> kvp in settings)
|
||||
{
|
||||
string value = kvp.Value;
|
||||
bool ispublic = false;
|
||||
bool modified = false;
|
||||
bool isprivate = false;
|
||||
|
||||
// manage settings modified with SetSetting method
|
||||
if (value.StartsWith("[Private]"))
|
||||
{
|
||||
modified = true;
|
||||
isprivate = true;
|
||||
value = value.Substring(9);
|
||||
}
|
||||
if (value.StartsWith("[Public]"))
|
||||
{
|
||||
if (entityName == EntityNames.Site)
|
||||
{
|
||||
ispublic = true;
|
||||
}
|
||||
value = value.Substring(8); // remove [Public]
|
||||
modified = true;
|
||||
isprivate = false;
|
||||
value = value.Substring(8);
|
||||
}
|
||||
|
||||
Setting setting = settingsList.FirstOrDefault(item => item.SettingName.Equals(kvp.Key, StringComparison.OrdinalIgnoreCase));
|
||||
@ -149,22 +156,21 @@ namespace Oqtane.Services
|
||||
setting.EntityId = entityId;
|
||||
setting.SettingName = kvp.Key;
|
||||
setting.SettingValue = value;
|
||||
setting.IsPublic = ispublic;
|
||||
setting.IsPrivate = isprivate;
|
||||
setting = await AddSettingAsync(setting);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (setting.SettingValue != kvp.Value)
|
||||
if (setting.SettingValue != value || (modified && setting.IsPrivate != isprivate))
|
||||
{
|
||||
setting.SettingValue = value;
|
||||
setting.IsPublic = ispublic;
|
||||
setting.IsPrivate = isprivate;
|
||||
setting = await UpdateSettingAsync(setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<Setting> GetSettingAsync(string entityName, int settingId)
|
||||
{
|
||||
return await GetJsonAsync<Setting>($"{Apiurl}/{settingId}/{entityName}");
|
||||
@ -201,13 +207,13 @@ namespace Oqtane.Services
|
||||
return SetSetting(settings, settingName, settingValue, false);
|
||||
}
|
||||
|
||||
public Dictionary<string, string> SetSetting(Dictionary<string, string> settings, string settingName, string settingValue, bool isPublic)
|
||||
public Dictionary<string, string> SetSetting(Dictionary<string, string> settings, string settingName, string settingValue, bool isPrivate)
|
||||
{
|
||||
if (settings == null)
|
||||
{
|
||||
settings = new Dictionary<string, string>();
|
||||
}
|
||||
settingValue = (isPublic) ? "[Public]" + settingValue : settingValue;
|
||||
settingValue = (isPrivate) ? "[Private]" + settingValue : "[Public]" + settingValue;
|
||||
if (settings.ContainsKey(settingName))
|
||||
{
|
||||
settings[settingName] = settingValue;
|
||||
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Shared;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
@ -33,6 +34,11 @@ namespace Oqtane.Services
|
||||
return await GetJsonAsync<UrlMapping>($"{Apiurl}/{urlMappingId}");
|
||||
}
|
||||
|
||||
public async Task<UrlMapping> GetUrlMappingAsync(int siteId, string url)
|
||||
{
|
||||
return await GetJsonAsync<UrlMapping>($"{Apiurl}/url/{siteId}?url={WebUtility.UrlEncode(url)}");
|
||||
}
|
||||
|
||||
public async Task<UrlMapping> AddUrlMappingAsync(UrlMapping role)
|
||||
{
|
||||
return await PostJsonAsync<UrlMapping>(Apiurl, role);
|
||||
|
@ -1,13 +1,20 @@
|
||||
@namespace Oqtane.Themes.BlazorTheme
|
||||
@inherits ContainerBase
|
||||
<div class="container">
|
||||
<div class="row p-4">
|
||||
<div class="d-flex flex-nowrap">
|
||||
<ModuleActions /><h2><ModuleTitle /></h2>
|
||||
</div>
|
||||
<hr class="app-rule" />
|
||||
</div>
|
||||
<div class="row px-4">
|
||||
@if (ModuleState.Title != "-")
|
||||
{
|
||||
<div class="row p-4">
|
||||
<div class="d-flex flex-nowrap">
|
||||
<ModuleActions /><h2><ModuleTitle /></h2>
|
||||
</div>
|
||||
<hr class="app-rule" />
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ModuleActions />
|
||||
}
|
||||
<div class="row px-4">
|
||||
<div class="container">
|
||||
<ModuleInstance />
|
||||
</div>
|
||||
|
@ -31,7 +31,7 @@
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
// obtained from https://cdnjs.com/libraries
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css", Integrity = "sha512-usVBAd66/NpVNfBge19gws2j6JZinnca12rAe2l+d+QkLU9fiG02O1X8Q6hepIpr/EYKZvKx/I9WsnujJuOmBA==", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css", Integrity = "sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js", Integrity = "sha512-pax4MlgXjHEPfCwcJLQhigY7+N8rt6bVvWLFyUMuxShv170X53TRzGPmPkZmGBhk+jikR8WBM4yl7A9WMHHqvg==", CrossOrigin = "anonymous" }
|
||||
};
|
||||
|
@ -3,7 +3,9 @@
|
||||
@attribute [OqtaneIgnore]
|
||||
|
||||
<span class="app-moduletitle">
|
||||
@((MarkupString)title)
|
||||
<a id="@ModuleState.PageModuleId.ToString()">
|
||||
@((MarkupString)title)
|
||||
</a>
|
||||
</span>
|
||||
|
||||
@code {
|
||||
|
@ -46,360 +46,366 @@
|
||||
</div>
|
||||
<div class="@BodyClass">
|
||||
<div class="container-fluid">
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
<div class="row d-flex">
|
||||
<div class="col">
|
||||
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-primary col-12" @onclick=@(async () => Navigate("Admin"))>@Localizer["AdminDash"]</button>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
<div class="row d-flex">
|
||||
<div class="col">
|
||||
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-primary col-12" @onclick=@(async () => Navigate("Admin"))>@Localizer["AdminDash"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="app-rule" />
|
||||
<hr class="app-rule" />
|
||||
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label class="control-label">@Localizer["Page.Manage"] </label>
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label class="control-label">@Localizer["Page.Manage"] </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row d-flex">
|
||||
<div class="col d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-secondary col me-1" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Add"))>@SharedLocalizer["Add"]</button>
|
||||
<button type="button" class="btn btn-secondary col" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Edit"))>@SharedLocalizer["Edit"]</button>
|
||||
<button type="button" class="btn btn-danger col ms-1" @onclick="ConfirmDelete">@SharedLocalizer["Delete"]</button>
|
||||
<div class="row d-flex mb-2">
|
||||
<div class="col d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-secondary col me-1" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Add"))>@SharedLocalizer["Add"]</button>
|
||||
<button type="button" class="btn btn-secondary col" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Edit"))>@SharedLocalizer["Edit"]</button>
|
||||
<button type="button" class="btn btn-danger col ms-1" @onclick="ConfirmDelete">@SharedLocalizer["Delete"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row d-flex">
|
||||
<div class="col">
|
||||
@if (UserSecurity.GetPermissionStrings(PageState.Page.Permissions).FirstOrDefault(item => item.PermissionName == PermissionNames.View).Permissions.Split(';').Contains(RoleNames.Everyone))
|
||||
{
|
||||
<button type="button" class="btn btn-secondary col-12" @onclick=@(async () => Publish("unpublish"))>@Localizer["Page.Unpublish"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-secondary col-12" @onclick=@(async () => Publish("publish"))>@Localizer["Page.Publish"]</button>
|
||||
}
|
||||
<div class="row d-flex">
|
||||
<div class="col">
|
||||
@if (UserSecurity.GetPermissionStrings(PageState.Page.Permissions).FirstOrDefault(item => item.PermissionName == PermissionNames.View).Permissions.Split(';').Contains(RoleNames.Everyone))
|
||||
{
|
||||
<button type="button" class="btn btn-secondary col-12" @onclick=@(async () => Publish("unpublish"))>@Localizer["Page.Unpublish"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-secondary col-12" @onclick=@(async () => Publish("publish"))>@Localizer["Page.Publish"]</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@if (_deleteConfirmation)
|
||||
{
|
||||
<div class="app-admin-modal">
|
||||
<div class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@Localizer["Page.Delete"]</h5>
|
||||
<button type="button" class="btn-close" aria-label="Close" @onclick="ConfirmDelete"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are You Sure You Want To Delete This Page?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" @onclick="DeletePage">@SharedLocalizer["Delete"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="ConfirmDelete">@SharedLocalizer["Cancel"]</button>
|
||||
@if (_deleteConfirmation)
|
||||
{
|
||||
<div class="app-admin-modal">
|
||||
<div class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@Localizer["Page.Delete"]</h5>
|
||||
<button type="button" class="btn-close" aria-label="Close" @onclick="ConfirmDelete"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are You Sure You Want To Delete This Page?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" @onclick="DeletePage">@SharedLocalizer["Delete"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="ConfirmDelete">@SharedLocalizer["Cancel"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<hr class="app-rule" />
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Module" class="control-label">@Localizer["Module.Manage"] </label>
|
||||
<select class="form-select" @bind="@ModuleType">
|
||||
<option value="new">@Localizer["Module.AddNew"]</option>
|
||||
<option value="existing">@Localizer["Module.AddExisting"]</option>
|
||||
</select>
|
||||
@if (ModuleType == "new")
|
||||
{
|
||||
@if (_moduleDefinitions != null)
|
||||
}
|
||||
<hr class="app-rule" />
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Module" class="control-label">@Localizer["Module.Manage"] </label>
|
||||
<select class="form-select" @bind="@ModuleType">
|
||||
<option value="new">@Localizer["Module.AddNew"]</option>
|
||||
<option value="existing">@Localizer["Module.AddExisting"]</option>
|
||||
</select>
|
||||
@if (ModuleType == "new")
|
||||
{
|
||||
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
||||
@foreach (var category in _categories)
|
||||
{
|
||||
if (category == Category)
|
||||
@if (_moduleDefinitions != null)
|
||||
{
|
||||
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
||||
@foreach (var category in _categories)
|
||||
{
|
||||
<option value="@category" selected>@category @Localizer["Modules"]</option>
|
||||
if (category == Category)
|
||||
{
|
||||
<option value="@category" selected>@category @Localizer["Modules"]</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@category">@category @Localizer["Modules"]</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
<select class="form-select" @onchange="(e => ModuleChanged(e))">
|
||||
@if (ModuleDefinitionName == "-")
|
||||
{
|
||||
<option value="-" selected><@Localizer["Module.Select"]></option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@category">@category @Localizer["Modules"]</option>
|
||||
<option value="-"><@Localizer["Module.Select"]></option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
<select class="form-select" @onchange="(e => ModuleChanged(e))">
|
||||
@if (ModuleDefinitionName == "-")
|
||||
{
|
||||
<option value="-" selected><@Localizer["Module.Select"]></option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="-"><@Localizer["Module.Select"]></option>
|
||||
}
|
||||
@foreach (var moduledefinition in _moduleDefinitions)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.Permissions))
|
||||
@foreach (var moduledefinition in _moduleDefinitions)
|
||||
{
|
||||
if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString()))
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.Permissions))
|
||||
{
|
||||
<option value="@moduledefinition.ModuleDefinitionName">@moduledefinition.Name</option>
|
||||
if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString()))
|
||||
{
|
||||
<option value="@moduledefinition.ModuleDefinitionName">@moduledefinition.Name</option>
|
||||
}
|
||||
}
|
||||
}
|
||||
</select>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<select class="form-select" @onchange="(e => PageChanged(e))">
|
||||
<option value="-"><@Localizer["Page.Select"]></option>
|
||||
@foreach (Page p in _pages)
|
||||
{
|
||||
<option value="@p.PageId">@p.Name</option>
|
||||
}
|
||||
</select>
|
||||
<select class="form-select" @bind="@ModuleId">
|
||||
<option value="-"><@Localizer["Module.Select"]></option>
|
||||
@foreach (Module module in _modules)
|
||||
{
|
||||
<option value="@module.ModuleId">@module.Title</option>
|
||||
}
|
||||
</select>
|
||||
@((MarkupString) Description)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<select class="form-select" @onchange="(e => PageChanged(e))">
|
||||
<option value="-"><@Localizer["Page.Select"]></option>
|
||||
@foreach (Page p in _pages)
|
||||
{
|
||||
<option value="@p.PageId">@p.Name</option>
|
||||
}
|
||||
</select>
|
||||
<select class="form-select" @bind="@ModuleId">
|
||||
<option value="-"><@Localizer["Module.Select"]></option>
|
||||
@foreach (Module module in _modules)
|
||||
{
|
||||
<option value="@module.ModuleId">@module.Title</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Title" class="control-label">@Localizer["Title"] </label>
|
||||
<input type="text" name="Title" class="form-control" @bind="@Title" />
|
||||
</div>
|
||||
</div>
|
||||
@if (_pane.Length > 1)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Pane" class="control-label">@Localizer["Pane"] </label>
|
||||
<select class="form-select" @bind="@Pane">
|
||||
@foreach (string pane in PageState.Page.Panes)
|
||||
<label for="Title" class="control-label">@Localizer["Title"] </label>
|
||||
<input type="text" name="Title" class="form-control" @bind="@Title" />
|
||||
</div>
|
||||
</div>
|
||||
@if (_pane.Length > 1)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Pane" class="control-label">@Localizer["Pane"] </label>
|
||||
<select class="form-select" @bind="@Pane">
|
||||
@foreach (string pane in PageState.Page.Panes)
|
||||
{
|
||||
<option value="@pane">@pane Pane</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Container" class="control-label">@Localizer["Container"] </label>
|
||||
<select class="form-select" @bind="@ContainerType">
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@pane">@pane Pane</option>
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="Container" class="control-label">@Localizer["Container"] </label>
|
||||
<select class="form-select" @bind="@ContainerType">
|
||||
@foreach (var container in _containers)
|
||||
{
|
||||
<option value="@container.TypeName">@container.Name</option>
|
||||
}
|
||||
</select>
|
||||
<div class="row">
|
||||
<div class="col text-center">
|
||||
<label for="visibility" class="control-label">@Localizer["Visibility"]</label>
|
||||
<select class="form-select" @bind="@Visibility">
|
||||
<option value="edit" selected>@Localizer["VisibilityEdit"]</option>
|
||||
<option value="view">@Localizer["VisibilityView"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-primary col-12" @onclick="@AddModule">@Localizer["Page.Module.Add"]</button>
|
||||
@((MarkupString) Message)
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<hr class="app-rule" />
|
||||
<NavLink class="btn btn-info col-12" data-bs-dismiss="offcanvas" href="@NavigateUrl("admin/update")">@Localizer["System.Update"]</NavLink>
|
||||
}
|
||||
<button type="button" class="btn btn-primary col-12 mt-4" @onclick="@AddModule">@Localizer["Page.Module.Add"]</button>
|
||||
@((MarkupString) Message)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code{
|
||||
private bool _deleteConfirmation = false;
|
||||
private List<string> _categories = new List<string>();
|
||||
private List<ModuleDefinition> _allModuleDefinitions;
|
||||
private List<ModuleDefinition> _moduleDefinitions;
|
||||
private List<Page> _pages = new List<Page>();
|
||||
private List<Module> _modules = new List<Module>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _category = "Common";
|
||||
|
||||
private bool _deleteConfirmation = false;
|
||||
private List<string> _categories = new List<string>();
|
||||
private List<ModuleDefinition> _allModuleDefinitions;
|
||||
private List<ModuleDefinition> _moduleDefinitions;
|
||||
private List<Page> _pages = new List<Page>();
|
||||
private List<Module> _modules = new List<Module>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _category = "Common";
|
||||
protected string PageId { get; private set; } = "-";
|
||||
protected string ModuleId { get; private set; } = "-";
|
||||
protected string ModuleType { get; private set; } = "new";
|
||||
protected string ModuleDefinitionName { get; private set; } = "-";
|
||||
|
||||
protected string PageId { get; private set; } = "-";
|
||||
protected string ModuleId { get; private set; } = "-";
|
||||
protected string ModuleType { get; private set; } = "new";
|
||||
protected string ModuleDefinitionName { get; private set; } = "-";
|
||||
protected string Category
|
||||
{
|
||||
get => _category;
|
||||
private set
|
||||
{
|
||||
if (_category != value)
|
||||
{
|
||||
_category = value;
|
||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
|
||||
ModuleDefinitionName = "-";
|
||||
Message = "";
|
||||
StateHasChanged();
|
||||
_ = UpdateSettingsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected string Category
|
||||
{
|
||||
get => _category;
|
||||
private set
|
||||
{
|
||||
if (_category != value)
|
||||
{
|
||||
_category = value;
|
||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(Category)).ToList();
|
||||
ModuleDefinitionName = "-";
|
||||
Description = "";
|
||||
StateHasChanged();
|
||||
_ = UpdateSettingsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
protected string Pane
|
||||
{
|
||||
get => _pane;
|
||||
private set
|
||||
{
|
||||
if (_pane != value)
|
||||
{
|
||||
_pane = value;
|
||||
_ = UpdateSettingsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected string Pane
|
||||
{
|
||||
get => _pane;
|
||||
private set
|
||||
{
|
||||
if (_pane != value)
|
||||
{
|
||||
_pane = value;
|
||||
_ = UpdateSettingsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
protected string Title { get; private set; } = "";
|
||||
protected string ContainerType { get; private set; } = "";
|
||||
protected string Visibility { get; private set; } = "edit";
|
||||
protected string Message { get; private set; } = "";
|
||||
|
||||
[Parameter]
|
||||
public string ButtonClass { get; set; } = "btn-outline-secondary";
|
||||
|
||||
[Parameter]
|
||||
public string ContainerClass { get; set; } = "offcanvas offcanvas-end";
|
||||
|
||||
[Parameter]
|
||||
public string HeaderClass { get; set; } = "offcanvas-header";
|
||||
|
||||
[Parameter]
|
||||
public string BodyClass { get; set; } = "offcanvas-body overflow-auto";
|
||||
|
||||
[Parameter]
|
||||
public bool ShowLanguageSwitcher { get; set; } = true;
|
||||
|
||||
|
||||
protected string Description { get; private set; } = "";
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||
{
|
||||
_pages?.Clear();
|
||||
|
||||
protected string Title { get; private set; } = "";
|
||||
protected string ContainerType { get; private set; } = "";
|
||||
protected string Message { get; private set; } = "";
|
||||
foreach (Page p in PageState.Pages)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||
{
|
||||
_pages.Add(p);
|
||||
}
|
||||
}
|
||||
await LoadSettingsAsync();
|
||||
|
||||
[Parameter]
|
||||
public string ButtonClass { get; set; } = "btn-outline-secondary";
|
||||
var themes = await ThemeService.GetThemesAsync();
|
||||
_containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public string ContainerClass { get; set; } = "offcanvas offcanvas-end";
|
||||
private void CategoryChanged(ChangeEventArgs e)
|
||||
{
|
||||
Category = (string)e.Value;
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public string HeaderClass { get; set; } = "offcanvas-header";
|
||||
private void ModuleChanged(ChangeEventArgs e)
|
||||
{
|
||||
ModuleDefinitionName = (string)e.Value;
|
||||
if (ModuleDefinitionName != "-")
|
||||
{
|
||||
var moduleDefinition = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName);
|
||||
Message = "<div class=\"alert alert-info mt-2 text-center\" role=\"alert\">" + moduleDefinition.Description + "</div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
Message = "";
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public string BodyClass { get; set; } = "offcanvas-body overflow-auto";
|
||||
private void PageChanged(ChangeEventArgs e)
|
||||
{
|
||||
PageId = (string)e.Value;
|
||||
if (PageId != "-")
|
||||
{
|
||||
_modules = PageState.Modules
|
||||
.Where(module => module.PageId == int.Parse(PageId)
|
||||
&& !module.IsDeleted
|
||||
&& UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions))
|
||||
.ToList();
|
||||
}
|
||||
ModuleId = "-";
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public bool ShowLanguageSwitcher { get; set; } = true;
|
||||
private async Task AddModule()
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||
{
|
||||
if ((ModuleType == "new" && ModuleDefinitionName != "-") || (ModuleType != "new" && ModuleId != "-"))
|
||||
{
|
||||
if (ModuleType == "new")
|
||||
{
|
||||
Module module = new Module();
|
||||
module.SiteId = PageState.Site.SiteId;
|
||||
module.PageId = PageState.Page.PageId;
|
||||
module.ModuleDefinitionName = ModuleDefinitionName;
|
||||
module.AllPages = false;
|
||||
|
||||
List<PermissionString> permissions = UserSecurity.GetPermissionStrings(PageState.Page.Permissions);
|
||||
if (Visibility == "view")
|
||||
{
|
||||
// set module view permissions to page view permissions
|
||||
permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions = permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set module view permissions to page edit permissions
|
||||
permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions = permissions.Find(p => p.PermissionName == PermissionNames.Edit).Permissions;
|
||||
}
|
||||
module.Permissions = UserSecurity.SetPermissionStrings(permissions);
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||
{
|
||||
_pages?.Clear();
|
||||
module = await ModuleService.AddModuleAsync(module);
|
||||
ModuleId = module.ModuleId.ToString();
|
||||
}
|
||||
|
||||
foreach (Page p in PageState.Pages)
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
||||
{
|
||||
_pages.Add(p);
|
||||
}
|
||||
}
|
||||
await LoadSettingsAsync();
|
||||
|
||||
var themes = await ThemeService.GetThemesAsync();
|
||||
_containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private void CategoryChanged(ChangeEventArgs e)
|
||||
{
|
||||
Category = (string)e.Value;
|
||||
}
|
||||
|
||||
private void ModuleChanged(ChangeEventArgs e)
|
||||
{
|
||||
ModuleDefinitionName = (string)e.Value;
|
||||
if (ModuleDefinitionName != "-")
|
||||
{
|
||||
var moduleDefinition = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName);
|
||||
Description = "<br /><div class=\"alert alert-info\" role=\"alert\">" + moduleDefinition.Description + "</div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
Description = "";
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void PageChanged(ChangeEventArgs e)
|
||||
{
|
||||
PageId = (string)e.Value;
|
||||
if (PageId != "-")
|
||||
{
|
||||
_modules = PageState.Modules
|
||||
.Where(module => module.PageId == int.Parse(PageId)
|
||||
&& !module.IsDeleted
|
||||
&& UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions))
|
||||
.ToList();
|
||||
}
|
||||
ModuleId = "-";
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task AddModule()
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
||||
{
|
||||
if ((ModuleType == "new" && ModuleDefinitionName != "-") || (ModuleType != "new" && ModuleId != "-"))
|
||||
{
|
||||
if (ModuleType == "new")
|
||||
{
|
||||
Module module = new Module();
|
||||
module.SiteId = PageState.Site.SiteId;
|
||||
module.PageId = PageState.Page.PageId;
|
||||
module.ModuleDefinitionName = ModuleDefinitionName;
|
||||
module.AllPages = false;
|
||||
|
||||
// set module view permissions to page edit permissions
|
||||
List<PermissionString> permissions = UserSecurity.GetPermissionStrings(PageState.Page.Permissions);
|
||||
permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions = permissions.Find(p => p.PermissionName == PermissionNames.Edit).Permissions;
|
||||
module.Permissions = UserSecurity.SetPermissionStrings(permissions);
|
||||
|
||||
module = await ModuleService.AddModuleAsync(module);
|
||||
ModuleId = module.ModuleId.ToString();
|
||||
}
|
||||
|
||||
var pageModule = new PageModule
|
||||
var pageModule = new PageModule
|
||||
{
|
||||
PageId = PageState.Page.PageId,
|
||||
ModuleId = int.Parse(ModuleId),
|
||||
Title = Title
|
||||
};
|
||||
if (pageModule.Title == "")
|
||||
{
|
||||
if (ModuleType == "new")
|
||||
{
|
||||
pageModule.Title = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName)?.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
pageModule.Title = _modules.FirstOrDefault(item => item.ModuleId == int.Parse(ModuleId))?.Title;
|
||||
}
|
||||
}
|
||||
if (pageModule.Title == "")
|
||||
{
|
||||
if (ModuleType == "new")
|
||||
{
|
||||
pageModule.Title = _moduleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == ModuleDefinitionName)?.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
pageModule.Title = _modules.FirstOrDefault(item => item.ModuleId == int.Parse(ModuleId))?.Title;
|
||||
}
|
||||
}
|
||||
|
||||
pageModule.Pane = Pane;
|
||||
pageModule.Order = int.MaxValue;
|
||||
pageModule.ContainerType = ContainerType;
|
||||
pageModule.Pane = Pane;
|
||||
pageModule.Order = int.MaxValue;
|
||||
pageModule.ContainerType = ContainerType;
|
||||
|
||||
if (pageModule.ContainerType == PageState.Site.DefaultContainerType)
|
||||
{
|
||||
pageModule.ContainerType = "";
|
||||
}
|
||||
if (pageModule.ContainerType == PageState.Site.DefaultContainerType)
|
||||
{
|
||||
pageModule.ContainerType = "";
|
||||
}
|
||||
|
||||
await PageModuleService.AddPageModuleAsync(pageModule);
|
||||
await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane);
|
||||
await PageModuleService.AddPageModuleAsync(pageModule);
|
||||
await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane);
|
||||
|
||||
Message = $"<div class=\"alert alert-success mt-2 text-center\" role=\"alert\">{Localizer["Success.Page.ModuleAdd"]}</div>";
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
Message = $"<div class=\"alert alert-success mt-2 text-center\" role=\"alert\">{Localizer["Success.Page.ModuleAdd"]}</div>";
|
||||
Title = "";
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2,6 +2,7 @@ using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Providers;
|
||||
using Oqtane.Security;
|
||||
using Oqtane.Services;
|
||||
@ -17,6 +18,7 @@ namespace Oqtane.Themes.Controls
|
||||
[Inject] public IJSRuntime jsRuntime { get; set; }
|
||||
[Inject] public IServiceProvider ServiceProvider { get; set; }
|
||||
[Inject] public SiteState SiteState { get; set; }
|
||||
[Inject] public ILogService LoggingService { get; set; }
|
||||
|
||||
protected void LoginUser()
|
||||
{
|
||||
@ -31,6 +33,8 @@ namespace Oqtane.Themes.Controls
|
||||
protected async Task LogoutUser()
|
||||
{
|
||||
await UserService.LogoutUserAsync(PageState.User);
|
||||
await LoggingService.Log(PageState.Alias, PageState.Page.PageId, PageState.ModuleId, PageState.User.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User.Username);
|
||||
|
||||
PageState.User = null;
|
||||
bool authorizedtoviewpage = UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, PageState.Page.Permissions);
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
@inject ISettingService SettingService
|
||||
|
||||
<div class="@_classes">
|
||||
@if (_title)
|
||||
@if (_title && ModuleState.Title != "-")
|
||||
{
|
||||
<div class="row px-4">
|
||||
<div class="d-flex flex-nowrap">
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="title" ResourceKey="Title" HelpText="Specify If The Module Title Should Be Displayed">Display Title?</Label>
|
||||
<Label Class="col-sm-3" For="title" ResourceKey="Title" ResourceType="@resourceType" HelpText="Specify If The Module Title Should Be Displayed">Display Title?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="title" class="form-select" @bind="@_title">
|
||||
<option value="true">Yes</option>
|
||||
@ -15,7 +15,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="background\" ResourceKey="Background" HelpText="Optionally Specify A Background Color For The Container">Background Color:</Label>
|
||||
<Label Class="col-sm-3" For="background\" ResourceKey="Background" ResourceType="@resourceType" HelpText="Optionally Specify A Background Color For The Container">Background Color:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="background" class="form-select" @bind="@_background">
|
||||
<option value="">None</option>
|
||||
@ -31,7 +31,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="text" ResourceKey="Text" HelpText="Optionally Specify A Text Color For The Container">Text Color:</Label>
|
||||
<Label Class="col-sm-3" For="text" ResourceKey="Text" ResourceType="@resourceType" HelpText="Optionally Specify A Text Color For The Container">Text Color:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="text" class="form-select" @bind="@_text">
|
||||
<option value="">None</option>
|
||||
@ -47,7 +47,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="border" ResourceKey="Border" HelpText="Optionally Specify A Border For The Container">Border Color:</Label>
|
||||
<Label Class="col-sm-3" For="border" ResourceKey="Border" ResourceType="@resourceType" HelpText="Optionally Specify A Border For The Container">Border Color:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="border" class="form-select" @bind="@_border">
|
||||
<option value="">None</option>
|
||||
@ -65,41 +65,42 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private string _title = "true";
|
||||
private string _background = "";
|
||||
private string _text = "";
|
||||
private string _border = "";
|
||||
@code {
|
||||
private string resourceType = "Oqtane.Themes.OqtaneTheme.ContainerSettings, Oqtane.Client"; // for localization
|
||||
private string _title = "true";
|
||||
private string _background = "";
|
||||
private string _text = "";
|
||||
private string _border = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
_title = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Title", "true");
|
||||
_background = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Background", "");
|
||||
_text = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Text", "");
|
||||
_border = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Border", "");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
_title = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Title", "true");
|
||||
_background = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Background", "");
|
||||
_text = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Text", "");
|
||||
_border = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Border", "");
|
||||
}
|
||||
|
||||
public async Task UpdateSettings()
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = ModuleState.Settings;
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Title", _title);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Background", _background);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Text", _text);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Border", _border);
|
||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Title", _title);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Background", _background);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Text", _text);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Border", _border);
|
||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="scope" ResourceKey="Scope" HelpText="Specify if the settings are applicable to this page or the entire site.">Setting Scope:</Label>
|
||||
<Label Class="col-sm-3" For="scope" ResourceKey="Scope" ResourceType="@resourceType" HelpText="Specify if the settings are applicable to this page or the entire site.">Setting Scope:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="scope" class="form-select" value="@_scope" @onchange="(e => ScopeChanged(e))">
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
@ -20,7 +20,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="login" ResourceKey="Login" HelpText="Specify if a Login option should be displayed. Note that this option does not prevent the login page from being accessible via a direct url.">Show Login?</Label>
|
||||
<Label Class="col-sm-3" For="login" ResourceKey="Login" ResourceType="@resourceType" HelpText="Specify if a Login option should be displayed. Note that this option does not prevent the login page from being accessible via a direct url.">Show Login?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="login" class="form-select" @bind="@_login">
|
||||
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
||||
@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="register" ResourceKey="Register" HelpText="Specify if a Register option should be displayed. Note that this option is also dependent on the Allow Registration option in Site Settings.">Show Register?</Label>
|
||||
<Label Class="col-sm-3" For="register" ResourceKey="Register" ResourceType="@resourceType" HelpText="Specify if a Register option should be displayed. Note that this option is also dependent on the Allow Registration option in Site Settings.">Show Register?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="register" class="form-select" @bind="@_register">
|
||||
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
||||
@ -40,7 +40,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="footer" ResourceKey="Footer" HelpText="Specify if a Footer pane should always be displayed in a fixed location at the bottom of the page">Display Fixed Footer?</Label>
|
||||
<Label Class="col-sm-3" For="footer" ResourceKey="Footer" ResourceType="@resourceType" HelpText="Specify if a Footer pane should always be displayed in a fixed location at the bottom of the page">Display Fixed Footer?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="footer" class="form-select" @bind="@_footer">
|
||||
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
||||
@ -52,16 +52,17 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private string _scope = "page";
|
||||
private string _login = "-";
|
||||
private string _register = "-";
|
||||
private string _footer = "-";
|
||||
private string resourceType = "Oqtane.Themes.OqtaneTheme.ThemeSettings, Oqtane.Client"; // for localization
|
||||
private string _scope = "page";
|
||||
private string _login = "-";
|
||||
private string _register = "-";
|
||||
private string _footer = "-";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await LoadSettings();
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await LoadSettings();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -110,7 +111,7 @@
|
||||
{
|
||||
if (_scope == "site")
|
||||
{
|
||||
var settings = PageState.Site.Settings;
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
if (_login != "-")
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login, true);
|
||||
@ -127,7 +128,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
var settings = PageState.Page.Settings;
|
||||
var settings = await SettingService.GetPageSettingsAsync(PageState.Page.PageId);
|
||||
if (_login != "-")
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login);
|
||||
|
@ -104,14 +104,19 @@ namespace Oqtane.Themes
|
||||
return Utilities.ContentUrl(PageState.Alias, fileid, asAttachment);
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode)
|
||||
public string ImageUrl(int fileid, int width, int height)
|
||||
{
|
||||
return ImageUrl(fileid, width, height, mode, 0);
|
||||
return ImageUrl(fileid, width, height, "");
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode, int rotate)
|
||||
public string ImageUrl(int fileid, int width, int height, string mode)
|
||||
{
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, rotate);
|
||||
return ImageUrl(fileid, width, height, mode, "", "", 0, false);
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode, string position, string background, int rotate, bool recreate)
|
||||
{
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, position, background, rotate, recreate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -262,5 +262,36 @@ namespace Oqtane.UI
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public Task ScrollTo(int top, int left, string behavior)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(behavior)) behavior = "smooth";
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.scrollTo",
|
||||
top, left, behavior);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public Task ScrollToId(string id)
|
||||
{
|
||||
try
|
||||
{
|
||||
_jsRuntime.InvokeVoidAsync(
|
||||
"Oqtane.Interop.scrollToId",
|
||||
id);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,5 +21,6 @@ namespace Oqtane.UI
|
||||
public DateTime LastSyncDate { get; set; }
|
||||
public Oqtane.Shared.Runtime Runtime { get; set; }
|
||||
public int VisitorId { get; set; }
|
||||
public string RemoteIPAddress { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,9 @@
|
||||
@inject IPageService PageService
|
||||
@inject IUserService UserService
|
||||
@inject IModuleService ModuleService
|
||||
@inject IUrlMappingService UrlMappingService
|
||||
@inject ILogService LogService
|
||||
@inject IJSRuntime JSRuntime
|
||||
@implements IHandleAfterRender
|
||||
|
||||
@DynamicComponent
|
||||
@ -82,134 +84,137 @@
|
||||
var action = (!string.IsNullOrEmpty(route.Action)) ? route.Action : Constants.DefaultAction;
|
||||
var querystring = ParseQueryString(route.Query);
|
||||
|
||||
// reload the client application if there is a forced reload or the user navigated to a site with a different alias
|
||||
if (querystring.ContainsKey("reload") || (!route.AbsolutePath.Substring(1).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
|
||||
{
|
||||
NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", ""), true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the refresh parameter is used to refresh the PageState
|
||||
if (querystring.ContainsKey("refresh"))
|
||||
{
|
||||
refresh = UI.Refresh.Site;
|
||||
}
|
||||
}
|
||||
// reload the client application if there is a forced reload or the user navigated to a site with a different alias
|
||||
if (querystring.ContainsKey("reload") || (!route.AbsolutePath.Substring(1).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
|
||||
{
|
||||
NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", ""), true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the refresh parameter is used to refresh the PageState
|
||||
if (querystring.ContainsKey("refresh"))
|
||||
{
|
||||
refresh = UI.Refresh.Site;
|
||||
}
|
||||
}
|
||||
|
||||
if (PageState != null)
|
||||
{
|
||||
editmode = PageState.EditMode;
|
||||
lastsyncdate = PageState.LastSyncDate;
|
||||
}
|
||||
if (PageState != null)
|
||||
{
|
||||
editmode = PageState.EditMode;
|
||||
lastsyncdate = PageState.LastSyncDate;
|
||||
}
|
||||
|
||||
// process any sync events
|
||||
var sync = await SyncService.GetSyncAsync(lastsyncdate);
|
||||
lastsyncdate = sync.SyncDate;
|
||||
if (sync.SyncEvents.Any())
|
||||
{
|
||||
// reload client application if server was restarted or site runtime/rendermode was modified
|
||||
if (PageState != null && sync.SyncEvents.Exists(item => (item.TenantId == -1 || item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId) && item.Reload))
|
||||
{
|
||||
NavigationManager.NavigateTo(_absoluteUri, true);
|
||||
return;
|
||||
}
|
||||
if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId))
|
||||
{
|
||||
refresh = UI.Refresh.Site;
|
||||
}
|
||||
}
|
||||
// process any sync events
|
||||
var sync = await SyncService.GetSyncAsync(lastsyncdate);
|
||||
lastsyncdate = sync.SyncDate;
|
||||
if (sync.SyncEvents.Any())
|
||||
{
|
||||
// reload client application if server was restarted or site runtime/rendermode was modified
|
||||
if (PageState != null && sync.SyncEvents.Exists(item => (item.TenantId == -1 || item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId) && item.Reload))
|
||||
{
|
||||
NavigationManager.NavigateTo(_absoluteUri, true);
|
||||
return;
|
||||
}
|
||||
if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId))
|
||||
{
|
||||
refresh = UI.Refresh.Site;
|
||||
}
|
||||
}
|
||||
|
||||
if (refresh == UI.Refresh.Site || PageState == null || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
||||
{
|
||||
site = await SiteService.GetSiteAsync(SiteState.Alias.SiteId);
|
||||
refresh = UI.Refresh.Site;
|
||||
}
|
||||
else
|
||||
{
|
||||
site = PageState.Site;
|
||||
}
|
||||
if (refresh == UI.Refresh.Site || PageState == null || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
||||
{
|
||||
site = await SiteService.GetSiteAsync(SiteState.Alias.SiteId);
|
||||
refresh = UI.Refresh.Site;
|
||||
}
|
||||
else
|
||||
{
|
||||
site = PageState.Site;
|
||||
}
|
||||
|
||||
if (site != null)
|
||||
{
|
||||
if (PageState == null || refresh == UI.Refresh.Site)
|
||||
{
|
||||
// get user
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
if (authState.User.Identity.IsAuthenticated)
|
||||
{
|
||||
user = await UserService.GetUserAsync(authState.User.Identity.Name, site.SiteId);
|
||||
user.IsAuthenticated = authState.User.Identity.IsAuthenticated;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
user = PageState.User;
|
||||
}
|
||||
if (site != null)
|
||||
{
|
||||
if (PageState == null || refresh == UI.Refresh.Site)
|
||||
{
|
||||
// get user
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
if (authState.User.Identity.IsAuthenticated)
|
||||
{
|
||||
user = await UserService.GetUserAsync(authState.User.Identity.Name, site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
user.IsAuthenticated = authState.User.Identity.IsAuthenticated;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
user = PageState.User;
|
||||
}
|
||||
|
||||
// process any sync events for user
|
||||
if (refresh != UI.Refresh.Site && user != null && sync.SyncEvents.Any())
|
||||
{
|
||||
if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.User && item.EntityId == user.UserId))
|
||||
{
|
||||
refresh = UI.Refresh.Site;
|
||||
}
|
||||
}
|
||||
// process any sync events for user
|
||||
if (refresh != UI.Refresh.Site && user != null && sync.SyncEvents.Any())
|
||||
{
|
||||
if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.User && item.EntityId == user.UserId))
|
||||
{
|
||||
refresh = UI.Refresh.Site;
|
||||
}
|
||||
}
|
||||
|
||||
if (PageState == null || refresh == UI.Refresh.Site)
|
||||
{
|
||||
pages = await PageService.GetPagesAsync(site.SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
pages = PageState.Pages;
|
||||
}
|
||||
if (PageState == null || refresh == UI.Refresh.Site)
|
||||
{
|
||||
pages = await PageService.GetPagesAsync(site.SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
pages = PageState.Pages;
|
||||
}
|
||||
|
||||
if (PageState == null || refresh == UI.Refresh.Site)
|
||||
{
|
||||
page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
page = PageState.Page;
|
||||
}
|
||||
if (PageState == null || refresh == UI.Refresh.Site)
|
||||
{
|
||||
page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
else
|
||||
{
|
||||
page = PageState.Page;
|
||||
}
|
||||
|
||||
// get the page if the path has changed
|
||||
if (page == null || page.Path != route.PagePath)
|
||||
{
|
||||
page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||
// get the page if the path has changed
|
||||
if (page == null || page.Path != route.PagePath)
|
||||
{
|
||||
page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||
// if the home page path does not exist then use the first page in the collection (a future enhancement would allow the admin to specify the home page)
|
||||
if (page == null && route.PagePath == "")
|
||||
{
|
||||
page = pages.FirstOrDefault();
|
||||
}
|
||||
editmode = false;
|
||||
}
|
||||
editmode = false;
|
||||
}
|
||||
|
||||
if (page != null)
|
||||
{
|
||||
if (PageState == null)
|
||||
{
|
||||
editmode = false;
|
||||
}
|
||||
if (page != null)
|
||||
{
|
||||
if (PageState == null)
|
||||
{
|
||||
editmode = false;
|
||||
}
|
||||
|
||||
// check if user is authorized to view page
|
||||
if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.Permissions))
|
||||
{
|
||||
page = await ProcessPage(page, site, user);
|
||||
// check if user is authorized to view page
|
||||
if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.Permissions))
|
||||
{
|
||||
page = await ProcessPage(page, site, user);
|
||||
|
||||
if (PageState == null || refresh == UI.Refresh.Site)
|
||||
{
|
||||
modules = await ModuleService.GetModulesAsync(site.SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
modules = PageState.Modules;
|
||||
}
|
||||
if (PageState == null || refresh == UI.Refresh.Site)
|
||||
{
|
||||
modules = await ModuleService.GetModulesAsync(site.SiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
modules = PageState.Modules;
|
||||
}
|
||||
|
||||
(page, modules) = ProcessModules(page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType);
|
||||
(page, modules) = ProcessModules(page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType);
|
||||
|
||||
_pagestate = new PageState
|
||||
_pagestate = new PageState
|
||||
{
|
||||
Alias = SiteState.Alias,
|
||||
Site = site,
|
||||
@ -225,260 +230,293 @@
|
||||
EditMode = editmode,
|
||||
LastSyncDate = lastsyncdate,
|
||||
Runtime = runtime,
|
||||
VisitorId = VisitorId
|
||||
VisitorId = VisitorId,
|
||||
RemoteIPAddress = SiteState.RemoteIPAddress
|
||||
};
|
||||
|
||||
OnStateChange?.Invoke(_pagestate);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
// redirect to login page
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + route.AbsolutePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
await LogService.Log(null, null, user.UserId, GetType().AssemblyQualifiedName, Utilities.GetTypeNameLastSegment(GetType().AssemblyQualifiedName, 1), LogFunction.Security, LogLevel.Error, null, "Page Does Not Exist Or User Is Not Authorized To View Page {Path}", route.PagePath);
|
||||
if (route.PagePath != "")
|
||||
{
|
||||
// redirect to home page
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
OnStateChange?.Invoke(_pagestate);
|
||||
await ScrollToFragment(_pagestate.Uri);
|
||||
}
|
||||
}
|
||||
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;
|
||||
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=" + route.AbsolutePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
await LogService.Log(null, null, user.UserId, GetType().AssemblyQualifiedName, Utilities.GetTypeNameLastSegment(GetType().AssemblyQualifiedName, 1), LogFunction.Security, LogLevel.Error, null, "Page Does Not Exist Or User Is Not Authorized To View Page {Path}", route.PagePath);
|
||||
if (route.PagePath != "")
|
||||
{
|
||||
// redirect to home page
|
||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// site does not exist
|
||||
}
|
||||
}
|
||||
|
||||
private async void LocationChanged(object sender, LocationChangedEventArgs args)
|
||||
{
|
||||
_absoluteUri = args.Location;
|
||||
await Refresh();
|
||||
}
|
||||
|
||||
Task IHandleAfterRender.OnAfterRenderAsync()
|
||||
{
|
||||
if (!_navigationInterceptionEnabled)
|
||||
{
|
||||
_navigationInterceptionEnabled = true;
|
||||
return NavigationInterception.EnableNavigationInterceptionAsync();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Dictionary<string, string> ParseQueryString(string query)
|
||||
{
|
||||
Dictionary<string, string> querystring = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // case insensistive keys
|
||||
if (!string.IsNullOrEmpty(query))
|
||||
{
|
||||
if (query.StartsWith("?"))
|
||||
{
|
||||
query = query.Substring(1); // ignore "?"
|
||||
}
|
||||
foreach (string kvp in query.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (kvp != "")
|
||||
{
|
||||
if (kvp.Contains("="))
|
||||
{
|
||||
string[] pair = kvp.Split('=');
|
||||
querystring.Add(pair[0], pair[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
querystring.Add(kvp, "true"); // default parameter when no value is provided
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return querystring;
|
||||
}
|
||||
|
||||
private async Task<Page> ProcessPage(Page page, Site site, User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (page.IsPersonalizable && user != null)
|
||||
{
|
||||
// load the personalized page
|
||||
page = await PageService.GetPageAsync(page.PageId, user.UserId);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(page.ThemeType))
|
||||
{
|
||||
page.ThemeType = site.DefaultThemeType;
|
||||
}
|
||||
|
||||
page.Panes = new List<string>();
|
||||
page.Resources = new List<Resource>();
|
||||
|
||||
string panes = PaneNames.Admin;
|
||||
Type themetype = Type.GetType(page.ThemeType);
|
||||
if (themetype == null)
|
||||
{
|
||||
// fallback
|
||||
page.ThemeType = Constants.DefaultTheme;
|
||||
themetype = Type.GetType(Constants.DefaultTheme);
|
||||
}
|
||||
if (themetype != null)
|
||||
{
|
||||
var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
|
||||
if (themeobject != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(themeobject.Panes))
|
||||
{
|
||||
panes = themeobject.Panes;
|
||||
}
|
||||
page.Resources = ManagePageResources(page.Resources, themeobject.Resources);
|
||||
}
|
||||
}
|
||||
page.Panes = panes.Replace(";", ",").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// error loading theme or layout
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
private (Page Page, List<Module> Modules) ProcessModules(Page page, List<Module> modules, int moduleid, string action, string defaultcontainertype)
|
||||
{
|
||||
var paneindex = new Dictionary<string, int>();
|
||||
foreach (Module module in modules)
|
||||
{
|
||||
// initialize module control properties
|
||||
module.SecurityAccessLevel = SecurityAccessLevel.Host;
|
||||
module.ControlTitle = "";
|
||||
module.Actions = "";
|
||||
module.UseAdminContainer = false;
|
||||
module.PaneModuleIndex = -1;
|
||||
module.PaneModuleCount = 0;
|
||||
|
||||
if ((module.PageId == page.PageId || module.ModuleId == moduleid))
|
||||
{
|
||||
var typename = Constants.ErrorModule;
|
||||
if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(Runtime)))
|
||||
{
|
||||
typename = module.ModuleDefinition.ControlTypeTemplate;
|
||||
|
||||
// handle default action
|
||||
if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
|
||||
{
|
||||
action = module.ModuleDefinition.DefaultAction;
|
||||
}
|
||||
|
||||
// check if the module defines custom action routes
|
||||
if (module.ModuleDefinition.ControlTypeRoutes != "")
|
||||
{
|
||||
foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (route.StartsWith(action + "="))
|
||||
{
|
||||
typename = route.Replace(action + "=", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure component exists and implements IModuleControl
|
||||
module.ModuleType = "";
|
||||
if (Constants.DefaultModuleActions.Contains(action, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, action);
|
||||
}
|
||||
else
|
||||
{
|
||||
typename = typename.Replace(Constants.ActionToken, action);
|
||||
}
|
||||
Type moduletype = Type.GetType(typename, false, true); // case insensitive
|
||||
if (moduletype != null && moduletype.GetInterfaces().Contains(typeof(IModuleControl)))
|
||||
{
|
||||
module.ModuleType = Utilities.GetFullTypeName(moduletype.AssemblyQualifiedName); // get actual type name
|
||||
}
|
||||
|
||||
// get additional metadata from IModuleControl interface
|
||||
if (moduletype != null && module.ModuleType != "")
|
||||
{
|
||||
// retrieve module component resources
|
||||
var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources);
|
||||
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
||||
{
|
||||
// settings components are embedded within a framework settings module
|
||||
moduletype = Type.GetType(module.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, action), false, true);
|
||||
if (moduletype != null)
|
||||
{
|
||||
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources);
|
||||
}
|
||||
}
|
||||
|
||||
// additional metadata needed for admin components
|
||||
if (module.ModuleId == moduleid && action != "")
|
||||
{
|
||||
module.SecurityAccessLevel = moduleobject.SecurityAccessLevel;
|
||||
module.ControlTitle = moduleobject.Title;
|
||||
module.Actions = moduleobject.Actions;
|
||||
module.UseAdminContainer = moduleobject.UseAdminContainer;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure module's pane exists in current page and if not, assign it to the Admin pane
|
||||
if (page.Panes == null || page.Panes.FindIndex(item => item.Equals(module.Pane, StringComparison.OrdinalIgnoreCase)) == -1)
|
||||
{
|
||||
module.Pane = PaneNames.Admin;
|
||||
}
|
||||
|
||||
// calculate module position within pane
|
||||
if (paneindex.ContainsKey(module.Pane.ToLower()))
|
||||
{
|
||||
paneindex[module.Pane.ToLower()] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
paneindex.Add(module.Pane.ToLower(), 0);
|
||||
}
|
||||
|
||||
module.PaneModuleIndex = paneindex[module.Pane.ToLower()];
|
||||
|
||||
// container fallback
|
||||
if (string.IsNullOrEmpty(module.ContainerType))
|
||||
{
|
||||
module.ContainerType = defaultcontainertype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Module module in modules.Where(item => item.PageId == page.PageId))
|
||||
{
|
||||
if (paneindex.ContainsKey(module.Pane.ToLower()))
|
||||
{
|
||||
module.PaneModuleCount = paneindex[module.Pane.ToLower()] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (page, modules);
|
||||
}
|
||||
|
||||
private List<Resource> ManagePageResources(List<Resource> pageresources, List<Resource> resources)
|
||||
{
|
||||
if (resources != null)
|
||||
{
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
// ensure resource does not exist already
|
||||
if (pageresources.Find(item => item.Url == resource.Url) == null)
|
||||
{
|
||||
pageresources.Add(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pageresources;
|
||||
}
|
||||
|
||||
private async Task ScrollToFragment(Uri uri)
|
||||
{
|
||||
var fragment = uri.Fragment;
|
||||
if (fragment.StartsWith('#'))
|
||||
{
|
||||
// handle text fragment (https://example.org/#test:~:text=foo)
|
||||
var id = fragment.Substring(1);
|
||||
var index = id.IndexOf(":~:", StringComparison.Ordinal);
|
||||
if (index > 0)
|
||||
{
|
||||
id = id.Substring(0, index);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(id))
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.ScrollToId(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// site does not exist
|
||||
}
|
||||
}
|
||||
|
||||
private async void LocationChanged(object sender, LocationChangedEventArgs args)
|
||||
{
|
||||
_absoluteUri = args.Location;
|
||||
await Refresh();
|
||||
}
|
||||
|
||||
Task IHandleAfterRender.OnAfterRenderAsync()
|
||||
{
|
||||
if (!_navigationInterceptionEnabled)
|
||||
{
|
||||
_navigationInterceptionEnabled = true;
|
||||
return NavigationInterception.EnableNavigationInterceptionAsync();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Dictionary<string, string> ParseQueryString(string query)
|
||||
{
|
||||
Dictionary<string, string> querystring = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // case insensistive keys
|
||||
if (!string.IsNullOrEmpty(query))
|
||||
{
|
||||
if (query.StartsWith("?"))
|
||||
{
|
||||
query = query.Substring(1); // ignore "?"
|
||||
}
|
||||
foreach (string kvp in query.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (kvp != "")
|
||||
{
|
||||
if (kvp.Contains("="))
|
||||
{
|
||||
string[] pair = kvp.Split('=');
|
||||
querystring.Add(pair[0], pair[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
querystring.Add(kvp, "true"); // default parameter when no value is provided
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return querystring;
|
||||
}
|
||||
|
||||
private async Task<Page> ProcessPage(Page page, Site site, User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (page.IsPersonalizable && user != null)
|
||||
{
|
||||
// load the personalized page
|
||||
page = await PageService.GetPageAsync(page.PageId, user.UserId);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(page.ThemeType))
|
||||
{
|
||||
page.ThemeType = site.DefaultThemeType;
|
||||
}
|
||||
|
||||
page.Panes = new List<string>();
|
||||
page.Resources = new List<Resource>();
|
||||
|
||||
string panes = PaneNames.Admin;
|
||||
Type themetype = Type.GetType(page.ThemeType);
|
||||
if (themetype == null)
|
||||
{
|
||||
// fallback
|
||||
page.ThemeType = Constants.DefaultTheme;
|
||||
themetype = Type.GetType(Constants.DefaultTheme);
|
||||
}
|
||||
if (themetype != null)
|
||||
{
|
||||
var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
|
||||
if (themeobject != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(themeobject.Panes))
|
||||
{
|
||||
panes = themeobject.Panes;
|
||||
}
|
||||
page.Resources = ManagePageResources(page.Resources, themeobject.Resources);
|
||||
}
|
||||
}
|
||||
page.Panes = panes.Replace(";", ",").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// error loading theme or layout
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
private (Page Page, List<Module> Modules) ProcessModules(Page page, List<Module> modules, int moduleid, string action, string defaultcontainertype)
|
||||
{
|
||||
var paneindex = new Dictionary<string, int>();
|
||||
foreach (Module module in modules)
|
||||
{
|
||||
// initialize module control properties
|
||||
module.SecurityAccessLevel = SecurityAccessLevel.Host;
|
||||
module.ControlTitle = "";
|
||||
module.Actions = "";
|
||||
module.UseAdminContainer = false;
|
||||
module.PaneModuleIndex = -1;
|
||||
module.PaneModuleCount = 0;
|
||||
|
||||
if ((module.PageId == page.PageId || module.ModuleId == moduleid))
|
||||
{
|
||||
var typename = Constants.ErrorModule;
|
||||
if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(Runtime)))
|
||||
{
|
||||
typename = module.ModuleDefinition.ControlTypeTemplate;
|
||||
|
||||
// handle default action
|
||||
if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
|
||||
{
|
||||
action = module.ModuleDefinition.DefaultAction;
|
||||
}
|
||||
|
||||
// check if the module defines custom action routes
|
||||
if (module.ModuleDefinition.ControlTypeRoutes != "")
|
||||
{
|
||||
foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (route.StartsWith(action + "="))
|
||||
{
|
||||
typename = route.Replace(action + "=", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure component exists and implements IModuleControl
|
||||
module.ModuleType = "";
|
||||
if (Constants.DefaultModuleActions.Contains(action, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, action);
|
||||
}
|
||||
else
|
||||
{
|
||||
typename = typename.Replace(Constants.ActionToken, action);
|
||||
}
|
||||
Type moduletype = Type.GetType(typename, false, true); // case insensitive
|
||||
if (moduletype != null && moduletype.GetInterfaces().Contains(typeof(IModuleControl)))
|
||||
{
|
||||
module.ModuleType = Utilities.GetFullTypeName(moduletype.AssemblyQualifiedName); // get actual type name
|
||||
}
|
||||
|
||||
// get additional metadata from IModuleControl interface
|
||||
if (moduletype != null && module.ModuleType != "")
|
||||
{
|
||||
// retrieve module component resources
|
||||
var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources);
|
||||
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
||||
{
|
||||
// settings components are embedded within a framework settings module
|
||||
moduletype = Type.GetType(module.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, action), false, true);
|
||||
if (moduletype != null)
|
||||
{
|
||||
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources);
|
||||
}
|
||||
}
|
||||
|
||||
// additional metadata needed for admin components
|
||||
if (module.ModuleId == moduleid && action != "")
|
||||
{
|
||||
module.SecurityAccessLevel = moduleobject.SecurityAccessLevel;
|
||||
module.ControlTitle = moduleobject.Title;
|
||||
module.Actions = moduleobject.Actions;
|
||||
module.UseAdminContainer = moduleobject.UseAdminContainer;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure module's pane exists in current page and if not, assign it to the Admin pane
|
||||
if (page.Panes == null || page.Panes.FindIndex(item => item.Equals(module.Pane, StringComparison.OrdinalIgnoreCase)) == -1)
|
||||
{
|
||||
module.Pane = PaneNames.Admin;
|
||||
}
|
||||
|
||||
// calculate module position within pane
|
||||
if (paneindex.ContainsKey(module.Pane.ToLower()))
|
||||
{
|
||||
paneindex[module.Pane.ToLower()] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
paneindex.Add(module.Pane.ToLower(), 0);
|
||||
}
|
||||
|
||||
module.PaneModuleIndex = paneindex[module.Pane.ToLower()];
|
||||
|
||||
// container fallback
|
||||
if (string.IsNullOrEmpty(module.ContainerType))
|
||||
{
|
||||
module.ContainerType = defaultcontainertype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Module module in modules.Where(item => item.PageId == page.PageId))
|
||||
{
|
||||
if (paneindex.ContainsKey(module.Pane.ToLower()))
|
||||
{
|
||||
module.PaneModuleCount = paneindex[module.Pane.ToLower()] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (page, modules);
|
||||
}
|
||||
|
||||
private List<Resource> ManagePageResources(List<Resource> pageresources, List<Resource> resources)
|
||||
{
|
||||
if (resources != null)
|
||||
{
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
// ensure resource does not exist already
|
||||
if (pageresources.Find(item => item.Url == resource.Url) == null)
|
||||
{
|
||||
pageresources.Add(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pageresources;
|
||||
}
|
||||
}
|
||||
|
@ -28,32 +28,29 @@
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender)
|
||||
var interop = new Interop(JsRuntime);
|
||||
|
||||
// manage stylesheets for this page
|
||||
string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
|
||||
var links = new List<object>();
|
||||
foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet && item.Declaration != ResourceDeclaration.Global))
|
||||
{
|
||||
links.Add(new { id = "app-stylesheet-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = resource.Url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", key = "" });
|
||||
}
|
||||
if (links.Any())
|
||||
{
|
||||
await interop.IncludeLinks(links.ToArray());
|
||||
}
|
||||
await interop.RemoveElementsById("app-stylesheet", "", "app-stylesheet-" + batch + "-00");
|
||||
|
||||
// set page title
|
||||
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
||||
{
|
||||
var interop = new Interop(JsRuntime);
|
||||
|
||||
// set page title
|
||||
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
||||
{
|
||||
await interop.UpdateTitle(PageState.Page.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
await interop.UpdateTitle(PageState.Site.Name + " - " + PageState.Page.Name);
|
||||
}
|
||||
|
||||
// manage stylesheets for this page
|
||||
string batch = DateTime.Now.ToString("yyyyMMddHHmmssfff");
|
||||
var links = new List<object>();
|
||||
foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet && item.Declaration != ResourceDeclaration.Global))
|
||||
{
|
||||
links.Add(new { id = "app-stylesheet-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = resource.Url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", key = "" });
|
||||
}
|
||||
if (links.Any())
|
||||
{
|
||||
await interop.IncludeLinks(links.ToArray());
|
||||
}
|
||||
await interop.RemoveElementsById("app-stylesheet", "", "app-stylesheet-" + batch + "-00");
|
||||
await interop.UpdateTitle(PageState.Page.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
await interop.UpdateTitle(PageState.Site.Name + " - " + PageState.Page.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.0.3</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.MySQL</id>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.3</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane MySQL Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.0.3</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.PostgreSQL</id>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.3</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane PostgreSQL Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.0.3</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.SqlServer</id>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.3</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane SQL Server Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.0.1</Version>
|
||||
<Version>3.0.3</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -10,7 +10,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Database.Sqlite</id>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.3</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane SQLite Provider</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -30,6 +30,11 @@ namespace Oqtane.Database.Sqlite
|
||||
return table.Column<int>(name: name, nullable: false).Annotation("Sqlite:Autoincrement", true);
|
||||
}
|
||||
|
||||
public override void DropColumn(MigrationBuilder builder, string name, string table)
|
||||
{
|
||||
// not implemented as SQLite does not support dropping columns
|
||||
}
|
||||
|
||||
public override string ConcatenateSql(params string[] values)
|
||||
{
|
||||
var returnValue = String.Empty;
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Client</id>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.3</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Framework</id>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.3</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -11,8 +11,8 @@
|
||||
<copyright>.NET Foundation</copyright>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v3.0.1/Oqtane.Framework.3.0.1.Upgrade.zip</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v3.0.3/Oqtane.Framework.3.0.3.Upgrade.zip</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane framework</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Server</id>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.3</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Shared</id>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.3</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>Oqtane.Updater</id>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.3</version>
|
||||
<authors>Shaun Walker</authors>
|
||||
<owners>.NET Foundation</owners>
|
||||
<title>Oqtane Framework</title>
|
||||
@ -12,7 +12,7 @@
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.1</releaseNotes>
|
||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3</releaseNotes>
|
||||
<icon>icon.png</icon>
|
||||
<tags>oqtane</tags>
|
||||
</metadata>
|
||||
|
@ -1 +1 @@
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.0.1.Install.zip" -Force
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.0.3.Install.zip" -Force
|
@ -1 +1 @@
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.0.1.Upgrade.zip" -Force
|
||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net6.0\publish\*" -DestinationPath "Oqtane.Framework.3.0.3.Upgrade.zip" -Force
|
@ -19,7 +19,6 @@ using Oqtane.Extensions;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using System.Net.Http;
|
||||
|
||||
// ReSharper disable StringIndexOfIsCultureSpecific.1
|
||||
@ -508,8 +507,8 @@ namespace Oqtane.Controllers
|
||||
return System.IO.File.Exists(errorPath) ? PhysicalFile(errorPath, MimeUtilities.GetMimeType(errorPath)) : null;
|
||||
}
|
||||
|
||||
[HttpGet("image/{id}/{width}/{height}/{mode?}/{rotate?}")]
|
||||
public IActionResult GetImage(int id, int width, int height, string mode, string rotate)
|
||||
[HttpGet("image/{id}/{width}/{height}/{mode}/{position}/{background}/{rotate}/{recreate}")]
|
||||
public IActionResult GetImage(int id, int width, int height, string mode, string position, string background, string rotate, string recreate)
|
||||
{
|
||||
var file = _files.GetFile(id);
|
||||
if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions))
|
||||
@ -519,21 +518,25 @@ namespace Oqtane.Controllers
|
||||
var filepath = _files.GetFilePath(file);
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
mode = (string.IsNullOrEmpty(mode)) ? "crop" : mode;
|
||||
rotate = (string.IsNullOrEmpty(rotate)) ? "0" : rotate;
|
||||
// validation
|
||||
if (!Enum.TryParse(mode, true, out ResizeMode _)) mode = "crop";
|
||||
if (!Enum.TryParse(position, true, out AnchorPositionMode _)) position = "center";
|
||||
if (!Color.TryParseHex("#" + background, out _)) background = "000000";
|
||||
if (!int.TryParse(rotate, out _)) rotate = "0";
|
||||
rotate = (int.Parse(rotate) < 0 || int.Parse(rotate) > 360) ? "0" : rotate;
|
||||
if (!bool.TryParse(recreate, out _)) recreate = "false";
|
||||
|
||||
string imagepath = filepath.Replace(Path.GetExtension(filepath), "." + width.ToString() + "x" + height.ToString() + "." + mode.ToLower() + ".png");
|
||||
if (!System.IO.File.Exists(imagepath))
|
||||
string imagepath = filepath.Replace(Path.GetExtension(filepath), "." + width.ToString() + "x" + height.ToString() + ".png");
|
||||
if (!System.IO.File.Exists(imagepath) || bool.Parse(recreate))
|
||||
{
|
||||
if ((_userPermissions.IsAuthorized(User, PermissionNames.Edit, file.Folder.Permissions) ||
|
||||
!string.IsNullOrEmpty(file.Folder.ImageSizes) && file.Folder.ImageSizes.ToLower().Split(",").Contains(width.ToString() + "x" + height.ToString()))
|
||||
&& Enum.TryParse(mode, true, out ResizeMode resizemode))
|
||||
!string.IsNullOrEmpty(file.Folder.ImageSizes) && file.Folder.ImageSizes.ToLower().Split(",").Contains(width.ToString() + "x" + height.ToString())))
|
||||
{
|
||||
imagepath = CreateImage(filepath, width, height, resizemode.ToString(), rotate, imagepath);
|
||||
imagepath = CreateImage(filepath, width, height, mode, position, background, rotate, imagepath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Invalid Image Size For Folder Or Invalid Mode Specification {Folder} {Width} {Height} {Mode}", file.Folder, width, height, mode);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Invalid Image Size For Folder {Folder} {Width} {Height}", file.Folder, width, height);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
@ -569,35 +572,37 @@ namespace Oqtane.Controllers
|
||||
return System.IO.File.Exists(errorPath) ? PhysicalFile(errorPath, MimeUtilities.GetMimeType(errorPath)) : null;
|
||||
}
|
||||
|
||||
private string CreateImage(string filepath, int width, int height, string mode, string rotate, string imagepath)
|
||||
private string CreateImage(string filepath, int width, int height, string mode, string position, string background, string rotate, string imagepath)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileStream stream = new FileStream(filepath, FileMode.Open, FileAccess.Read);
|
||||
using (Image image = Image.Load(stream))
|
||||
using (var stream = new FileStream(filepath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
Enum.TryParse(mode, true, out ResizeMode resizemode);
|
||||
|
||||
image.Mutate(x =>
|
||||
x.Resize(new ResizeOptions
|
||||
{
|
||||
Size = new Size(width, height),
|
||||
Mode = resizemode
|
||||
})
|
||||
.BackgroundColor(new Rgba32(255, 255, 255, 0)));
|
||||
|
||||
if (rotate != "0" && int.TryParse(rotate, out int angle))
|
||||
stream.Position = 0;
|
||||
using (var image = Image.Load(stream))
|
||||
{
|
||||
image.Mutate(x => x.Rotate(angle));
|
||||
}
|
||||
int.TryParse(rotate, out int angle);
|
||||
Enum.TryParse(mode, true, out ResizeMode resizemode);
|
||||
Enum.TryParse(position, true, out AnchorPositionMode anchorpositionmode);
|
||||
|
||||
image.Save(imagepath, new PngEncoder());
|
||||
image.Mutate(x => x
|
||||
.AutoOrient() // auto orient the image
|
||||
.Rotate(angle)
|
||||
.Resize(new ResizeOptions
|
||||
{
|
||||
Mode = resizemode,
|
||||
Position = anchorpositionmode,
|
||||
Size = new Size(width, height)
|
||||
})
|
||||
.BackgroundColor(Color.ParseHex("#" + background)));
|
||||
|
||||
image.Save(imagepath, new PngEncoder());
|
||||
}
|
||||
}
|
||||
stream.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Error Creating Image For File {FilePath} {Width} {Height} {Mode} {Error}", filepath, width, height, mode, ex.Message);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Error Creating Image For File {FilePath} {Width} {Height} {Mode} {Rotate} {Error}", filepath, width, height, mode, rotate, ex.Message);
|
||||
imagepath = "";
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Job Post Attempt {Alias}", job);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Job Post Attempt {Job}", job);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
job = null;
|
||||
}
|
||||
@ -74,7 +74,7 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Job Put Attempt {Alias}", job);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Job Put Attempt {Job}", job);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
job = null;
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ namespace Oqtane.Controllers
|
||||
|
||||
module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName);
|
||||
module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, pagemodule.Module.Permissions))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
|
||||
modules.Add(module);
|
||||
@ -101,7 +102,8 @@ namespace Oqtane.Controllers
|
||||
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(module.SiteId).ToList();
|
||||
module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName);
|
||||
module.Settings = _settings.GetSettings(EntityNames.Module, id)
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, module.Permissions))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
return module;
|
||||
}
|
||||
else
|
||||
@ -171,7 +173,7 @@ namespace Oqtane.Controllers
|
||||
public void Delete(int id)
|
||||
{
|
||||
var module = _modules.GetModule(id);
|
||||
if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, module.ModuleId, PermissionNames.Edit))
|
||||
if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit))
|
||||
{
|
||||
_modules.DeleteModule(id);
|
||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId);
|
||||
|
@ -57,6 +57,7 @@ namespace Oqtane.Controllers
|
||||
if (_userPermissions.IsAuthorized(User, PermissionNames.View, page.Permissions))
|
||||
{
|
||||
page.Settings = settings.Where(item => item.EntityId == page.PageId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, page.Permissions))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
pages.Add(page);
|
||||
}
|
||||
@ -85,15 +86,16 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
page = _pages.GetPage(id, int.Parse(userid));
|
||||
}
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions))
|
||||
if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions))
|
||||
{
|
||||
page.Settings = _settings.GetSettings(EntityNames.Page, page.PageId)
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, page.Permissions))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
return page;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Page}", page);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {PageId} {UserId}", id, userid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
@ -104,24 +106,16 @@ namespace Oqtane.Controllers
|
||||
public Page Get(string path, int siteid)
|
||||
{
|
||||
Page page = _pages.GetPage(WebUtility.UrlDecode(path), siteid);
|
||||
if (page != null && page.SiteId == _alias.SiteId)
|
||||
if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, page.Permissions))
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions))
|
||||
{
|
||||
page.Settings = _settings.GetSettings(EntityNames.Page, page.PageId)
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
return page;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Page}", page);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
page.Settings = _settings.GetSettings(EntityNames.Page, page.PageId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(User, PermissionNames.Edit, page.Permissions))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
return page;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Path} for Site {SiteId}", path, siteid);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {SiteId} {Path}", siteid, path);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
@ -267,11 +261,10 @@ namespace Oqtane.Controllers
|
||||
// save url mapping if page path changed
|
||||
if (currentPage.Path != page.Path)
|
||||
{
|
||||
var url = HttpContext.Request.Scheme + "://" + _alias.Name + "/";
|
||||
var urlMapping = new UrlMapping();
|
||||
urlMapping.SiteId = page.SiteId;
|
||||
urlMapping.Url = url + currentPage.Path;
|
||||
urlMapping.MappedUrl = url + page.Path;
|
||||
urlMapping.Url = currentPage.Path;
|
||||
urlMapping.MappedUrl = page.Path;
|
||||
urlMapping.Requests = 0;
|
||||
urlMapping.CreatedOn = System.DateTime.UtcNow;
|
||||
urlMapping.RequestedOn = System.DateTime.UtcNow;
|
||||
|
@ -20,6 +20,7 @@ namespace Oqtane.Controllers
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
private readonly string _visitorCookie;
|
||||
|
||||
public SettingController(ISettingRepository settings, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
@ -29,39 +30,25 @@ namespace Oqtane.Controllers
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
_visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString();
|
||||
}
|
||||
|
||||
// GET: api/<controller>
|
||||
[HttpGet]
|
||||
public IEnumerable<Setting> Get(string entityName, int entityid)
|
||||
public IEnumerable<Setting> Get(string entityName, int entityId)
|
||||
{
|
||||
List<Setting> settings = new List<Setting>();
|
||||
if (IsAuthorized(entityName, entityid, PermissionNames.View))
|
||||
if (IsAuthorized(entityName, entityId, PermissionNames.View))
|
||||
{
|
||||
settings = _settings.GetSettings(entityName, entityid).ToList();
|
||||
|
||||
// ispublic filter
|
||||
switch (entityName)
|
||||
settings = _settings.GetSettings(entityName, entityId).ToList();
|
||||
if (FilterPrivate(entityName, entityId))
|
||||
{
|
||||
case EntityNames.Tenant:
|
||||
case EntityNames.ModuleDefinition:
|
||||
case EntityNames.Host:
|
||||
if (!User.IsInRole(RoleNames.Host))
|
||||
{
|
||||
settings = settings.Where(item => item.IsPublic).ToList();
|
||||
}
|
||||
break;
|
||||
case EntityNames.Site:
|
||||
if (!User.IsInRole(RoleNames.Admin))
|
||||
{
|
||||
settings = settings.Where(item => item.IsPublic).ToList();
|
||||
}
|
||||
break;
|
||||
settings = settings.Where(item => !item.IsPrivate).ToList();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Settings {EntityName} {EntityId}", entityName, entityid);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Settings {EntityName} {EntityId}", entityName, entityId);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
return settings;
|
||||
@ -74,30 +61,15 @@ namespace Oqtane.Controllers
|
||||
Setting setting = _settings.GetSetting(entityName, id);
|
||||
if (IsAuthorized(setting.EntityName, setting.EntityId, PermissionNames.View))
|
||||
{
|
||||
// ispublic filter
|
||||
switch (entityName)
|
||||
if (FilterPrivate(entityName, id) && setting.IsPrivate)
|
||||
{
|
||||
case EntityNames.Tenant:
|
||||
case EntityNames.ModuleDefinition:
|
||||
case EntityNames.Host:
|
||||
if (!User.IsInRole(RoleNames.Host) && !setting.IsPublic)
|
||||
{
|
||||
setting = null;
|
||||
}
|
||||
break;
|
||||
case EntityNames.Site:
|
||||
if (!User.IsInRole(RoleNames.Admin) && !setting.IsPublic)
|
||||
{
|
||||
setting = null;
|
||||
}
|
||||
break;
|
||||
setting = null;
|
||||
}
|
||||
|
||||
return setting;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Setting {Setting}", setting);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Setting {EntityName} {SettingId}", entityName, id);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
@ -204,20 +176,67 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
break;
|
||||
case EntityNames.Visitor:
|
||||
var visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString();
|
||||
if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId))
|
||||
authorized = User.IsInRole(RoleNames.Admin);
|
||||
if (!authorized)
|
||||
{
|
||||
authorized = (visitorId == entityId);
|
||||
if (int.TryParse(Request.Cookies[_visitorCookie], out int visitorId))
|
||||
{
|
||||
authorized = (visitorId == entityId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: // custom entity
|
||||
if (permissionName == PermissionNames.Edit)
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Admin) || _userPermissions.IsAuthorized(User, entityName, entityId, permissionName);
|
||||
}
|
||||
else
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Admin);
|
||||
authorized = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return authorized;
|
||||
}
|
||||
|
||||
private bool FilterPrivate(string entityName, int entityId)
|
||||
{
|
||||
bool filter = false;
|
||||
switch (entityName)
|
||||
{
|
||||
case EntityNames.Tenant:
|
||||
case EntityNames.ModuleDefinition:
|
||||
case EntityNames.Host:
|
||||
filter = !User.IsInRole(RoleNames.Host);
|
||||
break;
|
||||
case EntityNames.Site:
|
||||
filter = !User.IsInRole(RoleNames.Admin);
|
||||
break;
|
||||
case EntityNames.Page:
|
||||
case EntityNames.Module:
|
||||
case EntityNames.Folder:
|
||||
filter = !_userPermissions.IsAuthorized(User, entityName, entityId, PermissionNames.Edit);
|
||||
break;
|
||||
case EntityNames.User:
|
||||
filter = !User.IsInRole(RoleNames.Admin) && _userPermissions.GetUser(User).UserId != entityId;
|
||||
break;
|
||||
case EntityNames.Visitor:
|
||||
if (!User.IsInRole(RoleNames.Admin))
|
||||
{
|
||||
filter = true;
|
||||
if (int.TryParse(Request.Cookies[_visitorCookie], out int visitorId))
|
||||
{
|
||||
filter = (visitorId != entityId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: // custom entity
|
||||
filter = !User.IsInRole(RoleNames.Admin) && !_userPermissions.IsAuthorized(User, entityName, entityId, PermissionNames.Edit);
|
||||
break;
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
private void AddSyncEvent(string EntityName)
|
||||
{
|
||||
switch (EntityName)
|
||||
|
@ -44,12 +44,9 @@ namespace Oqtane.Controllers
|
||||
var site = _sites.GetSite(id);
|
||||
if (site.SiteId == _alias.SiteId)
|
||||
{
|
||||
var settings = _settings.GetSettings(EntityNames.Site, site.SiteId);
|
||||
if (!User.IsInRole(RoleNames.Admin))
|
||||
{
|
||||
settings = settings.Where(item => item.IsPublic);
|
||||
}
|
||||
site.Settings = settings.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
site.Settings = _settings.GetSettings(EntityNames.Site, site.SiteId)
|
||||
.Where(item => !item.IsPrivate || User.IsInRole(RoleNames.Admin))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
return site;
|
||||
}
|
||||
else
|
||||
|
@ -31,7 +31,7 @@ namespace Oqtane.Controllers
|
||||
systeminfo.Add("osversion", Environment.OSVersion.ToString());
|
||||
systeminfo.Add("machinename", Environment.MachineName);
|
||||
systeminfo.Add("serverpath", _environment.ContentRootPath);
|
||||
systeminfo.Add("servertime", DateTime.Now.ToString());
|
||||
systeminfo.Add("servertime", DateTime.UtcNow.ToString());
|
||||
systeminfo.Add("installationid", _configManager.GetInstallationId());
|
||||
|
||||
systeminfo.Add("runtime", _configManager.GetSetting("Runtime", "Server"));
|
||||
|
@ -48,7 +48,7 @@ namespace Oqtane.Controllers
|
||||
public UrlMapping Get(int id)
|
||||
{
|
||||
var urlMapping = _urlMappings.GetUrlMapping(id);
|
||||
if (urlMapping != null && (urlMapping.SiteId == _alias.SiteId))
|
||||
if (urlMapping != null && urlMapping.SiteId == _alias.SiteId)
|
||||
{
|
||||
return urlMapping;
|
||||
}
|
||||
@ -60,6 +60,23 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
// GET api/<controller>/url/x?url=y
|
||||
[HttpGet("url/{siteid}")]
|
||||
public UrlMapping Get(int siteid, string url)
|
||||
{
|
||||
var urlMapping = _urlMappings.GetUrlMapping(siteid, WebUtility.UrlDecode(url));
|
||||
if (urlMapping != null && urlMapping.SiteId == _alias.SiteId)
|
||||
{
|
||||
return urlMapping;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UrlMapping Get Attempt {SiteId} {Url}", siteid, url);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
|
@ -389,7 +389,7 @@ namespace Oqtane.Controllers
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
||||
if (identityuser != null)
|
||||
if (identityuser != null && !string.IsNullOrEmpty(token))
|
||||
{
|
||||
var result = await _identityUserManager.ConfirmEmailAsync(identityuser, token);
|
||||
if (result.Succeeded)
|
||||
@ -398,13 +398,13 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Email Verification Failed For {Username}", user.Username);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Email Verification Failed For {Username} - Error {Error}", user.Username, result.Errors.ToString());
|
||||
user = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Email Verification Failed For {Username}", user.Username);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Email Verification Failed For {Username}And Token {Token}", user.Username, token);
|
||||
user = null;
|
||||
}
|
||||
}
|
||||
@ -420,9 +420,14 @@ namespace Oqtane.Controllers
|
||||
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
||||
if (identityuser != null)
|
||||
{
|
||||
user = _users.GetUser(user.Username);
|
||||
string token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityuser);
|
||||
string url = HttpContext.Request.Scheme + "://" + _alias.Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string body = "Dear " + user.DisplayName + ",\n\nPlease Click The Link Displayed Below To Reset Your Password:\n\n" + url + "\n\nThank You!";
|
||||
string body = "Dear " + user.DisplayName + ",\n\nYou recently requested to reset your password. Please use the link below to complete the process:\n\n" + url +
|
||||
"\n\nPlease note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site." +
|
||||
"\n\nIf you did not request to reset your password you can safely ignore this message." +
|
||||
"\n\nThank You!";
|
||||
|
||||
var notification = new Notification(user.SiteId, null, user, "User Password Reset", body, null);
|
||||
_notifications.AddNotification(notification);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Security, "Password Reset Notification Sent For {Username}", user.Username);
|
||||
@ -451,13 +456,13 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Password Reset Failed For {Username}", user.Username);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Password Reset Failed For {Username} - Error {Error}", user.Username, result.Errors.ToString());
|
||||
user = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Password Reset Failed For {Username}", user.Username);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Password Reset Failed For {Username} And Token {Token}", user.Username, token);
|
||||
user = null;
|
||||
}
|
||||
}
|
||||
|
@ -47,15 +47,14 @@ namespace Oqtane.Controllers
|
||||
[HttpGet("{id}")]
|
||||
public Visitor Get(int id)
|
||||
{
|
||||
bool authorized;
|
||||
var visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString();
|
||||
if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId))
|
||||
bool authorized = User.IsInRole(RoleNames.Admin);
|
||||
if (!authorized)
|
||||
{
|
||||
authorized = (visitorId == id);
|
||||
}
|
||||
else
|
||||
{
|
||||
authorized = User.IsInRole(RoleNames.Admin);
|
||||
var visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString();
|
||||
if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId))
|
||||
{
|
||||
authorized = (visitorId == id);
|
||||
}
|
||||
}
|
||||
|
||||
var visitor = _visitors.GetVisitor(id);
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
@ -75,6 +76,11 @@ namespace Oqtane.Databases
|
||||
|
||||
}
|
||||
|
||||
public virtual void DropColumn(MigrationBuilder builder, string name, string table)
|
||||
{
|
||||
builder.DropColumn(name, table);
|
||||
}
|
||||
|
||||
public abstract DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user