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:
parent
5c42e8e5bc
commit
e4201c1a4d
@ -54,13 +54,13 @@
|
|||||||
<h2>@Localizer["ApplicationAdmin"]</h2><br />
|
<h2>@Localizer["ApplicationAdmin"]</h2><br />
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="username" HelpText="The username of the host user account (this is not customizable)" ResourceKey="Username">Username:</Label>
|
<Label Class="col-sm-3" For="username" HelpText="Provide a username for the primary user accountt" ResourceKey="Username">Username:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="username" type="text" class="form-control" @bind="@_hostUsername" readonly />
|
<input id="username" type="text" class="form-control" @bind="@_hostUsername" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="password" HelpText="Provide the password for the host user account" ResourceKey="Password">Password:</Label>
|
<Label Class="col-sm-3" For="password" HelpText="Provide a password for the primary user account" ResourceKey="Password">Password:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="password" type="password" class="form-control" @bind="@_hostPassword" />
|
<input id="password" type="password" class="form-control" @bind="@_hostPassword" />
|
||||||
</div>
|
</div>
|
||||||
@ -102,7 +102,7 @@
|
|||||||
private object _databaseConfig;
|
private object _databaseConfig;
|
||||||
private RenderFragment DatabaseConfigComponent { get; set; }
|
private RenderFragment DatabaseConfigComponent { get; set; }
|
||||||
|
|
||||||
private string _hostUsername = UserNames.Host;
|
private string _hostUsername = string.Empty;
|
||||||
private string _hostPassword = string.Empty;
|
private string _hostPassword = string.Empty;
|
||||||
private string _confirmPassword = string.Empty;
|
private string _confirmPassword = string.Empty;
|
||||||
private string _hostEmail = string.Empty;
|
private string _hostEmail = string.Empty;
|
||||||
@ -162,7 +162,7 @@
|
|||||||
connectionString = databaseConfigControl.GetConnectionString();
|
connectionString = databaseConfigControl.GetConnectionString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionString != "" && _hostUsername != "" && _hostPassword.Length >= 6 && _hostPassword == _confirmPassword && _hostEmail != "" && _hostEmail.Contains("@"))
|
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && _hostPassword.Length >= 6 && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@"))
|
||||||
{
|
{
|
||||||
_loadingDisplay = "";
|
_loadingDisplay = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
@ -176,9 +176,10 @@
|
|||||||
DatabaseType = database.DBType,
|
DatabaseType = database.DBType,
|
||||||
ConnectionString = connectionString,
|
ConnectionString = connectionString,
|
||||||
Aliases = uri.Authority,
|
Aliases = uri.Authority,
|
||||||
HostEmail = _hostEmail,
|
HostUsername = _hostUsername,
|
||||||
HostPassword = _hostPassword,
|
HostPassword = _hostPassword,
|
||||||
HostName = UserNames.Host,
|
HostEmail = _hostEmail,
|
||||||
|
HostName = _hostUsername,
|
||||||
TenantName = TenantNames.Master,
|
TenantName = TenantNames.Master,
|
||||||
IsNewTenant = true,
|
IsNewTenant = true,
|
||||||
SiteName = Constants.DefaultSite,
|
SiteName = Constants.DefaultSite,
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<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>
|
<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">
|
<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>
|
<select id="runs-every" class="form-select" @bind="@_frequency" required>
|
||||||
<option value="m">@Localizer["Minute(s)"]</option>
|
<option value="m">@Localizer["Minute(s)"]</option>
|
||||||
<option value="H">@Localizer["Hour(s)"]</option>
|
<option value="H">@Localizer["Hour(s)"]</option>
|
||||||
@ -40,18 +40,6 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<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>
|
<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">
|
<div class="col-sm-9">
|
||||||
@ -59,9 +47,42 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<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">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -82,10 +103,13 @@
|
|||||||
private string _isEnabled = "True";
|
private string _isEnabled = "True";
|
||||||
private string _interval = string.Empty;
|
private string _interval = string.Empty;
|
||||||
private string _frequency = string.Empty;
|
private string _frequency = string.Empty;
|
||||||
private string _startDate = string.Empty;
|
private DateTime? _startDate = null;
|
||||||
private string _endDate = string.Empty;
|
private string _startTime = string.Empty;
|
||||||
|
private DateTime? _endDate = null;
|
||||||
|
private string _endTime = string.Empty;
|
||||||
private string _retentionHistory = 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 string createdby;
|
||||||
private DateTime createdon;
|
private DateTime createdon;
|
||||||
private string modifiedby;
|
private string modifiedby;
|
||||||
@ -106,10 +130,22 @@
|
|||||||
_isEnabled = job.IsEnabled.ToString();
|
_isEnabled = job.IsEnabled.ToString();
|
||||||
_interval = job.Interval.ToString();
|
_interval = job.Interval.ToString();
|
||||||
_frequency = job.Frequency;
|
_frequency = job.Frequency;
|
||||||
_startDate = (job.StartDate != null) ? job.StartDate.ToString() : string.Empty;
|
_startDate = job.StartDate;
|
||||||
_endDate = (job.EndDate != null) ? job.EndDate.ToString() : string.Empty;
|
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();
|
_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;
|
createdby = job.CreatedBy;
|
||||||
createdon = job.CreatedOn;
|
createdon = job.CreatedOn;
|
||||||
modifiedby = job.ModifiedBy;
|
modifiedby = job.ModifiedBy;
|
||||||
@ -135,35 +171,34 @@
|
|||||||
job.IsEnabled = Boolean.Parse(_isEnabled);
|
job.IsEnabled = Boolean.Parse(_isEnabled);
|
||||||
job.Frequency = _frequency;
|
job.Frequency = _frequency;
|
||||||
job.Interval = int.Parse(_interval);
|
job.Interval = int.Parse(_interval);
|
||||||
|
job.StartDate = _startDate;
|
||||||
if (_startDate == string.Empty)
|
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.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
|
try
|
||||||
{
|
{
|
||||||
|
@ -10,17 +10,14 @@
|
|||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Download" ResourceKey="Download">
|
<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>
|
<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="row justify-content-center mb-3">
|
||||||
<div class="col-3"></div>
|
<div class="col-sm-6">
|
||||||
<div class="col-sm-4">
|
<div class="input-group">
|
||||||
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
||||||
</div>
|
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||||
<div class="col-sm-2">
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -36,7 +33,7 @@
|
|||||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] | @SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> | @SharedLocalizer["Search.Version"]: <strong>@context.Version</strong> | @SharedLocalizer["Search.Source"]: <strong>@context.PackageUrl</strong>
|
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] | @SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> | @SharedLocalizer["Search.Version"]: <strong>@context.Version</strong> | @SharedLocalizer["Search.Source"]: <strong>@context.PackageUrl</strong>
|
||||||
</td>
|
</td>
|
||||||
<td style="vertical-align: middle;">
|
<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>
|
</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
@ -62,12 +59,48 @@
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabStrip>
|
</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>
|
<button type="button" class="btn btn-success" @onclick="InstallModules">@SharedLocalizer["Install"]</button>
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
private string _search = "";
|
private string _search = "";
|
||||||
|
private string _productname = "";
|
||||||
|
private string _license = "";
|
||||||
|
private string _packageid = "";
|
||||||
|
private string _version = "";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
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()
|
private async Task InstallModules()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -138,20 +217,4 @@
|
|||||||
await logger.LogError(ex, "Error Installing Module");
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ else
|
|||||||
<td>@context.EffectiveDate</td>
|
<td>@context.EffectiveDate</td>
|
||||||
<td>@context.ExpiryDate</td>
|
<td>@context.ExpiryDate</td>
|
||||||
<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>
|
</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
|
@ -128,13 +128,13 @@ else
|
|||||||
@DatabaseConfigComponent;
|
@DatabaseConfigComponent;
|
||||||
}
|
}
|
||||||
<div class="row mb-1 align-items-center">
|
<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">
|
<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>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<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">
|
<div class="col-sm-9">
|
||||||
<input id="hostPassword" type="password" class="form-control" @bind="@_hostpassword" />
|
<input id="hostPassword" type="password" class="form-control" @bind="@_hostpassword" />
|
||||||
</div>
|
</div>
|
||||||
@ -164,7 +164,7 @@ else
|
|||||||
|
|
||||||
private string _tenantName = string.Empty;
|
private string _tenantName = string.Empty;
|
||||||
|
|
||||||
private string _hostUserName = UserNames.Host;
|
private string _hostusername = string.Empty;
|
||||||
private string _hostpassword = string.Empty;
|
private string _hostpassword = string.Empty;
|
||||||
|
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
@ -275,7 +275,7 @@ else
|
|||||||
// validate host credentials
|
// validate host credentials
|
||||||
var user = new User();
|
var user = new User();
|
||||||
user.SiteId = PageState.Site.SiteId;
|
user.SiteId = PageState.Site.SiteId;
|
||||||
user.Username = UserNames.Host;
|
user.Username = _hostusername;
|
||||||
user.Password = _hostpassword;
|
user.Password = _hostpassword;
|
||||||
user = await UserService.LoginUserAsync(user, false, false);
|
user = await UserService.LoginUserAsync(user, false, false);
|
||||||
if (user.IsAuthenticated)
|
if (user.IsAuthenticated)
|
||||||
@ -292,8 +292,9 @@ else
|
|||||||
config.TenantName = _tenantName;
|
config.TenantName = _tenantName;
|
||||||
config.DatabaseType = database.DBType;
|
config.DatabaseType = database.DBType;
|
||||||
config.ConnectionString = connectionString;
|
config.ConnectionString = connectionString;
|
||||||
config.HostEmail = user.Email;
|
config.HostUsername = _hostusername;
|
||||||
config.HostPassword = _hostpassword;
|
config.HostPassword = _hostpassword;
|
||||||
|
config.HostEmail = user.Email;
|
||||||
config.HostName = user.DisplayName;
|
config.HostName = user.DisplayName;
|
||||||
config.IsNewTenant = true;
|
config.IsNewTenant = true;
|
||||||
}
|
}
|
||||||
|
@ -10,25 +10,17 @@
|
|||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Download" ResourceKey="Download">
|
<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>
|
<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="row justify-content-center mb-3">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-6">
|
||||||
|
<div class="input-group">
|
||||||
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
||||||
</div>
|
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||||
<div class="col-sm-2">
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@if (_packages != null)
|
@if (_packages != null)
|
||||||
{
|
{
|
||||||
if (_packages.Count > 0)
|
if (_packages.Count > 0)
|
||||||
@ -41,7 +33,7 @@
|
|||||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] | @SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> | @SharedLocalizer["Search.Version"]: <strong>@context.Version</strong> | @SharedLocalizer["Search.Source"]: <strong>@context.PackageUrl</strong>
|
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] | @SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> | @SharedLocalizer["Search.Version"]: <strong>@context.Version</strong> | @SharedLocalizer["Search.Source"]: <strong>@context.PackageUrl</strong>
|
||||||
</td>
|
</td>
|
||||||
<td style="vertical-align: middle;">
|
<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>
|
</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
@ -68,12 +60,48 @@
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabStrip>
|
</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>
|
<button type="button" class="btn btn-success" @onclick="InstallThemes">@SharedLocalizer["Install"]</button>
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
private string _search = "";
|
private string _search = "";
|
||||||
|
private string _productname = "";
|
||||||
|
private string _license = "";
|
||||||
|
private string _packageid = "";
|
||||||
|
private string _version = "";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
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()
|
private async Task InstallThemes()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -144,20 +218,4 @@
|
|||||||
await logger.LogError(ex, "Error Installing Theme");
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ else
|
|||||||
<ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="EditUser" />
|
<ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="EditUser" />
|
||||||
</td>
|
</td>
|
||||||
<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>
|
||||||
<td>
|
<td>
|
||||||
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="Roles" />
|
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="Roles" />
|
||||||
@ -95,6 +95,8 @@ else
|
|||||||
{
|
{
|
||||||
await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId);
|
await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId);
|
||||||
await logger.LogInformation("User Deleted {User}", UserRole.User);
|
await logger.LogInformation("User Deleted {User}", UserRole.User);
|
||||||
|
allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
|
||||||
|
userroles = Search(_search);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@namespace Oqtane.Modules.HtmlText
|
@namespace Oqtane.Modules.HtmlText
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject IHtmlTextService HtmlTextService
|
@inject IHtmlTextService HtmlTextService
|
||||||
@inject IStringLocalizer<Edit> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
|
||||||
@((MarkupString)content)
|
@((MarkupString)content)
|
||||||
|
|
||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
@code {
|
@code {
|
||||||
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 = ModulePath() + "Module.css" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -154,13 +154,13 @@
|
|||||||
<value>Email:</value>
|
<value>Email:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Password.HelpText" xml:space="preserve">
|
<data name="Password.HelpText" xml:space="preserve">
|
||||||
<value>Provide the password for the host user account</value>
|
<value>Provide a password for the primary user account</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Password.Text" xml:space="preserve">
|
<data name="Password.Text" xml:space="preserve">
|
||||||
<value>Password:</value>
|
<value>Password:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Username.HelpText" xml:space="preserve">
|
<data name="Username.HelpText" xml:space="preserve">
|
||||||
<value>The username of the host user account (this is not customizable)</value>
|
<value>Provide a username for the primary user account</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Username.Text" xml:space="preserve">
|
<data name="Username.Text" xml:space="preserve">
|
||||||
<value>Username:</value>
|
<value>Username:</value>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -154,16 +154,16 @@
|
|||||||
<value>Select how often you want the job to run</value>
|
<value>Select how often you want the job to run</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Starting.HelpText" xml:space="preserve">
|
<data name="Starting.HelpText" xml:space="preserve">
|
||||||
<value>What time do you want the job to start</value>
|
<value>Optionally enter the date and time when this job should start executing</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Ending.HelpText" xml:space="preserve">
|
<data name="Ending.HelpText" xml:space="preserve">
|
||||||
<value>When do you want the job to end</value>
|
<value>Optionally enter the date and time when this job should stop executing</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RetentionLog.HelpText" xml:space="preserve">
|
<data name="RetentionLog.HelpText" xml:space="preserve">
|
||||||
<value>Number of log entries to retain for this job</value>
|
<value>Number of log entries to retain for this job</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NextExecution.HelpText" xml:space="preserve">
|
<data name="NextExecution.HelpText" xml:space="preserve">
|
||||||
<value>Next execution for this job.</value>
|
<value>Optionally modify the date and time when this job should execute next</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Type.Text" xml:space="preserve">
|
<data name="Type.Text" xml:space="preserve">
|
||||||
<value>Type: </value>
|
<value>Type: </value>
|
||||||
|
@ -217,10 +217,10 @@
|
|||||||
<value>Enter the password for the integrated security</value>
|
<value>Enter the password for the integrated security</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="HostUsername.HelpText" xml:space="preserve">
|
<data name="HostUsername.HelpText" xml:space="preserve">
|
||||||
<value>Enter the username of the host for this site</value>
|
<value>Enter a valid host username</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="HostPassword.HelpText" xml:space="preserve">
|
<data name="HostPassword.HelpText" xml:space="preserve">
|
||||||
<value>Enter the password for the host of this site</value>
|
<value>Enter a valid host password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Name.Text" xml:space="preserve">
|
<data name="Name.Text" xml:space="preserve">
|
||||||
<value>Site Name: </value>
|
<value>Site Name: </value>
|
||||||
|
@ -8,6 +8,7 @@ namespace Oqtane.Services
|
|||||||
{
|
{
|
||||||
Task<List<Package>> GetPackagesAsync(string type);
|
Task<List<Package>> GetPackagesAsync(string type);
|
||||||
Task<List<Package>> GetPackagesAsync(string type, string search);
|
Task<List<Package>> GetPackagesAsync(string type, string search);
|
||||||
|
Task<Package> GetPackageAsync(string packageId, string version);
|
||||||
Task DownloadPackageAsync(string packageId, string version, string folder);
|
Task DownloadPackageAsync(string packageId, string version, string folder);
|
||||||
Task InstallPackagesAsync();
|
Task InstallPackagesAsync();
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,11 @@ namespace Oqtane.Services
|
|||||||
return await GetJsonAsync<List<Package>>($"{Apiurl}?type={type}&search={WebUtility.UrlEncode(search)}");
|
return await GetJsonAsync<List<Package>>($"{Apiurl}?type={type}&search={WebUtility.UrlEncode(search)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Package> GetPackageAsync(string packageId, string version)
|
||||||
|
{
|
||||||
|
return await PostJsonAsync<Package>($"{Apiurl}?packageid={packageId}&version={version}", null);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task DownloadPackageAsync(string packageId, string version, string folder)
|
public async Task DownloadPackageAsync(string packageId, string version, string folder)
|
||||||
{
|
{
|
||||||
await PostAsync($"{Apiurl}?packageid={packageId}&version={version}&folder={folder}");
|
await PostAsync($"{Apiurl}?packageid={packageId}&version={version}&folder={folder}");
|
||||||
|
@ -47,6 +47,7 @@ namespace Oqtane.Services
|
|||||||
{
|
{
|
||||||
return await PutJsonAsync<Role>($"{Apiurl}/{role.RoleId}", role);
|
return await PutJsonAsync<Role>($"{Apiurl}/{role.RoleId}", role);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteRoleAsync(int roleId)
|
public async Task DeleteRoleAsync(int roleId)
|
||||||
{
|
{
|
||||||
await DeleteAsync($"{Apiurl}/{roleId}");
|
await DeleteAsync($"{Apiurl}/{roleId}");
|
||||||
|
@ -34,6 +34,7 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
// GET: api/<controller>?type=x&search=y
|
// GET: api/<controller>?type=x&search=y
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
public async Task<IEnumerable<Package>> Get(string type, string search)
|
public async Task<IEnumerable<Package>> Get(string type, string search)
|
||||||
{
|
{
|
||||||
// get packages
|
// get packages
|
||||||
@ -52,36 +53,40 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Authorize(Roles = RoleNames.Host)]
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
public async Task Post(string packageid, string version, string folder)
|
public async Task<Package> Post(string packageid, string version, string folder)
|
||||||
{
|
{
|
||||||
// get package info
|
// get package info
|
||||||
Package package = null;
|
Package package = null;
|
||||||
if (bool.Parse(_configManager.GetSetting("PackageService", "true")) == true)
|
if (bool.Parse(_configManager.GetSetting("PackageService", "true")) == true)
|
||||||
{
|
{
|
||||||
|
var download = (string.IsNullOrEmpty(folder)) ? "false" : "true";
|
||||||
using (var client = new HttpClient())
|
using (var client = new HttpClient())
|
||||||
{
|
{
|
||||||
client.DefaultRequestHeaders.Add("Referer", HttpContext.Request.Scheme + "://" + HttpContext.Request.Host.Value);
|
client.DefaultRequestHeaders.Add("Referer", HttpContext.Request.Scheme + "://" + HttpContext.Request.Host.Value);
|
||||||
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(Constants.PackageId, Constants.Version));
|
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(Constants.PackageId, Constants.Version));
|
||||||
package = await GetJson<Package>(client, Constants.PackageRegistryUrl + $"/api/registry/package/?id={_configManager.GetInstallationId()}&package={packageid}&version={version}");
|
package = await GetJson<Package>(client, Constants.PackageRegistryUrl + $"/api/registry/package/?id={_configManager.GetInstallationId()}&package={packageid}&version={version}&download={download}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (package != null)
|
if (package != null)
|
||||||
{
|
{
|
||||||
using (var httpClient = new HttpClient())
|
if (bool.Parse(download))
|
||||||
{
|
{
|
||||||
folder = Path.Combine(_environment.ContentRootPath, folder);
|
using (var httpClient = new HttpClient())
|
||||||
var response = await httpClient.GetAsync(package.PackageUrl).ConfigureAwait(false);
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
{
|
||||||
string filename = packageid + "." + version + ".nupkg";
|
folder = Path.Combine(_environment.ContentRootPath, folder);
|
||||||
using (var fileStream = new FileStream(Path.Combine(folder, filename), FileMode.Create, FileAccess.Write, FileShare.None))
|
var response = await httpClient.GetAsync(package.PackageUrl).ConfigureAwait(false);
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
await response.Content.CopyToAsync(fileStream).ConfigureAwait(false);
|
string filename = packageid + "." + version + ".nupkg";
|
||||||
|
using (var fileStream = new FileStream(Path.Combine(folder, filename), FileMode.Create, FileAccess.Write, FileShare.None))
|
||||||
|
{
|
||||||
|
await response.Content.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "Could Not Download {PackageUrl}", package.PackageUrl);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "Could Not Download {PackageUrl}", package.PackageUrl);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,6 +95,7 @@ namespace Oqtane.Controllers
|
|||||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "Package {PackageId}.{Version} Is Not Registered", packageid, version);
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "Package {PackageId}.{Version} Is Not Registered", packageid, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return package;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<T> GetJson<T>(HttpClient httpClient, string url)
|
private async Task<T> GetJson<T>(HttpClient httpClient, string url)
|
||||||
|
@ -54,26 +54,19 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
// POST api/<controller>
|
// POST api/<controller>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
public Site Post([FromBody] Site site)
|
public Site Post([FromBody] Site site)
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid)
|
if (ModelState.IsValid)
|
||||||
{
|
{
|
||||||
bool authorized;
|
site = _sites.AddSite(site);
|
||||||
if (!_sites.GetSites().Any())
|
_logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Create, "Site Added {Site}", site);
|
||||||
{
|
}
|
||||||
// provision initial site during installation
|
else
|
||||||
authorized = true;
|
{
|
||||||
site.TenantId = _alias.TenantId;
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Post Attempt {Site}", site);
|
||||||
}
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
else
|
site = null;
|
||||||
{
|
|
||||||
authorized = User.IsInRole(RoleNames.Host);
|
|
||||||
}
|
|
||||||
if (authorized)
|
|
||||||
{
|
|
||||||
site = _sites.AddSite(site);
|
|
||||||
_logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Create, "Site Added {Site}", site);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return site;
|
return site;
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
bool verified;
|
bool verified;
|
||||||
bool allowregistration;
|
bool allowregistration;
|
||||||
if (user.Username == UserNames.Host || User.IsInRole(RoleNames.Admin))
|
if (User.IsInRole(RoleNames.Admin))
|
||||||
{
|
{
|
||||||
verified = true;
|
verified = true;
|
||||||
allowregistration = true;
|
allowregistration = true;
|
||||||
@ -177,18 +177,6 @@ namespace Oqtane.Controllers
|
|||||||
_notifications.AddNotification(notification);
|
_notifications.AddNotification(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign to host role if this is the host user ( initial installation )
|
|
||||||
if (user.Username == UserNames.Host)
|
|
||||||
{
|
|
||||||
int hostroleid = _roles.GetRoles(user.SiteId, true).Where(item => item.Name == RoleNames.Host).FirstOrDefault().RoleId;
|
|
||||||
UserRole userrole = new UserRole();
|
|
||||||
userrole.UserId = newUser.UserId;
|
|
||||||
userrole.RoleId = hostroleid;
|
|
||||||
userrole.EffectiveDate = null;
|
|
||||||
userrole.ExpiryDate = null;
|
|
||||||
_userRoles.AddUserRole(userrole);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add folder for user
|
// add folder for user
|
||||||
Folder folder = _folders.GetFolder(user.SiteId, Utilities.PathCombine("Users",Path.DirectorySeparatorChar.ToString()));
|
Folder folder = _folders.GetFolder(user.SiteId, Utilities.PathCombine("Users",Path.DirectorySeparatorChar.ToString()));
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
@ -221,7 +209,7 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newUser != null && user.Username != UserNames.Host)
|
if (newUser != null)
|
||||||
{
|
{
|
||||||
// add auto assigned roles to user for site
|
// add auto assigned roles to user for site
|
||||||
List<Role> roles = _roles.GetRoles(user.SiteId).Where(item => item.IsAutoAssigned).ToList();
|
List<Role> roles = _roles.GetRoles(user.SiteId).Where(item => item.IsAutoAssigned).ToList();
|
||||||
|
@ -53,7 +53,7 @@ namespace Oqtane.Controllers
|
|||||||
public UserRole Get(int id)
|
public UserRole Get(int id)
|
||||||
{
|
{
|
||||||
var userrole = _userRoles.GetUserRole(id);
|
var userrole = _userRoles.GetUserRole(id);
|
||||||
if (userrole != null && userrole.Role.SiteId == _alias.SiteId)
|
if (userrole != null && SiteValid(userrole.Role.SiteId))
|
||||||
{
|
{
|
||||||
return userrole;
|
return userrole;
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ namespace Oqtane.Controllers
|
|||||||
public UserRole Post([FromBody] UserRole userRole)
|
public UserRole Post([FromBody] UserRole userRole)
|
||||||
{
|
{
|
||||||
var role = _roles.GetRole(userRole.RoleId);
|
var role = _roles.GetRole(userRole.RoleId);
|
||||||
if (ModelState.IsValid && role != null && role.SiteId == _alias.SiteId && (User.IsInRole(RoleNames.Host) || role.Name != RoleNames.Host))
|
if (ModelState.IsValid && role != null && SiteValid(role.SiteId) && RoleValid(role.Name))
|
||||||
{
|
{
|
||||||
if (role.Name == RoleNames.Host)
|
if (role.Name == RoleNames.Host)
|
||||||
{
|
{
|
||||||
@ -100,7 +100,7 @@ namespace Oqtane.Controllers
|
|||||||
public UserRole Put(int id, [FromBody] UserRole userRole)
|
public UserRole Put(int id, [FromBody] UserRole userRole)
|
||||||
{
|
{
|
||||||
var role = _roles.GetRole(userRole.RoleId);
|
var role = _roles.GetRole(userRole.RoleId);
|
||||||
if (ModelState.IsValid && role != null && role.SiteId == _alias.SiteId && _userRoles.GetUserRole(userRole.UserRoleId, false) != null && (User.IsInRole(RoleNames.Host) || role.Name != RoleNames.Host))
|
if (ModelState.IsValid && role != null && SiteValid(role.SiteId) && RoleValid(role.Name) && _userRoles.GetUserRole(userRole.UserRoleId, false) != null)
|
||||||
{
|
{
|
||||||
userRole = _userRoles.UpdateUserRole(userRole);
|
userRole = _userRoles.UpdateUserRole(userRole);
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId);
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId);
|
||||||
@ -120,24 +120,24 @@ namespace Oqtane.Controllers
|
|||||||
[Authorize(Roles = RoleNames.Admin)]
|
[Authorize(Roles = RoleNames.Admin)]
|
||||||
public void Delete(int id)
|
public void Delete(int id)
|
||||||
{
|
{
|
||||||
UserRole userRole = _userRoles.GetUserRole(id);
|
UserRole userrole = _userRoles.GetUserRole(id);
|
||||||
if (userRole != null && userRole.Role.SiteId == _alias.SiteId && (User.IsInRole(RoleNames.Host) || userRole.Role.Name != RoleNames.Host))
|
if (userrole != null && SiteValid(userrole.Role.SiteId) && RoleValid(userrole.Role.Name))
|
||||||
{
|
{
|
||||||
_userRoles.DeleteUserRole(id);
|
_userRoles.DeleteUserRole(id);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userRole);
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userrole);
|
||||||
|
|
||||||
if (userRole.Role.Name == RoleNames.Host)
|
if (userrole.Role.Name == RoleNames.Host)
|
||||||
{
|
{
|
||||||
// add site specific user roles to preserve user access
|
// add site specific user roles to preserve user access
|
||||||
var role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Registered);
|
var role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Registered);
|
||||||
userRole = _userRoles.AddUserRole(new UserRole { UserId = userRole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null });
|
userrole = _userRoles.AddUserRole(new UserRole { UserId = userrole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null });
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole);
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userrole);
|
||||||
role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Admin);
|
role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Admin);
|
||||||
userRole = _userRoles.AddUserRole(new UserRole { UserId = userRole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null });
|
userrole = _userRoles.AddUserRole(new UserRole { UserId = userrole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null });
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole);
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userrole);
|
||||||
}
|
}
|
||||||
|
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId);
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userrole.UserId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -145,5 +145,15 @@ namespace Oqtane.Controllers
|
|||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool SiteValid(int? SiteId)
|
||||||
|
{
|
||||||
|
return (SiteId == _alias.SiteId || (SiteId == null && User.IsInRole(RoleNames.Host)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool RoleValid(string RoleName)
|
||||||
|
{
|
||||||
|
return (RoleName != RoleNames.Host || User.IsInRole(RoleNames.Host));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,13 +116,14 @@ namespace Oqtane.Infrastructure
|
|||||||
if (!installation.Success)
|
if (!installation.Success)
|
||||||
{
|
{
|
||||||
install.Aliases = GetInstallationConfig(SettingKeys.DefaultAliasKey, string.Empty);
|
install.Aliases = GetInstallationConfig(SettingKeys.DefaultAliasKey, string.Empty);
|
||||||
|
install.HostUsername = GetInstallationConfig(SettingKeys.HostUsernameKey, UserNames.Host);
|
||||||
install.HostPassword = GetInstallationConfig(SettingKeys.HostPasswordKey, string.Empty);
|
install.HostPassword = GetInstallationConfig(SettingKeys.HostPasswordKey, string.Empty);
|
||||||
install.HostEmail = GetInstallationConfig(SettingKeys.HostEmailKey, string.Empty);
|
install.HostEmail = GetInstallationConfig(SettingKeys.HostEmailKey, string.Empty);
|
||||||
|
install.HostName = GetInstallationConfig(SettingKeys.HostNameKey, UserNames.Host);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(install.ConnectionString) && !string.IsNullOrEmpty(install.Aliases) && !string.IsNullOrEmpty(install.HostPassword) && !string.IsNullOrEmpty(install.HostEmail))
|
if (!string.IsNullOrEmpty(install.ConnectionString) && !string.IsNullOrEmpty(install.Aliases) && !string.IsNullOrEmpty(install.HostPassword) && !string.IsNullOrEmpty(install.HostEmail))
|
||||||
{
|
{
|
||||||
// silent install
|
// silent install
|
||||||
install.HostName = UserNames.Host;
|
|
||||||
install.SiteTemplate = GetInstallationConfig(SettingKeys.SiteTemplateKey, Constants.DefaultSiteTemplate);
|
install.SiteTemplate = GetInstallationConfig(SettingKeys.SiteTemplateKey, Constants.DefaultSiteTemplate);
|
||||||
install.DefaultTheme = GetInstallationConfig(SettingKeys.DefaultThemeKey, Constants.DefaultTheme);
|
install.DefaultTheme = GetInstallationConfig(SettingKeys.DefaultThemeKey, Constants.DefaultTheme);
|
||||||
install.DefaultContainer = GetInstallationConfig(SettingKeys.DefaultContainerKey, Constants.DefaultContainer);
|
install.DefaultContainer = GetInstallationConfig(SettingKeys.DefaultContainerKey, Constants.DefaultContainer);
|
||||||
@ -583,49 +584,52 @@ namespace Oqtane.Infrastructure
|
|||||||
};
|
};
|
||||||
site = sites.AddSite(site);
|
site = sites.AddSite(site);
|
||||||
|
|
||||||
var identityUser = identityUserManager.FindByNameAsync(UserNames.Host).GetAwaiter().GetResult();
|
if (!string.IsNullOrEmpty(install.HostUsername))
|
||||||
if (identityUser == null)
|
|
||||||
{
|
{
|
||||||
identityUser = new IdentityUser {UserName = UserNames.Host, Email = install.HostEmail, EmailConfirmed = true};
|
var identityUser = identityUserManager.FindByNameAsync(install.HostUsername).GetAwaiter().GetResult();
|
||||||
var create = identityUserManager.CreateAsync(identityUser, install.HostPassword).GetAwaiter().GetResult();
|
if (identityUser == null)
|
||||||
if (create.Succeeded)
|
|
||||||
{
|
{
|
||||||
var user = new User
|
identityUser = new IdentityUser { UserName = install.HostUsername, Email = install.HostEmail, EmailConfirmed = true };
|
||||||
|
var create = identityUserManager.CreateAsync(identityUser, install.HostPassword).GetAwaiter().GetResult();
|
||||||
|
if (create.Succeeded)
|
||||||
{
|
{
|
||||||
SiteId = site.SiteId,
|
var user = new User
|
||||||
Username = UserNames.Host,
|
|
||||||
Password = install.HostPassword,
|
|
||||||
Email = install.HostEmail,
|
|
||||||
DisplayName = install.HostName,
|
|
||||||
LastIPAddress = "",
|
|
||||||
LastLoginOn = null
|
|
||||||
};
|
|
||||||
|
|
||||||
user = users.AddUser(user);
|
|
||||||
var hostRoleId = roles.GetRoles(user.SiteId, true).FirstOrDefault(item => item.Name == RoleNames.Host)?.RoleId ?? 0;
|
|
||||||
var userRole = new UserRole {UserId = user.UserId, RoleId = hostRoleId, EffectiveDate = null, ExpiryDate = null};
|
|
||||||
userRoles.AddUserRole(userRole);
|
|
||||||
|
|
||||||
// add user folder
|
|
||||||
var folder = folders.GetFolder(user.SiteId, Utilities.PathCombine("Users", Path.DirectorySeparatorChar.ToString()));
|
|
||||||
if (folder != null)
|
|
||||||
{
|
|
||||||
folders.AddFolder(new Folder
|
|
||||||
{
|
{
|
||||||
SiteId = folder.SiteId,
|
SiteId = site.SiteId,
|
||||||
ParentId = folder.FolderId,
|
Username = install.HostUsername,
|
||||||
Name = "My Folder",
|
Password = install.HostPassword,
|
||||||
Type = FolderTypes.Private,
|
Email = install.HostEmail,
|
||||||
Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()),
|
DisplayName = install.HostName,
|
||||||
Order = 1,
|
LastIPAddress = "",
|
||||||
IsSystem = true,
|
LastLoginOn = null
|
||||||
Permissions = new List<Permission>
|
};
|
||||||
|
|
||||||
|
user = users.AddUser(user);
|
||||||
|
var hostRoleId = roles.GetRoles(user.SiteId, true).FirstOrDefault(item => item.Name == RoleNames.Host)?.RoleId ?? 0;
|
||||||
|
var userRole = new UserRole { UserId = user.UserId, RoleId = hostRoleId, EffectiveDate = null, ExpiryDate = null };
|
||||||
|
userRoles.AddUserRole(userRole);
|
||||||
|
|
||||||
|
// add user folder
|
||||||
|
var folder = folders.GetFolder(user.SiteId, Utilities.PathCombine("Users", Path.DirectorySeparatorChar.ToString()));
|
||||||
|
if (folder != null)
|
||||||
|
{
|
||||||
|
folders.AddFolder(new Folder
|
||||||
|
{
|
||||||
|
SiteId = folder.SiteId,
|
||||||
|
ParentId = folder.FolderId,
|
||||||
|
Name = "My Folder",
|
||||||
|
Type = FolderTypes.Private,
|
||||||
|
Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()),
|
||||||
|
Order = 1,
|
||||||
|
IsSystem = true,
|
||||||
|
Permissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.Browse, user.UserId, true),
|
new Permission(PermissionNames.Browse, user.UserId, true),
|
||||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||||
new Permission(PermissionNames.Edit, user.UserId, true),
|
new Permission(PermissionNames.Edit, user.UserId, true),
|
||||||
}.EncodePermissions(),
|
}.EncodePermissions(),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,11 @@ namespace Oqtane.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// License for the Package.
|
||||||
|
/// </summary>
|
||||||
|
public string License { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Friendly name of the package
|
/// Friendly name of the package
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,6 +9,7 @@ namespace Oqtane.Shared
|
|||||||
public string TenantName { get; set; }
|
public string TenantName { get; set; }
|
||||||
public bool IsNewTenant { get; set; }
|
public bool IsNewTenant { get; set; }
|
||||||
public string SiteName { get; set; }
|
public string SiteName { get; set; }
|
||||||
|
public string HostUsername { get; set; }
|
||||||
public string HostPassword { get; set; }
|
public string HostPassword { get; set; }
|
||||||
public string HostEmail { get; set; }
|
public string HostEmail { get; set; }
|
||||||
public string HostName { get; set; }
|
public string HostName { get; set; }
|
||||||
|
@ -10,11 +10,12 @@ namespace Oqtane.Shared
|
|||||||
|
|
||||||
public const string InstallationSection = "Installation";
|
public const string InstallationSection = "Installation";
|
||||||
public const string DefaultAliasKey = "DefaultAlias";
|
public const string DefaultAliasKey = "DefaultAlias";
|
||||||
|
public const string HostUsernameKey = "HostUsername";
|
||||||
public const string HostPasswordKey = "HostPassword";
|
public const string HostPasswordKey = "HostPassword";
|
||||||
public const string HostEmailKey = "HostEmail";
|
public const string HostEmailKey = "HostEmail";
|
||||||
|
public const string HostNameKey = "HostName";
|
||||||
public const string SiteTemplateKey = "SiteTemplate";
|
public const string SiteTemplateKey = "SiteTemplate";
|
||||||
public const string DefaultThemeKey = "DefaultTheme";
|
public const string DefaultThemeKey = "DefaultTheme";
|
||||||
public const string DefaultLayoutKey = "DefaultLayout";
|
|
||||||
public const string DefaultContainerKey = "DefaultContainer";
|
public const string DefaultContainerKey = "DefaultContainer";
|
||||||
|
|
||||||
public const string AvailableDatabasesSection = "AvailableDatabases";
|
public const string AvailableDatabasesSection = "AvailableDatabases";
|
||||||
|
Reference in New Issue
Block a user