allow host username to be specified during installation, allow user to be added to host role, refresh user list after delete, improve date/time entry in scheduled jobs, require license acceptance during module and theme install

This commit is contained in:
Shaun Walker
2021-08-06 12:59:56 -04:00
parent 5c42e8e5bc
commit e4201c1a4d
22 changed files with 390 additions and 215 deletions

View File

@ -31,7 +31,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="runs-every" HelpText="Select how often you want the job to run" ResourceKey="RunsEvery">Runs Every: </Label>
<div class="col-sm-9">
<input id="runs-every" class="form-control" @bind="@_interval" maxlength="4" required/>
<input id="runs-every" class="form-control" @bind="@_interval" maxlength="4" required />
<select id="runs-every" class="form-select" @bind="@_frequency" required>
<option value="m">@Localizer["Minute(s)"]</option>
<option value="H">@Localizer["Hour(s)"]</option>
@ -40,18 +40,6 @@
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="starting" HelpText="What time do you want the job to start" ResourceKey="Starting">Starting: </Label>
<div class="col-sm-9">
<input id="starting" class="form-control" @bind="@_startDate" maxlength="8"/>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="ending" HelpText="When do you want the job to end" ResourceKey="Ending">Ending: </Label>
<div class="col-sm-9">
<input id="ending" class="form-control" @bind="@_endDate" maxlength="8"/>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="retention" HelpText="Number of log entries to retain for this job" ResourceKey="RetentionLog">Retention Log (Items): </Label>
<div class="col-sm-9">
@ -59,9 +47,42 @@
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="next" HelpText="Next execution for this job." ResourceKey="NextExecution">Next Execution: </Label>
<Label Class="col-sm-3" For="starting" HelpText="Optionally enter the date and time when this job should start executing" ResourceKey="Starting">Starting: </Label>
<div class="col-sm-9">
<input id="next" class="form-control" @bind="@_nextExecution" maxlength="8"/>
<div class="row">
<div class="col">
<input id="starting" type="date" class="form-control" @bind="@_startDate" />
</div>
<div class="col">
<input id="starting" type="text" class="form-control" placeholder="hh:mm" @bind="@_startTime" />
</div>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="ending" HelpText="Optionally enter the date and time when this job should stop executing" ResourceKey="Ending">Ending: </Label>
<div class="col-sm-9">
<div class="row">
<div class="col">
<input id="ending" type="date" class="form-control" @bind="@_endDate" />
</div>
<div class="col">
<input id="ending" type="text" class="form-control" placeholder="hh:mm" @bind="@_endTime" />
</div>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="next" HelpText="Optionally modify the date and time when this job should execute next" ResourceKey="NextExecution">Next Execution: </Label>
<div class="col-sm-9">
<div class="row">
<div class="col">
<input id="next" type="date" class="form-control" @bind="@_nextDate" />
</div>
<div class="col">
<input id="next" type="text" class="form-control" placeholder="hh:mm" @bind="@_nextTime" />
</div>
</div>
</div>
</div>
</div>
@ -82,10 +103,13 @@
private string _isEnabled = "True";
private string _interval = string.Empty;
private string _frequency = string.Empty;
private string _startDate = string.Empty;
private string _endDate = 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 string _nextExecution = string.Empty;
private DateTime? _nextDate = null;
private string _nextTime = string.Empty;
private string createdby;
private DateTime createdon;
private string modifiedby;
@ -106,10 +130,22 @@
_isEnabled = job.IsEnabled.ToString();
_interval = job.Interval.ToString();
_frequency = job.Frequency;
_startDate = (job.StartDate != null) ? job.StartDate.ToString() : string.Empty;
_endDate = (job.EndDate != null) ? job.EndDate.ToString() : string.Empty;
_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();
_nextExecution = job.NextExecution.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;
@ -135,35 +171,34 @@
job.IsEnabled = Boolean.Parse(_isEnabled);
job.Frequency = _frequency;
job.Interval = int.Parse(_interval);
if (_startDate == string.Empty)
job.StartDate = _startDate;
if (job.StartDate != null)
{
job.StartDate = null;
job.StartDate = job.StartDate.Value.Date;
if (!string.IsNullOrEmpty(_startTime))
{
job.StartDate = DateTime.Parse(job.StartDate.Value.ToShortDateString() + " " + _startTime);
}
}
else
job.EndDate = _endDate;
if (job.EndDate != null)
{
job.StartDate = DateTime.Parse(_startDate);
job.EndDate = job.EndDate.Value.Date;
if (!string.IsNullOrEmpty(_endTime))
{
job.EndDate = DateTime.Parse(job.EndDate.Value.ToShortDateString() + " " + _endTime);
}
}
if (_endDate == string.Empty)
{
job.EndDate = null;
}
else
{
job.EndDate = DateTime.Parse(_endDate);
}
if (_nextExecution == string.Empty)
{
job.NextExecution = null;
}
else
{
job.NextExecution = DateTime.Parse(_nextExecution);
}
job.RetentionHistory = int.Parse(_retentionHistory);
job.NextExecution = _nextDate;
if (job.NextExecution != null)
{
job.NextExecution = job.NextExecution.Value.Date;
if (!string.IsNullOrEmpty(_nextTime))
{
job.NextExecution = DateTime.Parse(job.NextExecution.Value.ToShortDateString() + " " + _nextTime);
}
}
try
{

View File

@ -10,17 +10,14 @@
<TabStrip>
<TabPanel Name="Download" ResourceKey="Download">
<ModuleMessage Type="MessageType.Info" Message="Download one or more modules from the list below. Once you are ready click Install to complete the installation."></ModuleMessage>
<div class="container">
<div class="row mb-1 align-items-center">
<div class="col-3"></div>
<div class="col-sm-4">
<div class="row justify-content-center mb-3">
<div class="col-sm-6">
<div class="input-group">
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
</div>
<div class="col-sm-2">
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>&nbsp;
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
</div>
<div class="col-3"></div>
</div>
</div>
@ -36,7 +33,7 @@
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"]&nbsp;&nbsp;|&nbsp;&nbsp; @SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong>&nbsp;&nbsp;|&nbsp;&nbsp;@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>&nbsp;&nbsp;|&nbsp;&nbsp;@SharedLocalizer["Search.Source"]: <strong>@context.PackageUrl</strong>
</td>
<td style="vertical-align: middle;">
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadModule(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
</td>
</Row>
</Pager>
@ -62,12 +59,48 @@
</TabPanel>
</TabStrip>
@if (_productname != "")
{
<div class="app-actiondialog">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@_productname @Localizer["License Terms"]</h5>
<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
</div>
<div class="modal-body">
<p style="height: 200px; overflow-y: scroll;">
@if (!string.IsNullOrEmpty(_license))
{
@_license
}
else
{
@Localizer["License Not Specified"]
}
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@Localizer["Accept"]</button>
<button type="button" class="btn btn-secondary" @onclick="HideModal">@Localizer["Cancel"]</button>
</div>
</div>
</div>
</div>
</div>
}
<button type="button" class="btn btn-success" @onclick="InstallModules">@SharedLocalizer["Install"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
@code {
private List<Package> _packages;
private string _search = "";
private string _productname = "";
private string _license = "";
private string _packageid = "";
private string _version = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
@ -126,6 +159,52 @@
}
}
private void HideModal()
{
_productname = "";
_license = "";
StateHasChanged();
}
private async Task GetPackage(string packageid, string version)
{
try
{
var package = await PackageService.GetPackageAsync(packageid, version);
if (package != null)
{
_productname = package.Name;
_license = package.License;
_packageid = package.PackageId;
_version = package.Version;
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packageid, version);
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
}
}
private async Task DownloadPackage()
{
try
{
await PackageService.DownloadPackageAsync(_packageid, _version, "Packages");
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
AddModuleMessage(Localizer["Success.Module.Download"], MessageType.Success);
_productname = "";
_license = "";
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packageid, _version);
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
}
}
private async Task InstallModules()
{
try
@ -138,20 +217,4 @@
await logger.LogError(ex, "Error Installing Module");
}
}
private async Task DownloadModule(string packageid, string version)
{
try
{
await PackageService.DownloadPackageAsync(packageid, version, "Packages");
await logger.LogInformation("Module {ModuleDefinitionName} {Version} Downloaded Successfully", packageid, version);
AddModuleMessage(Localizer["Success.Module.Download"], MessageType.Success);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Module {ModuleDefinitionName} {Version}", packageid, version);
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
}
}
}

