@@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>10.0.3</Version>
|
<Version>10.0.4</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018-2025 .NET Foundation
|
Copyright (c) 2018-2026 .NET Foundation
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Oqtane.Client" Version="10.0.3" />
|
<PackageReference Include="Oqtane.Client" Version="10.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Application.Template</id>
|
<id>Oqtane.Application.Template</id>
|
||||||
<version>10.0.3</version>
|
<version>10.0.4</version>
|
||||||
<title>Oqtane Application Template For Blazor</title>
|
<title>Oqtane Application Template For Blazor</title>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Oqtane.Server" Version="10.0.3" />
|
<PackageReference Include="Oqtane.Server" Version="10.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Oqtane.Shared" Version="10.0.3" />
|
<PackageReference Include="Oqtane.Shared" Version="10.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -5,100 +5,109 @@
|
|||||||
@inject IStringLocalizer<Edit> Localizer
|
@inject IStringLocalizer<Edit> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
@if (_initialized)
|
||||||
<div class="container">
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<Label Class="col-sm-3" For="name" HelpText="Enter the job name" ResourceKey="Name">Name: </Label>
|
<div class="container">
|
||||||
<div class="col-sm-9">
|
@if (!_editable)
|
||||||
<input id="name" class="form-control" @bind="@_name" maxlength="200" required />
|
{
|
||||||
|
<ModuleMessage Message="@Localizer["JobNotEditable"]" Type="MessageType.Warning" />
|
||||||
|
}
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="type" HelpText="The fully qualified job type name" ResourceKey="Type">Type: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="type" class="form-control" @bind="@_jobType" required disabled />
|
||||||
|
</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="name" HelpText="Enter the job name" ResourceKey="Name">Name: </Label>
|
||||||
<Label Class="col-sm-3" For="type" HelpText="The fully qualified job type name" ResourceKey="Type">Type: </Label>
|
<div class="col-sm-9">
|
||||||
<div class="col-sm-9">
|
<input id="name" class="form-control" @bind="@_name" maxlength="200" required disabled="@(!_editable)" />
|
||||||
<input id="type" class="form-control" @bind="@_jobType" readonly />
|
</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="enabled" HelpText="Select whether you want the job enabled or not" ResourceKey="Enabled">Enabled? </Label>
|
||||||
<Label Class="col-sm-3" For="enabled" HelpText="Select whether you want the job enabled or not" ResourceKey="Enabled">Enabled? </Label>
|
<div class="col-sm-9">
|
||||||
<div class="col-sm-9">
|
<select id="enabled" class="form-select" @bind="@_isEnabled" required disabled="@(!_editable)">
|
||||||
<select id="enabled" class="form-select" @bind="@_isEnabled" required>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
</select>
|
||||||
</select>
|
</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="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 mb-1" @bind="@_interval" maxlength="4" required disabled="@(!_editable)" />
|
||||||
<input id="runs-every" class="form-control mb-1" @bind="@_interval" maxlength="4" required />
|
<select id="runs-every" class="form-select" @bind="@_frequency" required disabled="@(!_editable)">
|
||||||
<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>
|
<option value="d">@Localizer["Day(s)"]</option>
|
||||||
<option value="d">@Localizer["Day(s)"]</option>
|
<option value="w">@Localizer["Week(s)"]</option>
|
||||||
<option value="w">@Localizer["Week(s)"]</option>
|
<option value="M">@Localizer["Month(s)"]</option>
|
||||||
<option value="M">@Localizer["Month(s)"]</option>
|
<option value="O">@Localizer["Once"]</option>
|
||||||
<option value="O">@Localizer["Once"]</option>
|
</select>
|
||||||
</select>
|
</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="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">
|
<input id="retention" type="number" min="0" step="1" class="form-control" @bind="@_retentionHistory" maxlength="3" required disabled="@(!_editable)" />
|
||||||
<input id="retention" type="number" min="0" step ="1" class="form-control" @bind="@_retentionHistory" maxlength="3" required />
|
</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="starting" HelpText="Optionally enter the date and time when this job should start executing" ResourceKey="Starting">Starting: </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">
|
<div class="row">
|
||||||
<div class="row">
|
<div class="col">
|
||||||
<div class="col">
|
<input id="starting" type="date" class="form-control" @bind="@_startDate" disabled="@(!_editable)" />
|
||||||
<input id="starting" type="date" class="form-control" @bind="@_startDate" />
|
</div>
|
||||||
</div>
|
<div class="col">
|
||||||
<div class="col">
|
<input id="starting" type="time" class="form-control" @bind="@_startTime" placeholder="hh:mm" required="@(_startDate.HasValue)" disabled="@(!_editable)" />
|
||||||
<input id="starting" type="time" class="form-control" @bind="@_startTime" placeholder="hh:mm" required="@(_startDate.HasValue)" />
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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="ending" HelpText="Optionally enter the date and time when this job should stop executing" ResourceKey="Ending">Ending: </Label>
|
||||||
<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="col-sm-9">
|
<div class="row">
|
||||||
<div class="row">
|
<div class="col">
|
||||||
<div class="col">
|
<input id="ending" type="date" class="form-control" @bind="@_endDate" disabled="@(!_editable)" />
|
||||||
<input id="ending" type="date" class="form-control" @bind="@_endDate" />
|
</div>
|
||||||
</div>
|
<div class="col">
|
||||||
<div class="col">
|
<input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" required="@(_endDate.HasValue)" disabled="@(!_editable)" />
|
||||||
<input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" required="@(_endDate.HasValue)" />
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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="The date and time when this job will execute next. This value cannot be modified. Use the settings above to control the execution of the job." ResourceKey="NextExecution">Next Execution: </Label>
|
||||||
<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="col-sm-9">
|
<input id="next" class="form-control" @bind="@_nextDate" disabled />
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<input id="next" type="date" class="form-control" @bind="@_nextDate" />
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<input id="next" type="time" class="form-control" placeholder="hh:mm" @bind="@_nextTime" required="@(_nextDate.HasValue)" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<br />
|
||||||
<br />
|
@if (_editable)
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveJob">@SharedLocalizer["Save"]</button>
|
{
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<button type="button" class="btn btn-success" @onclick="SaveJob">@SharedLocalizer["Save"]</button>
|
||||||
<br />
|
}
|
||||||
<br />
|
else
|
||||||
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
|
{
|
||||||
</form>
|
<button type="button" class="btn btn-danger" @onclick="DisableJob">@Localizer["Disable"]</button>
|
||||||
|
}
|
||||||
|
<NavLink class="btn btn-secondary ms-1" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
|
private bool _initialized = false;
|
||||||
|
private bool _editable = true;
|
||||||
private int _jobId;
|
private int _jobId;
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
private string _jobType = string.Empty;
|
private string _jobType = string.Empty;
|
||||||
@@ -113,26 +122,32 @@
|
|||||||
private DateTime? _nextDate = null;
|
private DateTime? _nextDate = null;
|
||||||
private DateTime? _nextTime = null;
|
private DateTime? _nextTime = null;
|
||||||
private string createdby;
|
private string createdby;
|
||||||
private DateTime createdon;
|
private DateTime createdon;
|
||||||
private string modifiedby;
|
private string modifiedby;
|
||||||
private DateTime modifiedon;
|
private DateTime modifiedon;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
await LoadJob();
|
||||||
{
|
}
|
||||||
_jobId = Int32.Parse(PageState.QueryString["id"]);
|
|
||||||
Job job = await JobService.GetJobAsync(_jobId);
|
protected async Task LoadJob()
|
||||||
if (job != null)
|
{
|
||||||
{
|
try
|
||||||
_name = job.Name;
|
{
|
||||||
_jobType = job.JobType;
|
_jobId = Int32.Parse(PageState.QueryString["id"]);
|
||||||
_isEnabled = job.IsEnabled.ToString();
|
Job job = await JobService.GetJobAsync(_jobId);
|
||||||
_interval = job.Interval.ToString();
|
if (job != null)
|
||||||
_frequency = job.Frequency;
|
{
|
||||||
_startDate = UtcToLocal(job.StartDate);
|
_editable = !job.IsEnabled && !job.IsExecuting;
|
||||||
|
_name = job.Name;
|
||||||
|
_jobType = job.JobType;
|
||||||
|
_isEnabled = job.IsEnabled.ToString();
|
||||||
|
_interval = job.Interval.ToString();
|
||||||
|
_frequency = job.Frequency;
|
||||||
|
_startDate = UtcToLocal(job.StartDate);
|
||||||
_startTime = UtcToLocal(job.StartDate);
|
_startTime = UtcToLocal(job.StartDate);
|
||||||
_endDate = UtcToLocal(job.EndDate);
|
_endDate = UtcToLocal(job.EndDate);
|
||||||
_endTime = UtcToLocal(job.EndDate);
|
_endTime = UtcToLocal(job.EndDate);
|
||||||
@@ -140,70 +155,107 @@
|
|||||||
_nextDate = UtcToLocal(job.NextExecution);
|
_nextDate = UtcToLocal(job.NextExecution);
|
||||||
_nextTime = UtcToLocal(job.NextExecution);
|
_nextTime = UtcToLocal(job.NextExecution);
|
||||||
createdby = job.CreatedBy;
|
createdby = job.CreatedBy;
|
||||||
createdon = job.CreatedOn;
|
createdon = job.CreatedOn;
|
||||||
modifiedby = job.ModifiedBy;
|
modifiedby = job.ModifiedBy;
|
||||||
modifiedon = job.ModifiedOn;
|
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()
|
_initialized = true;
|
||||||
{
|
|
||||||
if (!Utilities.ValidateEffectiveExpiryDates(_startDate, _endDate))
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.StartEndDateError"], MessageType.Warning);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
validated = true;
|
catch (Exception ex)
|
||||||
var interop = new Interop(JSRuntime);
|
{
|
||||||
if (await interop.FormValid(form))
|
await logger.LogError(ex, "Error Loading Job {JobId} {Error}", _jobId, ex.Message);
|
||||||
{
|
AddModuleMessage(Localizer["Error.Job.Load"], MessageType.Error);
|
||||||
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.HasValue && _startTime.HasValue
|
|
||||||
? LocalToUtc(_startDate.GetValueOrDefault().Date.Add(_startTime.GetValueOrDefault().TimeOfDay))
|
|
||||||
: null;
|
|
||||||
|
|
||||||
job.EndDate = _endDate.HasValue && _endTime.HasValue
|
private async Task SaveJob()
|
||||||
? LocalToUtc(_endDate.GetValueOrDefault().Date.Add(_endTime.GetValueOrDefault().TimeOfDay))
|
{
|
||||||
: null;
|
try
|
||||||
|
{
|
||||||
|
var interop = new Interop(JSRuntime);
|
||||||
|
if (await interop.FormValid(form))
|
||||||
|
{
|
||||||
|
var job = await JobService.GetJobAsync(_jobId);
|
||||||
|
job.Name = _name;
|
||||||
|
job.IsEnabled = bool.Parse(_isEnabled);
|
||||||
|
|
||||||
job.NextExecution = _nextDate.HasValue && _nextTime.HasValue
|
job.Frequency = _frequency;
|
||||||
? LocalToUtc(_nextDate.GetValueOrDefault().Date.Add(_nextTime.GetValueOrDefault().TimeOfDay))
|
if (job.Frequency == "O") // once
|
||||||
: null;
|
{
|
||||||
job.RetentionHistory = int.Parse(_retentionHistory);
|
job.Interval = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
job.Interval = int.Parse(_interval);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
job.StartDate = _startDate.HasValue && _startTime.HasValue
|
||||||
{
|
? LocalToUtc(_startDate.GetValueOrDefault().Date.Add(_startTime.GetValueOrDefault().TimeOfDay))
|
||||||
job = await JobService.UpdateJobAsync(job);
|
: null;
|
||||||
await logger.LogInformation("Job Updated {Job}", job);
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
job.EndDate = _endDate.HasValue && _endTime.HasValue
|
||||||
}
|
? LocalToUtc(_endDate.GetValueOrDefault().Date.Add(_endTime.GetValueOrDefault().TimeOfDay))
|
||||||
catch (Exception ex)
|
: null;
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Udate Job {Job} {Error}", job, ex.Message);
|
job.RetentionHistory = int.Parse(_retentionHistory);
|
||||||
AddModuleMessage(Localizer["Error.Job.Update"], MessageType.Error);
|
|
||||||
}
|
if (!job.IsEnabled || Utilities.ValidateEffectiveExpiryDates(job.StartDate, job.EndDate))
|
||||||
}
|
{
|
||||||
else
|
if (!job.IsEnabled || (job.StartDate >= DateTime.UtcNow || job.StartDate == null))
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Message.Required.JobInfo"], MessageType.Warning);
|
job.NextExecution = null;
|
||||||
}
|
job = await JobService.UpdateJobAsync(job);
|
||||||
}
|
await logger.LogInformation("Job Updated {Job}", job);
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.StartDateError"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.StartEndDateError"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Required.JobInfo"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Updating Job {JobId} {Error}", _jobId, ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Job.Update"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DisableJob()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var job = await JobService.GetJobAsync(_jobId);
|
||||||
|
if (job != null)
|
||||||
|
{
|
||||||
|
if (job.IsExecuting)
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.ExecutingError"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
job.IsEnabled = false;
|
||||||
|
job.NextExecution = null;
|
||||||
|
job = await JobService.UpdateJobAsync(job);
|
||||||
|
await logger.LogInformation("Job Updated {Job}", job);
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Updating Job {JobId} {Error}", _jobId, ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Job.Update"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,6 @@ else
|
|||||||
private string _code = string.Empty;
|
private string _code = string.Empty;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||||
public override bool? Prerender => true;
|
|
||||||
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
@@ -222,6 +221,14 @@ else
|
|||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["ExternalLoginStatus." + PageState.QueryString["status"]], MessageType.Warning);
|
AddModuleMessage(Localizer["ExternalLoginStatus." + PageState.QueryString["status"]], MessageType.Warning);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_allowexternallogin && !_allowsitelogin)
|
||||||
|
{
|
||||||
|
// external login
|
||||||
|
ExternalLogin();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
@inject IServiceProvider ServiceProvider
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject INotificationService NotificationService
|
@inject INotificationService NotificationService
|
||||||
|
@inject IJobService JobService
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
@inject IOutputCacheService CacheService
|
@inject IOutputCacheService CacheService
|
||||||
|
|
||||||
@@ -207,13 +208,6 @@
|
|||||||
</div>
|
</div>
|
||||||
@if (_smtpenabled == "True" && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
@if (_smtpenabled == "True" && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<div class="col-sm-3">
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<strong>@Localizer["Smtp.Required.EnableNotificationJob"]</strong><br />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="host" HelpText="Enter the host name of the SMTP server" ResourceKey="Host">Host: </Label>
|
<Label Class="col-sm-3" For="host" HelpText="Enter the host name of the SMTP server" ResourceKey="Host">Host: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@@ -264,15 +258,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="relay" HelpText="Only specify this option if you have properly configured an SMTP Relay Service to route your outgoing mail. This option will send notifications from the user's email rather than from the Email Sender specified below." ResourceKey="SmtpRelay">Relay Configured? </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="relay" class="form-select" @bind="@_smtprelay" required>
|
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -534,7 +519,6 @@
|
|||||||
private string _togglesmtpclientsecret = string.Empty;
|
private string _togglesmtpclientsecret = string.Empty;
|
||||||
private string _smtpscopes = string.Empty;
|
private string _smtpscopes = string.Empty;
|
||||||
private string _smtpsender = string.Empty;
|
private string _smtpsender = string.Empty;
|
||||||
private string _smtprelay = "False";
|
|
||||||
private int _retention = 30;
|
private int _retention = 30;
|
||||||
|
|
||||||
private string _pwaisenabled;
|
private string _pwaisenabled;
|
||||||
@@ -653,7 +637,6 @@
|
|||||||
_togglesmtpclientsecret = SharedLocalizer["ShowPassword"];
|
_togglesmtpclientsecret = SharedLocalizer["ShowPassword"];
|
||||||
_smtpscopes = SettingService.GetSetting(settings, "SMTPScopes", string.Empty);
|
_smtpscopes = SettingService.GetSetting(settings, "SMTPScopes", string.Empty);
|
||||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||||
_smtprelay = SettingService.GetSetting(settings, "SMTPRelay", "False");
|
|
||||||
_retention = int.Parse(SettingService.GetSetting(settings, "NotificationRetention", "30"));
|
_retention = int.Parse(SettingService.GetSetting(settings, "NotificationRetention", "30"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,8 +829,18 @@
|
|||||||
settings = SettingService.SetSetting(settings, "SMTPClientSecret", _smtpclientsecret, true);
|
settings = SettingService.SetSetting(settings, "SMTPClientSecret", _smtpclientsecret, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPScopes", _smtpscopes, true);
|
settings = SettingService.SetSetting(settings, "SMTPScopes", _smtpscopes, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true);
|
|
||||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
||||||
|
|
||||||
|
if (_smtpenabled == "True")
|
||||||
|
{
|
||||||
|
var jobs = await JobService.GetJobsAsync();
|
||||||
|
var job = jobs.FirstOrDefault(item => item.JobType == "Oqtane.Infrastructure.NotificationJob, Oqtane.Server");
|
||||||
|
if (job != null && !job.IsEnabled)
|
||||||
|
{
|
||||||
|
job.IsEnabled = true;
|
||||||
|
await JobService.UpdateJobAsync(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//cookie consent
|
//cookie consent
|
||||||
@@ -957,7 +950,10 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_smtpenabled = "True";
|
||||||
|
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||||
@@ -972,6 +968,14 @@
|
|||||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
await logger.LogInformation("Site SMTP Settings Saved");
|
await logger.LogInformation("Site SMTP Settings Saved");
|
||||||
|
|
||||||
|
var jobs = await JobService.GetJobsAsync();
|
||||||
|
var job = jobs.FirstOrDefault(item => item.JobType == "Oqtane.Infrastructure.NotificationJob, Oqtane.Server");
|
||||||
|
if (job != null && !job.IsEnabled)
|
||||||
|
{
|
||||||
|
job.IsEnabled = true;
|
||||||
|
await JobService.UpdateJobAsync(job);
|
||||||
|
}
|
||||||
|
|
||||||
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
||||||
AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info);
|
AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info);
|
||||||
await ScrollToPageTop();
|
await ScrollToPageTop();
|
||||||
|
|||||||
@@ -83,14 +83,14 @@ else
|
|||||||
{
|
{
|
||||||
@if (_connection != "-")
|
@if (_connection != "-")
|
||||||
{
|
{
|
||||||
@if (!string.IsNullOrEmpty(_tenant))
|
<div class="row mb-1 align-items-center">
|
||||||
{
|
<Label Class="col-sm-3" For="databasetype" HelpText="The database type" ResourceKey="DatabaseType">Type: </Label>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="col-sm-9">
|
||||||
<Label Class="col-sm-3" For="databasetype" HelpText="The database type" ResourceKey="DatabaseType">Type: </Label>
|
<input id="databasetype" class="form-control" @bind="@_databasetype" readonly />
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="databasetype" class="form-control" @bind="@_databasetype" readonly />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (!string.IsNullOrEmpty(_tenant))
|
||||||
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="tenant" HelpText="The database using this connection" ResourceKey="Tenant">Database: </Label>
|
<Label Class="col-sm-3" For="tenant" HelpText="The database using this connection" ResourceKey="Tenant">Database: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@@ -150,130 +150,149 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string _connection = "-";
|
private string _connection = "-";
|
||||||
private Dictionary<string, object> _connections;
|
private Dictionary<string, object> _connections;
|
||||||
private List<Tenant> _tenants;
|
private List<Tenant> _tenants;
|
||||||
private List<Database> _databases;
|
private List<Database> _databases;
|
||||||
|
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
private string _databasetype = string.Empty;
|
private string _databasetype = string.Empty;
|
||||||
private Type _databaseConfigType;
|
private Type _databaseConfigType;
|
||||||
private object _databaseConfig;
|
private object _databaseConfig;
|
||||||
private RenderFragment DatabaseConfigComponent { get; set; }
|
private RenderFragment DatabaseConfigComponent { get; set; }
|
||||||
private bool _showConnectionString = false;
|
private bool _showConnectionString = false;
|
||||||
private string _tenant = string.Empty;
|
private string _tenant = string.Empty;
|
||||||
private string _connectionstring = string.Empty;
|
private string _connectionstring = string.Empty;
|
||||||
private string _connectionstringtype = "password";
|
private string _connectionstringtype = "password";
|
||||||
private string _connectionstringtoggle = string.Empty;
|
private string _connectionstringtoggle = string.Empty;
|
||||||
private string _sql = string.Empty;
|
private string _sql = string.Empty;
|
||||||
private List<Dictionary<string, string>> _results;
|
private List<Dictionary<string, string>> _results;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_connections = await SystemService.GetSystemInfoAsync("connectionstrings");
|
_connections = await SystemService.GetSystemInfoAsync("connectionstrings");
|
||||||
_tenants = await TenantService.GetTenantsAsync();
|
_tenants = await TenantService.GetTenantsAsync();
|
||||||
_databases = await DatabaseService.GetDatabasesAsync();
|
_databases = await DatabaseService.GetDatabasesAsync();
|
||||||
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Tenants {Error}", ex.Message);
|
await logger.LogError(ex, "Error Loading Tenants {Error}", ex.Message);
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ConnectionChanged(ChangeEventArgs e)
|
private async void ConnectionChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_connection = (string)e.Value;
|
_connection = (string)e.Value;
|
||||||
if (_connection != "-" && _connection != "+")
|
if (_connection != "-" && _connection != "+")
|
||||||
{
|
{
|
||||||
_connectionstring = _connections[_connection].ToString();
|
_connectionstring = _connections[_connection].ToString();
|
||||||
_tenant = "";
|
_tenant = "";
|
||||||
_databasetype = "";
|
_databasetype = "";
|
||||||
var tenant = _tenants.FirstOrDefault(item => item.DBConnectionString == _connection);
|
var tenant = _tenants.FirstOrDefault(item => item.DBConnectionString == _connection);
|
||||||
if (tenant != null)
|
if (tenant != null)
|
||||||
{
|
{
|
||||||
_tenant = tenant.Name;
|
_tenant = tenant.Name;
|
||||||
// hack - there are 3 providers with SqlServerDatabase DBTypes - so we are choosing the last one in alphabetical order
|
// hack - there are 3 providers with SqlServerDatabase DBTypes - so we are choosing the last one in alphabetical order
|
||||||
_databasetype = _databases.Where(item => item.DBType == tenant.DBType).OrderBy(item => item.Name).Last()?.Name;
|
_databasetype = _databases.Where(item => item.DBType == tenant.DBType).OrderBy(item => item.Name).Last()?.Name;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
if (_connection.Contains(" ("))
|
||||||
if (_databases.Exists(item => item.IsDefault))
|
{
|
||||||
{
|
_databasetype = _connection.Substring(_connection.LastIndexOf(" (") + 2).Replace(")", "");
|
||||||
_databasetype = _databases.Find(item => item.IsDefault).Name;
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
if (_databases.Exists(item => item.IsDefault))
|
||||||
|
{
|
||||||
|
_databasetype = _databases.Find(item => item.IsDefault).Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_databasetype = Constants.DefaultDBName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_databases.Exists(item => item.IsDefault))
|
||||||
|
{
|
||||||
|
_databasetype = _databases.Find(item => item.IsDefault).Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
_databasetype = Constants.DefaultDBName;
|
_databasetype = Constants.DefaultDBName;
|
||||||
}
|
}
|
||||||
_showConnectionString = false;
|
_showConnectionString = false;
|
||||||
LoadDatabaseConfigComponent();
|
LoadDatabaseConfigComponent();
|
||||||
}
|
}
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Connection {Connection} {Error}", _connection, ex.Message);
|
await logger.LogError(ex, "Error Loading Connection {Connection} {Error}", _connection, ex.Message);
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DatabaseTypeChanged(ChangeEventArgs eventArgs)
|
private void DatabaseTypeChanged(ChangeEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_databasetype = (string)eventArgs.Value;
|
_databasetype = (string)eventArgs.Value;
|
||||||
_showConnectionString = false;
|
_showConnectionString = false;
|
||||||
LoadDatabaseConfigComponent();
|
LoadDatabaseConfigComponent();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Error.Database.LoadConfig"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Database.LoadConfig"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadDatabaseConfigComponent()
|
private void LoadDatabaseConfigComponent()
|
||||||
{
|
{
|
||||||
var database = _databases.SingleOrDefault(d => d.Name == _databasetype);
|
var database = _databases.SingleOrDefault(d => d.Name == _databasetype);
|
||||||
if (database != null)
|
if (database != null)
|
||||||
{
|
{
|
||||||
_databaseConfigType = Type.GetType(database.ControlType);
|
_databaseConfigType = Type.GetType(database.ControlType);
|
||||||
DatabaseConfigComponent = builder =>
|
DatabaseConfigComponent = builder =>
|
||||||
{
|
{
|
||||||
builder.OpenComponent(0, _databaseConfigType);
|
builder.OpenComponent(0, _databaseConfigType);
|
||||||
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
|
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowConnectionString()
|
private void ShowConnectionString()
|
||||||
{
|
{
|
||||||
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
||||||
{
|
{
|
||||||
_connectionstring = databaseConfigControl.GetConnectionString();
|
_connectionstring = databaseConfigControl.GetConnectionString();
|
||||||
}
|
}
|
||||||
_showConnectionString = !_showConnectionString;
|
_showConnectionString = !_showConnectionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Add()
|
private async Task Add()
|
||||||
{
|
{
|
||||||
var connectionstring = _connectionstring;
|
var connectionstring = _connectionstring;
|
||||||
if (!_showConnectionString && _databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
if (!_showConnectionString && _databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
||||||
{
|
{
|
||||||
connectionstring = databaseConfigControl.GetConnectionString();
|
connectionstring = databaseConfigControl.GetConnectionString();
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(_name) && !string.IsNullOrEmpty(connectionstring))
|
if (!string.IsNullOrEmpty(_name) && !string.IsNullOrEmpty(connectionstring))
|
||||||
{
|
{
|
||||||
var settings = new Dictionary<string, object>();
|
_name = _name + " (" + _databasetype +")";
|
||||||
|
var settings = new Dictionary<string, object>();
|
||||||
settings.Add($"{SettingKeys.ConnectionStringsSection}:{_name}", connectionstring);
|
settings.Add($"{SettingKeys.ConnectionStringsSection}:{_name}", connectionstring);
|
||||||
await SystemService.UpdateSystemInfoAsync(settings);
|
await SystemService.UpdateSystemInfoAsync(settings);
|
||||||
_connections = await SystemService.GetSystemInfoAsync("connectionstrings");
|
_connections = await SystemService.GetSystemInfoAsync("connectionstrings");
|
||||||
|
|||||||
@@ -11,11 +11,22 @@
|
|||||||
{
|
{
|
||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Download" ResourceKey="Download">
|
<TabPanel Name="Download" ResourceKey="Download">
|
||||||
@if (_package != null && _upgradeavailable)
|
@if (_versions.Count > 0 && _upgradeable)
|
||||||
{
|
{
|
||||||
<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" HelpText="Specify if you want to backup files during the upgrade process. Disabling this option will reduce the time required for the upgrade." ResourceKey="Backup">Backup Files? </Label>
|
<Label Class="col-sm-3" For="version" HelpText="Select the framework upgrade version" ResourceKey="Version">Version: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="backup" class="form-select" @bind="@_version">
|
||||||
|
@foreach (var version in _versions)
|
||||||
|
{
|
||||||
|
<option value="@version">@version</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="backup" HelpText="Specify if you want to backup files during the upgrade process. Disabling this option will reduce the time required for the upgrade." ResourceKey="Backup">Backup Files? </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="backup" class="form-select" @bind="@_backup">
|
<select id="backup" class="form-select" @bind="@_backup">
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
@@ -27,7 +38,7 @@
|
|||||||
<br />
|
<br />
|
||||||
@if (!_downloaded)
|
@if (!_downloaded)
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await Download(Constants.PackageId, @_package.Version))>@SharedLocalizer["Download"] @_package.Version</button>
|
<button type="button" class="btn btn-primary" @onclick=@(async () => await Download(Constants.PackageId, _version))>@SharedLocalizer["Download"] @_version</button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -66,8 +77,9 @@
|
|||||||
@code {
|
@code {
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private bool _downloaded = false;
|
private bool _downloaded = false;
|
||||||
private Package _package;
|
private List<string> _versions = new List<string>();
|
||||||
private bool _upgradeavailable = false;
|
private string _version;
|
||||||
|
private bool _upgradeable = false;
|
||||||
private string _backup = "True";
|
private string _backup = "True";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
@@ -84,18 +96,18 @@
|
|||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Disclaimer.Text"], MessageType.Warning);
|
AddModuleMessage(Localizer["Disclaimer.Text"], MessageType.Warning);
|
||||||
|
|
||||||
List<Package> packages = await PackageService.GetPackagesAsync("framework", "", "", "");
|
var packages = await PackageService.GetPackagesAsync("framework", "", "", "");
|
||||||
if (packages != null)
|
if (packages != null)
|
||||||
{
|
{
|
||||||
_package = packages.Where(item => item.PackageId.StartsWith(Constants.PackageId)).FirstOrDefault();
|
_version = packages.First(item => item.PackageId.StartsWith(Constants.PackageId)).Version;
|
||||||
if (_package != null)
|
foreach (var version in Constants.ReleaseVersions.Split(','))
|
||||||
{
|
{
|
||||||
_upgradeavailable = (Version.Parse(_package.Version).CompareTo(Version.Parse(Constants.Version)) > 0);
|
if (Version.Parse(version).CompareTo(Version.Parse(Constants.Version)) > 0)
|
||||||
}
|
{
|
||||||
else
|
_versions.Add(version);
|
||||||
{
|
}
|
||||||
_package = new Package { Name = Constants.PackageId, Version = Constants.Version };
|
|
||||||
}
|
}
|
||||||
|
_upgradeable = (Version.Parse(_version).CompareTo(Version.Parse(Constants.Version)) > 0);
|
||||||
}
|
}
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
@if (_style == MessageStyle.Toast)
|
@if (_style == MessageStyle.Toast)
|
||||||
{
|
{
|
||||||
<div class="app-modulemessage-toast bottom-0 end-0" @key="DateTime.UtcNow">
|
<div class="app-modulemessage-toast bottom-0 end-0">
|
||||||
<div class="@_classname alert-dismissible fade show mb-3 rounded-end-0" role="alert">
|
<div class="@_classname alert-dismissible fade show mb-3 rounded-end-0" role="alert">
|
||||||
@((MarkupString)Message)
|
@((MarkupString)Message)
|
||||||
@if (Type == MessageType.Error && PageState != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
@if (Type == MessageType.Error && PageState != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
|||||||
@@ -86,11 +86,19 @@
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if a tab should be visible based on user permissions.
|
/// Determines if a tab should be visible based on user permissions.
|
||||||
/// Authorization hierarchy:
|
/// Authorization follows this hierarchy:
|
||||||
/// 1. Host and Admin roles ALWAYS have access (bypass all checks)
|
/// 1. Host tabs (Security == Host): Only users with Host role can access (Admins excluded)
|
||||||
/// 2. Check standard SecurityAccessLevel (View, Edit, etc.)
|
/// 2. Admin users: Bypass all other checks (except Host restrictions)
|
||||||
/// 3. If RoleName specified AND user is not Admin/Host, check RoleName
|
/// 3. SecurityAccessLevel check (null/Anonymous/View/Edit/Host):
|
||||||
/// 4. If PermissionName specified AND user is not Admin/Host, check PermissionName
|
/// - null: No security level restriction (proceeds to step 4)
|
||||||
|
/// - Anonymous: No authentication required
|
||||||
|
/// - View/Edit: Requires corresponding module permission
|
||||||
|
/// - Host: Only Host role can access
|
||||||
|
/// 4. Additional RoleName requirement (if specified)
|
||||||
|
/// 5. Additional PermissionName requirement (if specified)
|
||||||
|
///
|
||||||
|
/// Important: When Security is null, RoleName and PermissionName checks STILL apply
|
||||||
|
/// (Security = null doesn't mean unrestricted, it means "no security level required")
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="tabPanel">The tab panel to check authorization for</param>
|
/// <param name="tabPanel">The tab panel to check authorization for</param>
|
||||||
/// <returns>True if user is authorized to see this tab, false otherwise</returns>
|
/// <returns>True if user is authorized to see this tab, false otherwise</returns>
|
||||||
@@ -99,24 +107,40 @@
|
|||||||
// Step 1: Check for Host-only restriction
|
// Step 1: Check for Host-only restriction
|
||||||
if (tabPanel.Security == SecurityAccessLevel.Host)
|
if (tabPanel.Security == SecurityAccessLevel.Host)
|
||||||
{
|
{
|
||||||
// Only Host users can access Host-level security tabs (Admin users are excluded)
|
|
||||||
return UserSecurity.IsAuthorized(PageState.User, RoleNames.Host);
|
return UserSecurity.IsAuthorized(PageState.User, RoleNames.Host);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Admin bypass all other restrictions
|
// Step 2: Admin bypass all restrictions except Host
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var authorized = false;
|
// Step 3: If Security is null, check only RoleName and PermissionName
|
||||||
|
if (tabPanel.Security == null)
|
||||||
|
{
|
||||||
|
// Start with authorized = true for null security
|
||||||
|
bool isAuthorized = true;
|
||||||
|
|
||||||
// Step 3: Check standard SecurityAccessLevel
|
// Only apply RoleName check if provided
|
||||||
|
if (!string.IsNullOrEmpty(tabPanel.RoleName))
|
||||||
|
{
|
||||||
|
isAuthorized = UserSecurity.IsAuthorized(PageState.User, tabPanel.RoleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only apply PermissionName check if provided
|
||||||
|
if (isAuthorized && !string.IsNullOrEmpty(tabPanel.PermissionName))
|
||||||
|
{
|
||||||
|
isAuthorized = UserSecurity.IsAuthorized(PageState.User, tabPanel.PermissionName, ModuleState.PermissionList);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isAuthorized;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle other SecurityAccessLevel values
|
||||||
|
bool authorized = false; // Use different variable name or move declaration
|
||||||
switch (tabPanel.Security)
|
switch (tabPanel.Security)
|
||||||
{
|
{
|
||||||
case null:
|
|
||||||
authorized = true;
|
|
||||||
break;
|
|
||||||
case SecurityAccessLevel.Anonymous:
|
case SecurityAccessLevel.Anonymous:
|
||||||
authorized = true;
|
authorized = true;
|
||||||
break;
|
break;
|
||||||
@@ -131,13 +155,13 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4: Check RoleName if provided (additional requirement)
|
// Step 4: Additional RoleName requirement
|
||||||
if (authorized && !string.IsNullOrEmpty(tabPanel.RoleName))
|
if (authorized && !string.IsNullOrEmpty(tabPanel.RoleName))
|
||||||
{
|
{
|
||||||
authorized = UserSecurity.IsAuthorized(PageState.User, tabPanel.RoleName);
|
authorized = UserSecurity.IsAuthorized(PageState.User, tabPanel.RoleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5: Check PermissionName if provided (additional requirement)
|
// Step 5: Additional PermissionName requirement
|
||||||
if (authorized && !string.IsNullOrEmpty(tabPanel.PermissionName))
|
if (authorized && !string.IsNullOrEmpty(tabPanel.PermissionName))
|
||||||
{
|
{
|
||||||
authorized = UserSecurity.IsAuthorized(PageState.User, tabPanel.PermissionName, ModuleState.PermissionList);
|
authorized = UserSecurity.IsAuthorized(PageState.User, tabPanel.PermissionName, ModuleState.PermissionList);
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.2" />
|
||||||
<PackageReference Include="Radzen.Blazor" Version="8.4.0" />
|
<PackageReference Include="Radzen.Blazor" Version="8.6.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -139,7 +139,7 @@
|
|||||||
<value>Error Updating Job</value>
|
<value>Error Updating Job</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Required.JobInfo" xml:space="preserve">
|
<data name="Message.Required.JobInfo" xml:space="preserve">
|
||||||
<value>You Must Provide The Job Name, Type, Frequency, and Retention</value>
|
<value>You Must Provide The Job Name, Frequency, and Retention</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Name.HelpText" xml:space="preserve">
|
<data name="Name.HelpText" xml:space="preserve">
|
||||||
<value>Enter the job name</value>
|
<value>Enter the job name</value>
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
<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>Optionally enter the date and time when this job should start executing</value>
|
<value>Optionally enter the date and time when this job should start executing. If no date or time is specified, the job will execute immediately.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Ending.HelpText" xml:space="preserve">
|
<data name="Ending.HelpText" xml:space="preserve">
|
||||||
<value>Optionally enter the date and time when this job should stop executing</value>
|
<value>Optionally enter the date and time when this job should stop executing</value>
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
<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>Optionally modify the date and time when this job should execute next</value>
|
<value>The date and time when this job will execute next. This value cannot be modified. Use the settings above to control the execution of the job.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Type.Text" xml:space="preserve">
|
<data name="Type.Text" xml:space="preserve">
|
||||||
<value>Type: </value>
|
<value>Type: </value>
|
||||||
@@ -193,6 +193,15 @@
|
|||||||
<value>Execute Once</value>
|
<value>Execute Once</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.StartEndDateError" xml:space="preserve">
|
<data name="Message.StartEndDateError" xml:space="preserve">
|
||||||
<value>Start Date cannot be after End Date.</value>
|
<value>The Start Date Cannot Be Later Than The End Date</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.StartDateError" xml:space="preserve">
|
||||||
|
<value>The Start Date Cannot Be Prior To The Current Date</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.ExecutingError" xml:space="preserve">
|
||||||
|
<value>The Job Is Currently Executing. You Must Wait Until The Job Has Completed.</value>
|
||||||
|
</data>
|
||||||
|
<data name="JobNotEditable" xml:space="preserve">
|
||||||
|
<value>The Job Cannot Be Modified As It Is Currently Enabled. You Must Disable The Job To Change Its Settings.</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -132,9 +132,6 @@
|
|||||||
<data name="DefaultAdminContainer" xml:space="preserve">
|
<data name="DefaultAdminContainer" xml:space="preserve">
|
||||||
<value>Default Admin Container</value>
|
<value>Default Admin Container</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Smtp.Required.EnableNotificationJob" xml:space="preserve">
|
|
||||||
<value>** Please Note That SMTP Requires The Notification Job To Be Enabled In Scheduled Jobs</value>
|
|
||||||
</data>
|
|
||||||
<data name="Smtp.TestConfig" xml:space="preserve">
|
<data name="Smtp.TestConfig" xml:space="preserve">
|
||||||
<value>Test SMTP Configuration</value>
|
<value>Test SMTP Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -342,12 +339,6 @@
|
|||||||
<data name="HomePage.Text" xml:space="preserve">
|
<data name="HomePage.Text" xml:space="preserve">
|
||||||
<value>Home Page:</value>
|
<value>Home Page:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SmtpRelay.HelpText" xml:space="preserve">
|
|
||||||
<value>Only specify this option if you have properly configured an SMTP Relay Service to route your outgoing mail. This option will send notifications from the user's email rather than from the Email Sender specified above.</value>
|
|
||||||
</data>
|
|
||||||
<data name="SmtpRelay.Text" xml:space="preserve">
|
|
||||||
<value>Relay Configured?</value>
|
|
||||||
</data>
|
|
||||||
<data name="SiteMap.HelpText" xml:space="preserve">
|
<data name="SiteMap.HelpText" xml:space="preserve">
|
||||||
<value>The site map url for this site which can be submitted to search engines for indexing. The sitemap is cached for 5 minutes and the cache can be manually cleared.</value>
|
<value>The site map url for this site which can be submitted to search engines for indexing. The sitemap is cached for 5 minutes and the cache can be manually cleared.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -156,4 +156,10 @@
|
|||||||
<data name="Backup.HelpText" xml:space="preserve">
|
<data name="Backup.HelpText" xml:space="preserve">
|
||||||
<value>Specify if you want to backup files during the upgrade process. Disabling this option will reduce the time required for the upgrade.</value>
|
<value>Specify if you want to backup files during the upgrade process. Disabling this option will reduce the time required for the upgrade.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Version.Text" xml:space="preserve">
|
||||||
|
<value>Version:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Version.HelpText" xml:space="preserve">
|
||||||
|
<value>Select the framework upgrade version</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
{
|
{
|
||||||
@if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "top")
|
@if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "top")
|
||||||
{
|
{
|
||||||
<ModuleMessage Message="@_messageContent" Type="@_messageType" Parent="@this" Style="@_messageStyle" />
|
<ModuleMessage @key="_messageVersionTop" Message="@_messageContent" Type="@_messageType" Parent="@this" Style="@_messageStyle" />
|
||||||
}
|
}
|
||||||
@DynamicComponent
|
@DynamicComponent
|
||||||
@if (_progressIndicator)
|
@if (_progressIndicator)
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
}
|
}
|
||||||
@if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "bottom")
|
@if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "bottom")
|
||||||
{
|
{
|
||||||
<ModuleMessage Message="@_messageContent" Type="@_messageType" Parent="@this" Style="@_messageStyle" />
|
<ModuleMessage @key="_messageVersionBottom" Message="@_messageContent" Type="@_messageType" Parent="@this" Style="@_messageStyle" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,6 +52,8 @@
|
|||||||
private MessageStyle _messageStyle;
|
private MessageStyle _messageStyle;
|
||||||
private bool _progressIndicator = false;
|
private bool _progressIndicator = false;
|
||||||
private string _error;
|
private string _error;
|
||||||
|
private string _messageVersionTop = Guid.NewGuid().ToString();
|
||||||
|
private string _messageVersionBottom = Guid.NewGuid().ToString();
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public SiteState SiteState { get; set; }
|
public SiteState SiteState { get; set; }
|
||||||
@@ -143,6 +145,18 @@
|
|||||||
_messageStyle = style;
|
_messageStyle = style;
|
||||||
_progressIndicator = false;
|
_progressIndicator = false;
|
||||||
|
|
||||||
|
if (style == MessageStyle.Toast && !string.IsNullOrEmpty(_messageContent))
|
||||||
|
{
|
||||||
|
if (_messagePosition == "top")
|
||||||
|
{
|
||||||
|
_messageVersionTop = Guid.NewGuid().ToString();
|
||||||
|
}
|
||||||
|
else if (_messagePosition == "bottom")
|
||||||
|
{
|
||||||
|
_messageVersionBottom = Guid.NewGuid().ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<ApplicationId>com.oqtane.maui</ApplicationId>
|
<ApplicationId>com.oqtane.maui</ApplicationId>
|
||||||
|
|
||||||
<!-- Versions -->
|
<!-- Versions -->
|
||||||
<ApplicationDisplayVersion>10.0.3</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>10.0.4</ApplicationDisplayVersion>
|
||||||
<ApplicationVersion>1</ApplicationVersion>
|
<ApplicationVersion>1</ApplicationVersion>
|
||||||
|
|
||||||
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
|
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
|
||||||
@@ -54,11 +54,11 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.2" />
|
||||||
<PackageReference Include="System.Net.Http.Json" Version="10.0.1" />
|
<PackageReference Include="System.Net.Http.Json" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="$(MauiVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="$(MauiVersion)" />
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Client</id>
|
<id>Oqtane.Client</id>
|
||||||
<version>10.0.3</version>
|
<version>10.0.4</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@@ -12,18 +12,18 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<group targetFramework="net10.0">
|
<group targetFramework="net10.0">
|
||||||
<dependency id="Oqtane.Shared" version="10.0.0" exclude="Build,Analyzers" />
|
<dependency id="Oqtane.Shared" version="10.0.4" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.AspNetCore.Components.WebAssembly" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.AspNetCore.Components.WebAssembly" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.AspNetCore.Components.WebAssembly.Authentication" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.AspNetCore.Components.WebAssembly.Authentication" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.Extensions.Localization" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.Extensions.Localization" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.Extensions.Http" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.Extensions.Http" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="Radzen.Blazor" version="8.4.0" exclude="Build,Analyzers" />
|
<dependency id="Radzen.Blazor" version="8.6.0" exclude="Build,Analyzers" />
|
||||||
</group>
|
</group>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Framework</id>
|
<id>Oqtane.Framework</id>
|
||||||
<version>10.0.3</version>
|
<version>10.0.4</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@@ -11,8 +11,8 @@
|
|||||||
<copyright>.NET Foundation</copyright>
|
<copyright>.NET Foundation</copyright>
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v10.0.3/Oqtane.Framework.10.0.3.Upgrade.zip</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v10.0.4/Oqtane.Framework.10.0.4.Upgrade.zip</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane framework</tags>
|
<tags>oqtane framework</tags>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Server</id>
|
<id>Oqtane.Server</id>
|
||||||
<version>10.0.3</version>
|
<version>10.0.4</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@@ -12,29 +12,29 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<group targetFramework="net10.0">
|
<group targetFramework="net10.0">
|
||||||
<dependency id="Oqtane.Client" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Oqtane.Client" version="10.0.4" exclude="Build,Analyzers" />
|
||||||
<dependency id="Oqtane.Shared" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Oqtane.Shared" version="10.0.4" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.AspNetCore.Components.WebAssembly.Server" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.AspNetCore.Components.WebAssembly.Server" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.AspNetCore.Identity.EntityFrameworkCore" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.AspNetCore.Identity.EntityFrameworkCore" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.AspNetCore.Authentication.OpenIdConnect" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.AspNetCore.Authentication.OpenIdConnect" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.EntityFrameworkCore.Relational" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.EntityFrameworkCore.Relational" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="SixLabors.ImageSharp" version="3.1.12" exclude="Build,Analyzers" />
|
<dependency id="SixLabors.ImageSharp" version="3.1.12" exclude="Build,Analyzers" />
|
||||||
<dependency id="HtmlAgilityPack" version="1.12.4" exclude="Build,Analyzers" />
|
<dependency id="HtmlAgilityPack" version="1.12.4" exclude="Build,Analyzers" />
|
||||||
<dependency id="Swashbuckle.AspNetCore" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Swashbuckle.AspNetCore" version="10.1.0" exclude="Build,Analyzers" />
|
||||||
<dependency id="MailKit" version="4.14.1" exclude="Build,Analyzers" />
|
<dependency id="MailKit" version="4.14.1" exclude="Build,Analyzers" />
|
||||||
<dependency id="MySql.Data" version="9.5.0" exclude="Build,Analyzers" />
|
<dependency id="MySql.Data" version="9.5.0" exclude="Build,Analyzers" />
|
||||||
<dependency id="Pomelo.EntityFrameworkCore.MySql" version="9.0.0" exclude="Build,Analyzers" />
|
<dependency id="MySql.EntityFrameworkCore" version="10.0.0-rc" exclude="Build,Analyzers" />
|
||||||
<dependency id="EFCore.NamingConventions" version="10.0.0-rc.2" exclude="Build,Analyzers" />
|
<dependency id="EFCore.NamingConventions" version="10.0.0" exclude="Build,Analyzers" />
|
||||||
<dependency id="Npgsql.EntityFrameworkCore.PostgreSQL" version="10.0.0" exclude="Build,Analyzers" />
|
<dependency id="Npgsql.EntityFrameworkCore.PostgreSQL" version="10.0.0" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.EntityFrameworkCore.Sqlite" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.EntityFrameworkCore.Sqlite" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.Data.Sqlite.Core" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.Data.Sqlite.Core" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.EntityFrameworkCore.SqlServer" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.EntityFrameworkCore.SqlServer" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
</group>
|
</group>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<frameworkReferences>
|
<frameworkReferences>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Shared</id>
|
<id>Oqtane.Shared</id>
|
||||||
<version>10.0.3</version>
|
<version>10.0.4</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@@ -12,15 +12,15 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<group targetFramework="net10.0">
|
<group targetFramework="net10.0">
|
||||||
<dependency id="Microsoft.EntityFrameworkCore" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.EntityFrameworkCore" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.Extensions.DependencyInjection.Abstractions" version="10.0.1" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.Extensions.DependencyInjection.Abstractions" version="10.0.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="NodaTime" version="3.2.3" exclude="Build,Analyzers" />
|
<dependency id="NodaTime" version="3.3.0" exclude="Build,Analyzers" />
|
||||||
</group>
|
</group>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Updater</id>
|
<id>Oqtane.Updater</id>
|
||||||
<version>10.0.3</version>
|
<version>10.0.4</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.2</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net10.0\publish\*" -DestinationPath "Oqtane.Framework.10.0.3.Install.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net10.0\publish\*" -DestinationPath "Oqtane.Framework.10.0.4.Install.zip" -Force
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net10.0\publish\*" -DestinationPath "Oqtane.Framework.10.0.3.Upgrade.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net10.0\publish\*" -DestinationPath "Oqtane.Framework.10.0.4.Upgrade.zip" -Force
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_configManager.AddOrUpdateSetting(key, value, false);
|
_configManager.AddOrUpdateSetting(key, value, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore.Metadata;
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
|
using MySql.EntityFrameworkCore.Metadata;
|
||||||
using Oqtane.Databases;
|
using Oqtane.Databases;
|
||||||
|
|
||||||
namespace Oqtane.Database.MySQL
|
namespace Oqtane.Database.MySQL
|
||||||
@@ -25,7 +26,7 @@ namespace Oqtane.Database.MySQL
|
|||||||
|
|
||||||
public override OperationBuilder<AddColumnOperation> AddAutoIncrementColumn(ColumnsBuilder table, string name)
|
public override OperationBuilder<AddColumnOperation> AddAutoIncrementColumn(ColumnsBuilder table, string name)
|
||||||
{
|
{
|
||||||
return table.Column<int>(name: name, nullable: false).Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
|
return table.Column<int>(name: name, nullable: false).Annotation("MySQL:ValueGenerationStrategy", MySQLValueGenerationStrategy.IdentityColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ConcatenateSql(params string[] values)
|
public override string ConcatenateSql(params string[] values)
|
||||||
@@ -96,7 +97,7 @@ namespace Oqtane.Database.MySQL
|
|||||||
|
|
||||||
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
||||||
{
|
{
|
||||||
return optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
|
return optionsBuilder.UseMySQL(connectionString);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrepareCommand(MySqlConnection conn, MySqlCommand cmd, string query)
|
private void PrepareCommand(MySqlConnection conn, MySqlCommand cmd, string query)
|
||||||
|
|||||||
@@ -84,16 +84,13 @@ namespace Oqtane.Extensions
|
|||||||
options.Events.OnRemoteFailure = OnRemoteFailure;
|
options.Events.OnRemoteFailure = OnRemoteFailure;
|
||||||
if (sitesettings.GetValue("ExternalLogin:Parameters", "") != "")
|
if (sitesettings.GetValue("ExternalLogin:Parameters", "") != "")
|
||||||
{
|
{
|
||||||
options.Events = new OpenIdConnectEvents
|
options.Events.OnRedirectToIdentityProvider = context =>
|
||||||
{
|
{
|
||||||
OnRedirectToIdentityProvider = context =>
|
foreach (var parameter in sitesettings.GetValue("ExternalLogin:Parameters", "").Split(","))
|
||||||
{
|
{
|
||||||
foreach (var parameter in sitesettings.GetValue("ExternalLogin:Parameters", "").Split(","))
|
context.ProtocolMessage.SetParameter(parameter.Split("=")[0], parameter.Split("=")[1]);
|
||||||
{
|
|
||||||
context.ProtocolMessage.SetParameter(parameter.Split("=")[0], parameter.Split("=")[1]);
|
|
||||||
}
|
|
||||||
return Task.FromResult(0);
|
|
||||||
}
|
}
|
||||||
|
return Task.FromResult(0);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,18 +129,15 @@ namespace Oqtane.Extensions
|
|||||||
options.Events.OnRemoteFailure = OnRemoteFailure;
|
options.Events.OnRemoteFailure = OnRemoteFailure;
|
||||||
if (sitesettings.GetValue("ExternalLogin:Parameters", "") != "")
|
if (sitesettings.GetValue("ExternalLogin:Parameters", "") != "")
|
||||||
{
|
{
|
||||||
options.Events = new OAuthEvents
|
options.Events.OnRedirectToAuthorizationEndpoint = context =>
|
||||||
{
|
{
|
||||||
OnRedirectToAuthorizationEndpoint = context =>
|
var url = context.RedirectUri;
|
||||||
|
foreach (var parameter in sitesettings.GetValue("ExternalLogin:Parameters", "").Split(","))
|
||||||
{
|
{
|
||||||
var url = context.RedirectUri;
|
url += (!url.Contains("?")) ? "?" + parameter : "&" + parameter;
|
||||||
foreach (var parameter in sitesettings.GetValue("ExternalLogin:Parameters", "").Split(","))
|
|
||||||
{
|
|
||||||
url += (!url.Contains("?")) ? "?" + parameter : "&" + parameter;
|
|
||||||
}
|
|
||||||
context.Response.Redirect(url);
|
|
||||||
return Task.FromResult(0);
|
|
||||||
}
|
}
|
||||||
|
context.Response.Redirect(url);
|
||||||
|
return Task.FromResult(0);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,41 +198,27 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
case "m": // minutes
|
case "m": // minutes
|
||||||
nextExecution = nextExecution.AddMinutes(job.Interval);
|
nextExecution = nextExecution.AddMinutes(job.Interval);
|
||||||
|
if (nextExecution < DateTime.UtcNow) nextExecution = DateTime.UtcNow;
|
||||||
break;
|
break;
|
||||||
case "H": // hours
|
case "H": // hours
|
||||||
nextExecution = nextExecution.AddHours(job.Interval);
|
nextExecution = nextExecution.AddHours(job.Interval);
|
||||||
|
if (nextExecution < DateTime.UtcNow) nextExecution = DateTime.UtcNow;
|
||||||
break;
|
break;
|
||||||
case "d": // days
|
case "d": // days
|
||||||
|
nextExecution = DateTime.UtcNow.Date.Add(nextExecution.TimeOfDay); // preserve time of day
|
||||||
nextExecution = nextExecution.AddDays(job.Interval);
|
nextExecution = nextExecution.AddDays(job.Interval);
|
||||||
if (job.StartDate != null && job.StartDate.Value.TimeOfDay.TotalSeconds != 0)
|
|
||||||
{
|
|
||||||
// set the start time
|
|
||||||
nextExecution = nextExecution.Date.Add(job.StartDate.Value.TimeOfDay);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "w": // weeks
|
case "w": // weeks
|
||||||
|
nextExecution = DateTime.UtcNow.Date.Add(nextExecution.TimeOfDay); // preserve time of day
|
||||||
nextExecution = nextExecution.AddDays(job.Interval * 7);
|
nextExecution = nextExecution.AddDays(job.Interval * 7);
|
||||||
if (job.StartDate != null && job.StartDate.Value.TimeOfDay.TotalSeconds != 0)
|
|
||||||
{
|
|
||||||
// set the start time
|
|
||||||
nextExecution = nextExecution.Date.Add(job.StartDate.Value.TimeOfDay);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "M": // months
|
case "M": // months
|
||||||
|
nextExecution = DateTime.UtcNow.Date.Add(nextExecution.TimeOfDay); // preserve time of day
|
||||||
nextExecution = nextExecution.AddMonths(job.Interval);
|
nextExecution = nextExecution.AddMonths(job.Interval);
|
||||||
if (job.StartDate != null && job.StartDate.Value.TimeOfDay.TotalSeconds != 0)
|
|
||||||
{
|
|
||||||
// set the start time
|
|
||||||
nextExecution = nextExecution.Date.Add(job.StartDate.Value.TimeOfDay);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "O": // one time
|
case "O": // one time
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (nextExecution < DateTime.UtcNow)
|
|
||||||
{
|
|
||||||
nextExecution = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
return nextExecution;
|
return nextExecution;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ namespace Oqtane.Infrastructure
|
|||||||
var toEmail = notification.ToEmail ?? "";
|
var toEmail = notification.ToEmail ?? "";
|
||||||
var toName = notification.ToDisplayName ?? "";
|
var toName = notification.ToDisplayName ?? "";
|
||||||
|
|
||||||
// get sender and receiver information from user information if available
|
// get sender from user information if "from" email or name is not specified and user id is available
|
||||||
if ((string.IsNullOrEmpty(fromEmail) || string.IsNullOrEmpty(fromName)) && notification.FromUserId != null)
|
if ((string.IsNullOrEmpty(fromEmail) || string.IsNullOrEmpty(fromName)) && notification.FromUserId != null)
|
||||||
{
|
{
|
||||||
var user = userRepository.GetUser(notification.FromUserId.Value);
|
var user = userRepository.GetUser(notification.FromUserId.Value);
|
||||||
@@ -170,6 +170,9 @@ namespace Oqtane.Infrastructure
|
|||||||
fromName = string.IsNullOrEmpty(fromName) ? user.DisplayName ?? "" : fromName;
|
fromName = string.IsNullOrEmpty(fromName) ? user.DisplayName ?? "" : fromName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fromName = string.IsNullOrEmpty(fromName) ? site.Name : fromName;
|
||||||
|
|
||||||
|
// get recipient from user information if "to" email or name is not specified and user id is available
|
||||||
if ((string.IsNullOrEmpty(toEmail) || string.IsNullOrEmpty(toName)) && notification.ToUserId != null)
|
if ((string.IsNullOrEmpty(toEmail) || string.IsNullOrEmpty(toName)) && notification.ToUserId != null)
|
||||||
{
|
{
|
||||||
var user = userRepository.GetUser(notification.ToUserId.Value);
|
var user = userRepository.GetUser(notification.ToUserId.Value);
|
||||||
@@ -181,30 +184,34 @@ namespace Oqtane.Infrastructure
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create mailbox addresses
|
// create mailbox addresses
|
||||||
MailboxAddress to = null;
|
|
||||||
MailboxAddress from = null;
|
MailboxAddress from = null;
|
||||||
|
MailboxAddress to = null;
|
||||||
|
MailboxAddress replyTo = null;
|
||||||
var mailboxAddressValidationError = "";
|
var mailboxAddressValidationError = "";
|
||||||
|
|
||||||
// sender
|
// always send from SMTP Sender
|
||||||
if ((settingRepository.GetSettingValue(settings, "SMTPRelay", "False") == "True") && string.IsNullOrEmpty(fromEmail))
|
if (MailboxAddress.TryParse(settingRepository.GetSettingValue(settings, "SMTPSender", ""), out from))
|
||||||
{
|
{
|
||||||
fromEmail = settingRepository.GetSettingValue(settings, "SMTPSender", "");
|
from.Name = fromName;
|
||||||
fromName = string.IsNullOrEmpty(fromName) ? site.Name : fromName;
|
|
||||||
}
|
|
||||||
if (MailboxAddress.TryParse(fromEmail, out from))
|
|
||||||
{
|
|
||||||
from.Name = fromName;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
mailboxAddressValidationError += $" Invalid Sender: {fromName} <{settingRepository.GetSettingValue(settings, "SMTPSender", "")}>";
|
||||||
|
}
|
||||||
|
|
||||||
mailboxAddressValidationError += $" Invalid Sender: {fromName} <{fromEmail}>";
|
// reply to
|
||||||
|
if (!string.IsNullOrEmpty(fromEmail) && fromEmail != from.Address)
|
||||||
|
{
|
||||||
|
if (MailboxAddress.TryParse(fromEmail, out replyTo))
|
||||||
|
{
|
||||||
|
replyTo.Name = fromName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// recipient
|
// recipient
|
||||||
if (MailboxAddress.TryParse(toEmail, out to))
|
if (MailboxAddress.TryParse(toEmail, out to))
|
||||||
{
|
{
|
||||||
to.Name = toName;
|
to.Name = toName;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -218,6 +225,10 @@ namespace Oqtane.Infrastructure
|
|||||||
MimeMessage mailMessage = new MimeMessage();
|
MimeMessage mailMessage = new MimeMessage();
|
||||||
mailMessage.From.Add(from);
|
mailMessage.From.Add(from);
|
||||||
mailMessage.To.Add(to);
|
mailMessage.To.Add(to);
|
||||||
|
if (replyTo != null)
|
||||||
|
{
|
||||||
|
mailMessage.ReplyTo.Add(replyTo);
|
||||||
|
}
|
||||||
|
|
||||||
// subject
|
// subject
|
||||||
mailMessage.Subject = notification.Subject;
|
mailMessage.Subject = notification.Subject;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace Oqtane.Infrastructure.SiteTemplates
|
|||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
},
|
},
|
||||||
Content = "<p>Copyright (c) 2018-2025 .NET Foundation</p>" +
|
Content = "<p>Copyright (c) 2018-2026 .NET Foundation</p>" +
|
||||||
"<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>" +
|
"<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>" +
|
||||||
"<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>" +
|
"<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>" +
|
||||||
"<p>THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>"
|
"<p>THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>"
|
||||||
|
|||||||
@@ -78,9 +78,6 @@ namespace Oqtane.Infrastructure
|
|||||||
case "5.2.1":
|
case "5.2.1":
|
||||||
Upgrade_5_2_1(tenant, scope);
|
Upgrade_5_2_1(tenant, scope);
|
||||||
break;
|
break;
|
||||||
case "6.1.0":
|
|
||||||
Upgrade_6_1_0(tenant, scope);
|
|
||||||
break;
|
|
||||||
case "6.1.1":
|
case "6.1.1":
|
||||||
Upgrade_6_1_1(tenant, scope);
|
Upgrade_6_1_1(tenant, scope);
|
||||||
break;
|
break;
|
||||||
@@ -93,6 +90,9 @@ namespace Oqtane.Infrastructure
|
|||||||
case "6.2.1":
|
case "6.2.1":
|
||||||
Upgrade_6_2_1(tenant, scope);
|
Upgrade_6_2_1(tenant, scope);
|
||||||
break;
|
break;
|
||||||
|
case "10.0.4":
|
||||||
|
Upgrade_10_0_4(tenant, scope);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,16 +447,6 @@ namespace Oqtane.Infrastructure
|
|||||||
AddPagesToSites(scope, tenant, pageTemplates);
|
AddPagesToSites(scope, tenant, pageTemplates);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Upgrade_6_1_0(Tenant tenant, IServiceScope scope)
|
|
||||||
{
|
|
||||||
// remove MySql.EntityFrameworkCore package (replaced by Pomelo.EntityFrameworkCore.MySql)
|
|
||||||
string[] assemblies = {
|
|
||||||
"MySql.EntityFrameworkCore.dll"
|
|
||||||
};
|
|
||||||
|
|
||||||
RemoveAssemblies(tenant, assemblies, "6.1.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Upgrade_6_1_1(Tenant tenant, IServiceScope scope)
|
private void Upgrade_6_1_1(Tenant tenant, IServiceScope scope)
|
||||||
{
|
{
|
||||||
var localizer = scope.ServiceProvider.GetRequiredService<IStringLocalizer<AdminSiteTemplate>>();
|
var localizer = scope.ServiceProvider.GetRequiredService<IStringLocalizer<AdminSiteTemplate>>();
|
||||||
@@ -602,6 +592,16 @@ namespace Oqtane.Infrastructure
|
|||||||
RemoveFiles(tenant, files, "6.2.1");
|
RemoveFiles(tenant, files, "6.2.1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Upgrade_10_0_4(Tenant tenant, IServiceScope scope)
|
||||||
|
{
|
||||||
|
// remove Pomelo.EntityFrameworkCore.MySql package (replaced by MySql.EntityFrameworkCore)
|
||||||
|
string[] assemblies = {
|
||||||
|
"Pomelo.EntityFrameworkCore.MySql.dll"
|
||||||
|
};
|
||||||
|
|
||||||
|
RemoveAssemblies(tenant, assemblies, "10.0.4");
|
||||||
|
}
|
||||||
|
|
||||||
private void AddPagesToSites(IServiceScope scope, Tenant tenant, List<PageTemplate> pageTemplates)
|
private void AddPagesToSites(IServiceScope scope, Tenant tenant, List<PageTemplate> pageTemplates)
|
||||||
{
|
{
|
||||||
var tenants = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
var tenants = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||||
|
|||||||
@@ -181,13 +181,23 @@ namespace Oqtane.Managers
|
|||||||
succeeded = true;
|
succeeded = true;
|
||||||
if (!user.IsAuthenticated)
|
if (!user.IsAuthenticated)
|
||||||
{
|
{
|
||||||
var result = await _identitySignInManager.CheckPasswordSignInAsync(identityuser, user.Password, false);
|
// validate if the user already exists for the site
|
||||||
succeeded = result.Succeeded;
|
succeeded = string.IsNullOrEmpty(GetUser(user.Username, user.SiteId).Roles);
|
||||||
if (!succeeded)
|
if (succeeded)
|
||||||
{
|
{
|
||||||
errors = "Password Not Valid For User";
|
// a user is registering for a new site - ensure their password is valid
|
||||||
|
var result = await _identitySignInManager.CheckPasswordSignInAsync(identityuser, user.Password, false);
|
||||||
|
succeeded = result.Succeeded;
|
||||||
|
if (!succeeded)
|
||||||
|
{
|
||||||
|
errors = "User Already Exists In Installation But Cannot Be Added To A Site Because The Password Provided Is Not Valid";
|
||||||
|
}
|
||||||
|
user.EmailConfirmed = succeeded;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errors = "User Already Exists In Site";
|
||||||
}
|
}
|
||||||
user.EmailConfirmed = succeeded;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,28 +27,28 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.2" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
||||||
<PackageReference Include="HtmlAgilityPack" Version="1.12.4" />
|
<PackageReference Include="HtmlAgilityPack" Version="1.12.4" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.0.1" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.0" />
|
||||||
<PackageReference Include="MailKit" Version="4.14.1" />
|
<PackageReference Include="MailKit" Version="4.14.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- MySQL Database Provider Dependencies -->
|
<!-- MySQL Database Provider Dependencies -->
|
||||||
<PackageReference Include="MySql.Data" Version="9.5.0" />
|
<PackageReference Include="MySql.Data" Version="9.5.0" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0" />
|
<PackageReference Include="MySql.EntityFrameworkCore" Version="10.0.0-rc" />
|
||||||
<!-- PostgreSQL Database Provider Dependencies -->
|
<!-- PostgreSQL Database Provider Dependencies -->
|
||||||
<PackageReference Include="EFCore.NamingConventions" Version="10.0.0-rc.2" />
|
<PackageReference Include="EFCore.NamingConventions" Version="10.0.0" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
|
||||||
<!-- SQLite Database Provider Dependencies -->
|
<!-- SQLite Database Provider Dependencies -->
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="10.0.2" />
|
||||||
<!-- SQL Server Database Provider Dependencies -->
|
<!-- SQL Server Database Provider Dependencies -->
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Suppress EF Core internal warnings for Database Providers -->
|
<!-- Suppress EF Core internal warnings for Database Providers -->
|
||||||
|
|||||||
@@ -43,14 +43,6 @@ namespace Oqtane.Repository
|
|||||||
{
|
{
|
||||||
optionsBuilder.ReplaceService<IMigrationsAssembly, MultiDatabaseMigrationsAssembly>();
|
optionsBuilder.ReplaceService<IMigrationsAssembly, MultiDatabaseMigrationsAssembly>();
|
||||||
|
|
||||||
// specify the SchemaVersion for .NET Identity as it is not being persisted when using AddIdentityCore()
|
|
||||||
var services = new ServiceCollection();
|
|
||||||
services.AddIdentityCore<IdentityUser>(options =>
|
|
||||||
{
|
|
||||||
options.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
|
|
||||||
});
|
|
||||||
optionsBuilder.UseApplicationServiceProvider(services.BuildServiceProvider());
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_connectionString))
|
if (string.IsNullOrEmpty(_connectionString))
|
||||||
{
|
{
|
||||||
Tenant tenant = _tenantManager.GetTenant();
|
Tenant tenant = _tenantManager.GetTenant();
|
||||||
@@ -75,6 +67,22 @@ namespace Oqtane.Repository
|
|||||||
ActiveDatabase = Activator.CreateInstance(type) as IDatabase;
|
ActiveDatabase = Activator.CreateInstance(type) as IDatabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// specify the SchemaVersion for .NET Identity as it is not being persisted when using AddIdentityCore()
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
services.AddIdentityCore<IdentityUser>(options =>
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_databaseType) && _databaseType.ToLower().Contains("mysql"))
|
||||||
|
{
|
||||||
|
// MySQL does not support some of the newer features of .NET Identity (ie. Passkeys)
|
||||||
|
options.Stores.SchemaVersion = IdentitySchemaVersions.Version2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
options.Stores.SchemaVersion = IdentitySchemaVersions.Version3;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
optionsBuilder.UseApplicationServiceProvider(services.BuildServiceProvider());
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_connectionString) && ActiveDatabase != null)
|
if (!string.IsNullOrEmpty(_connectionString) && ActiveDatabase != null)
|
||||||
{
|
{
|
||||||
optionsBuilder.UseOqtaneDatabase(ActiveDatabase, _connectionString);
|
optionsBuilder.UseOqtaneDatabase(ActiveDatabase, _connectionString);
|
||||||
|
|||||||
@@ -13,11 +13,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.2" />
|
||||||
<PackageReference Include="System.Net.Http.Json" Version="10.0.1" />
|
<PackageReference Include="System.Net.Http.Json" Version="10.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -20,10 +20,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.1" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.2" />
|
||||||
<PackageReference Include="NodaTime" Version="3.2.3" />
|
<PackageReference Include="NodaTime" Version="3.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ namespace Oqtane.Shared
|
|||||||
{
|
{
|
||||||
public class Constants
|
public class Constants
|
||||||
{
|
{
|
||||||
public static readonly string Version = "10.0.3";
|
public static readonly string Version = "10.0.4";
|
||||||
public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0,5.1.1,5.1.2,5.2.0,5.2.1,5.2.2,5.2.3,5.2.4,6.0.0,6.0.1,6.1.0,6.1.1,6.1.2,6.1.3,6.1.4,6.1.5,6.2.0,6.2.1,10.0.0,10.0.1,10.0.2,10.0.3";
|
public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0,5.1.1,5.1.2,5.2.0,5.2.1,5.2.2,5.2.3,5.2.4,6.0.0,6.0.1,6.1.0,6.1.1,6.1.2,6.1.3,6.1.4,6.1.5,6.2.0,6.2.1,10.0.0,10.0.1,10.0.2,10.0.3,10.0.4";
|
||||||
public const string PackageId = "Oqtane.Framework";
|
public const string PackageId = "Oqtane.Framework";
|
||||||
public const string ClientId = "Oqtane.Client";
|
public const string ClientId = "Oqtane.Client";
|
||||||
public const string UpdaterPackageId = "Oqtane.Updater";
|
public const string UpdaterPackageId = "Oqtane.Updater";
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Oqtane is being developed based on some fundamental principles which are outline
|
|||||||
|
|
||||||
# Latest Release
|
# Latest Release
|
||||||
|
|
||||||
[10.0.3](https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.3) was released on December 24, 2025 and is a maintenance release including 19 pull requests by 2 different contributors, pushing the total number of project commits all-time to nearly 7500. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
|
[10.0.4](https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4) was released on January 20, 2026 and is a maintenance release including 27 pull requests by 3 different contributors, pushing the total number of project commits all-time over 7500. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
|
||||||
|
|
||||||
# Try It Now!
|
# Try It Now!
|
||||||
|
|
||||||
@@ -111,6 +111,9 @@ Connect with other developers, get support, and share ideas by joining the Oqtan
|
|||||||
# Roadmap
|
# Roadmap
|
||||||
This project is open source, and therefore is a work in progress...
|
This project is open source, and therefore is a work in progress...
|
||||||
|
|
||||||
|
[10.0.4](https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4) (Jan 20, 2026)
|
||||||
|
- [x] Stabilization improvements
|
||||||
|
|
||||||
[10.0.3](https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.3) (Dec 24, 2025)
|
[10.0.3](https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.3) (Dec 24, 2025)
|
||||||
- [x] Stabilization improvements
|
- [x] Stabilization improvements
|
||||||
|
|
||||||
|
|||||||
@@ -220,7 +220,7 @@
|
|||||||
"apiVersion": "2024-04-01",
|
"apiVersion": "2024-04-01",
|
||||||
"name": "[concat(parameters('BlazorWebsiteName'), '/ZipDeploy')]",
|
"name": "[concat(parameters('BlazorWebsiteName'), '/ZipDeploy')]",
|
||||||
"properties": {
|
"properties": {
|
||||||
"packageUri": "https://github.com/oqtane/oqtane.framework/releases/download/v10.0.3/Oqtane.Framework.10.0.3.Install.zip"
|
"packageUri": "https://github.com/oqtane/oqtane.framework/releases/download/v10.0.4/Oqtane.Framework.10.0.4.Install.zip"
|
||||||
},
|
},
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"[resourceId('Microsoft.Web/sites', parameters('BlazorWebsiteName'))]"
|
"[resourceId('Microsoft.Web/sites', parameters('BlazorWebsiteName'))]"
|
||||||
|
|||||||
Reference in New Issue
Block a user