View File

@ -61,7 +61,7 @@ else
<td>@context.EffectiveDate</td>
<td>@context.ExpiryDate</td>
<td>
<ActionDialog Header="Remove User" Message="@string.Format(Localizer["Confirm.User.DeleteRole"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || PageState.User.Username == UserNames.Host)" ResourceKey="DeleteUserRole" />
<ActionDialog Header="Remove User" Message="@string.Format(Localizer["Confirm.User.DeleteRole"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@context.Role.IsAutoAssigned" ResourceKey="DeleteUserRole" />
</td>
</Row>
</Pager>

View File

@ -128,13 +128,13 @@ else
@DatabaseConfigComponent;
}
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="hostUsername" HelpText="Enter the username of the host for this site" ResourceKey="HostUsername">Host Username:</Label>
<Label Class="col-sm-3" For="hostUsername" HelpText="Enter a valid host username" ResourceKey="HostUsername">Host Username:</Label>
<div class="col-sm-9">
<input id="hostUsername" class="form-control" @bind="@_hostUserName" readonly />
<input id="hostUsername" class="form-control" @bind="@_hostusername" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="hostPassword" HelpText="Enter the password for the host of this site" ResourceKey="HostPassword">Host Password:</Label>
<Label Class="col-sm-3" For="hostPassword" HelpText="Enter a valid host password" ResourceKey="HostPassword">Host Password:</Label>
<div class="col-sm-9">
<input id="hostPassword" type="password" class="form-control" @bind="@_hostpassword" />
</div>
@ -164,7 +164,7 @@ else
private string _tenantName = string.Empty;
private string _hostUserName = UserNames.Host;
private string _hostusername = string.Empty;
private string _hostpassword = string.Empty;
private string _name = string.Empty;
@ -275,7 +275,7 @@ else
// validate host credentials
var user = new User();
user.SiteId = PageState.Site.SiteId;
user.Username = UserNames.Host;
user.Username = _hostusername;
user.Password = _hostpassword;
user = await UserService.LoginUserAsync(user, false, false);
if (user.IsAuthenticated)
@ -292,8 +292,9 @@ else
config.TenantName = _tenantName;
config.DatabaseType = database.DBType;
config.ConnectionString = connectionString;
config.HostEmail = user.Email;
config.HostUsername = _hostusername;
config.HostPassword = _hostpassword;
config.HostEmail = user.Email;
config.HostName = user.DisplayName;
config.IsNewTenant = true;
}

View File

@ -10,25 +10,17 @@
<TabStrip>
<TabPanel Name="Download" ResourceKey="Download">
<ModuleMessage Type="MessageType.Info" Message="Download one or more themes from the list below. Once you are ready click Install to complete the installation."></ModuleMessage>
<div class="container">
<div class="row mb-1 align-items-center">
<div class="col-sm-3">
</div>
<div class="col-sm-4">
<div class="row justify-content-center mb-3">
<div class="col-sm-6">
<div class="input-group">
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
</div>
<div class="col-sm-2">
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>&nbsp;
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
</div>
<div class="col-sm-3">
</div>
</div>
</div>
@if (_packages != null)
{
if (_packages.Count > 0)
@ -41,7 +33,7 @@
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"]&nbsp;&nbsp;|&nbsp;&nbsp; @SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong>&nbsp;&nbsp;|&nbsp;&nbsp;@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>&nbsp;&nbsp;|&nbsp;&nbsp;@SharedLocalizer["Search.Source"]: <strong>@context.PackageUrl</strong>
</td>
<td style="vertical-align: middle;">
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadTheme(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
</td>
</Row>
</Pager>
@ -68,12 +60,48 @@
</TabPanel>
</TabStrip>
@if (_productname != "")
{
<div class="app-actiondialog">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@_productname @Localizer["License Terms"]</h5>
<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
</div>
<div class="modal-body">
<p style="height: 200px; overflow-y: scroll;">
@if (!string.IsNullOrEmpty(_license))
{
@_license
}
else
{
@Localizer["License Not Specified"]
}
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@Localizer["Accept"]</button>
<button type="button" class="btn btn-secondary" @onclick="HideModal">@Localizer["Cancel"]</button>
</div>
</div>
</div>
</div>
</div>
}
<button type="button" class="btn btn-success" @onclick="InstallThemes">@SharedLocalizer["Install"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
@code {
private List<Package> _packages;
private string _search = "";
private string _productname = "";
private string _license = "";
private string _packageid = "";
private string _version = "";
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
@ -132,6 +160,52 @@
}
}
private void HideModal()
{
_productname = "";
_license = "";
StateHasChanged();
}
private async Task GetPackage(string packageid, string version)
{
try
{
var package = await PackageService.GetPackageAsync(packageid, version);
if (package != null)
{
_productname = package.Name;
_license = package.License;
_packageid = package.PackageId;
_version = package.Version;
}
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packageid, version);
AddModuleMessage(Localizer["Error.Theme.Download"], MessageType.Error);
}
}
private async Task DownloadPackage()
{
try
{
await PackageService.DownloadPackageAsync(_packageid, _version, "Packages");
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
AddModuleMessage(Localizer["Success.Theme.Download"], MessageType.Success);
_productname = "";
_license = "";
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packageid, _version);
AddModuleMessage(Localizer["Error.Theme.Download"], MessageType.Error);
}
}
private async Task InstallThemes()
{
try
@ -144,20 +218,4 @@
await logger.LogError(ex, "Error Installing Theme");
}
}
private async Task DownloadTheme(string packageid, string version)
{
try
{
await PackageService.DownloadPackageAsync(packageid, version, "Packages");
await logger.LogInformation("Theme {ThemeName} {Version} Downloaded Successfully", packageid, version);
AddModuleMessage(Localizer["Success.Theme.Download"], MessageType.Success);
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Downloading Module {ThemeName} {Version}", packageid, version);
AddModuleMessage(Localizer["Error.Theme.Download"], MessageType.Error);
}
}
}

View File

@ -39,7 +39,7 @@ else
<ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="EditUser" />
</td>
<td>
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.Role.Name == RoleNames.Host)" ResourceKey="DeleteUser" />
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId)" ResourceKey="DeleteUser" />
</td>
<td>
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="Roles" />
@ -95,6 +95,8 @@ else
{
await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId);
await logger.LogInformation("User Deleted {User}", UserRole.User);
allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
userroles = Search(_search);
StateHasChanged();
}
}