6.1.4 Release
6.1.4 Release
This commit is contained in:
@ -53,8 +53,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
services.AddScoped<ISyncService, SyncService>();
|
services.AddScoped<ISyncService, SyncService>();
|
||||||
services.AddScoped<ILocalizationCookieService, LocalizationCookieService>();
|
services.AddScoped<ILocalizationCookieService, LocalizationCookieService>();
|
||||||
services.AddScoped<ICookieConsentService, CookieConsentService>();
|
services.AddScoped<ICookieConsentService, CookieConsentService>();
|
||||||
services.AddScoped<IOutputCacheService, OutputCacheService>();
|
|
||||||
services.AddScoped<ITimeZoneService, TimeZoneService>();
|
services.AddScoped<ITimeZoneService, TimeZoneService>();
|
||||||
|
services.AddScoped<IOutputCacheService, OutputCacheService>();
|
||||||
|
|
||||||
// providers
|
// providers
|
||||||
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.QuillJSTextEditor>();
|
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.QuillJSTextEditor>();
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
<input id="starting" type="date" class="form-control" @bind="@_startDate" />
|
<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" placeholder="hh:mm" @bind="@_startTime" />
|
<input id="starting" type="time" class="form-control" @bind="@_startTime" placeholder="hh:mm" required="@(_startDate.HasValue)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -69,7 +69,7 @@
|
|||||||
<input id="ending" type="date" class="form-control" @bind="@_endDate" />
|
<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" />
|
<input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" required="@(_endDate.HasValue)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -82,7 +82,7 @@
|
|||||||
<input id="next" type="date" class="form-control" @bind="@_nextDate" />
|
<input id="next" type="date" class="form-control" @bind="@_nextDate" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<input id="next" type="time" class="form-control" placeholder="hh:mm" @bind="@_nextTime" />
|
<input id="next" type="time" class="form-control" placeholder="hh:mm" @bind="@_nextTime" required="@(_nextDate.HasValue)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -176,10 +176,18 @@
|
|||||||
{
|
{
|
||||||
job.Interval = int.Parse(_interval);
|
job.Interval = int.Parse(_interval);
|
||||||
}
|
}
|
||||||
job.StartDate = LocalToUtc(_startDate.Value.Date.Add(_startTime.Value.TimeOfDay));
|
job.StartDate = _startDate.HasValue && _startTime.HasValue
|
||||||
job.EndDate = LocalToUtc(_endDate.Value.Date.Add(_endTime.Value.TimeOfDay));
|
? LocalToUtc(_startDate.GetValueOrDefault().Date.Add(_startTime.GetValueOrDefault().TimeOfDay))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
job.EndDate = _endDate.HasValue && _endTime.HasValue
|
||||||
|
? LocalToUtc(_endDate.GetValueOrDefault().Date.Add(_endTime.GetValueOrDefault().TimeOfDay))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
job.NextExecution = _nextDate.HasValue && _nextTime.HasValue
|
||||||
|
? LocalToUtc(_nextDate.GetValueOrDefault().Date.Add(_nextTime.GetValueOrDefault().TimeOfDay))
|
||||||
|
: null;
|
||||||
job.RetentionHistory = int.Parse(_retentionHistory);
|
job.RetentionHistory = int.Parse(_retentionHistory);
|
||||||
job.NextExecution = LocalToUtc(_nextDate.Value.Date.Add(_nextTime.Value.TimeOfDay));
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -198,5 +206,4 @@
|
|||||||
AddModuleMessage(Localizer["Message.Required.JobInfo"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.Required.JobInfo"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,7 @@ else
|
|||||||
@if (_allowexternallogin)
|
@if (_allowexternallogin)
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-primary" @onclick="ExternalLogin">@Localizer["Use"] @PageState.Site.Settings["ExternalLogin:ProviderName"]</button>
|
<button type="button" class="btn btn-primary" @onclick="ExternalLogin">@Localizer["Use"] @PageState.Site.Settings["ExternalLogin:ProviderName"]</button>
|
||||||
<br />
|
<br /><br />
|
||||||
|
|
||||||
<br />
|
|
||||||
}
|
}
|
||||||
@if (_allowsitelogin)
|
@if (_allowsitelogin)
|
||||||
{
|
{
|
||||||
@ -49,15 +47,11 @@ else
|
|||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-primary" @onclick="Login">@SharedLocalizer["Login"]</button>
|
<button type="button" class="btn btn-primary" @onclick="Login">@SharedLocalizer["Login"]</button>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
<br />
|
<br /><br />
|
||||||
|
|
||||||
<br />
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Forgot">@Localizer["ForgotPassword"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Forgot">@Localizer["ForgotPassword"]</button>
|
||||||
@if (PageState.Site.AllowRegistration)
|
@if (PageState.Site.AllowRegistration)
|
||||||
{
|
{
|
||||||
<br />
|
<br /><br />
|
||||||
|
|
||||||
<br />
|
|
||||||
<NavLink href="@NavigateUrl("register")">@Localizer["Register"]</NavLink>
|
<NavLink href="@NavigateUrl("register")">@Localizer["Register"]</NavLink>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@ else
|
|||||||
<div class="row mb-3 align-items-center">
|
<div class="row mb-3 align-items-center">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<ActionLink Action="Add" Text="Install Module" ResourceKey="InstallModule" />
|
<ActionLink Action="Add" Text="Install Module" ResourceKey="InstallModule" />
|
||||||
<ActionLink Action="Create" Text="Create Module" ResourceKey="CreateModule" Class="btn btn-secondary ps-2" />
|
<ActionLink Action="Create" Text="Create Module" ResourceKey="CreateModule" Class="btn btn-secondary ms-1" />
|
||||||
<button type="button" class="btn btn-secondary pw-2" @onclick="@Synchronize">@Localizer["Synchronize"]</button>
|
<button type="button" class="btn btn-secondary ms-1" @onclick="@Synchronize">@Localizer["Synchronize"]</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
@inject ITimeZoneService TimeZoneService
|
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
|
@inject ITimeZoneService TimeZoneService
|
||||||
|
|
||||||
@if (_initialized)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
@ -115,7 +115,7 @@
|
|||||||
{
|
{
|
||||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||||
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
|
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
|
||||||
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
_timezones = TimeZoneService.GetTimeZones();
|
||||||
_timezoneid = PageState.Site.TimeZoneId;
|
_timezoneid = PageState.Site.TimeZoneId;
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
<Row>
|
<Row>
|
||||||
<div class="search-item mb-2">
|
<div class="search-item mb-2">
|
||||||
<h4 class="mb-1"><a href="@context.Url">@context.Title</a></h4>
|
<h4 class="mb-1"><a href="@context.Url">@context.Title</a></h4>
|
||||||
<p class="mb-0 text-muted">@((MarkupString)context.Snippet)</p>
|
<p class="mb-0 text-body-secondary">@((MarkupString)context.Snippet)</p>
|
||||||
</div>
|
</div>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
|
@ -193,6 +193,17 @@
|
|||||||
</Section>
|
</Section>
|
||||||
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="smtpenabled" HelpText="Specify if SMTP is enabled for this site" ResourceKey="SmtpEnabled">Enabled? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="smtpenabled" class="form-select" value="@_smtpenabled" @onchange="(e => SMTPEnabledChanged(e))">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (_smtpenabled == "True")
|
||||||
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
</div>
|
</div>
|
||||||
@ -213,7 +224,7 @@
|
|||||||
</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="smtpssl" HelpText="Specify if SSL is required for your SMTP server" ResourceKey="UseSsl">SSL Enabled: </Label>
|
<Label Class="col-sm-3" For="smtpssl" HelpText="Specify if SSL is required for your SMTP server" ResourceKey="SmtpSSL">SSL Required: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="smtpssl" class="form-select" @bind="@_smtpssl" >
|
<select id="smtpssl" class="form-select" @bind="@_smtpssl" >
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
@ -221,29 +232,34 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="smtpauthentication" HelpText="Specify the SMTP authentication type" ResourceKey="SMTPAuthentication">Authentication: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="smtpauthentication" class="form-select" value="@_smtpauthentication" @onchange="(e => SMTPAuthenticationChanged(e))">
|
||||||
|
<option value="Basic">@Localizer["Basic"]</option>
|
||||||
|
<option value="OAuth2">@Localizer["OAuth2"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (_smtpauthentication == "Basic")
|
||||||
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="username" HelpText="Enter the username for your SMTP account" ResourceKey="SmtpUsername">Username: </Label>
|
<Label Class="col-sm-3" For="username" HelpText="Enter the username for your SMTP account" ResourceKey="SmtpUsername">Username: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="username" class="form-control" @bind="@_smtpusername" autocomplete="off"/>
|
<input id="username" class="form-control" @bind="@_smtpusername" autocomplete="off" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="password" HelpText="Enter the password for your SMTP account" ResourceKey="SmtpPassword">Password: </Label>
|
<Label Class="col-sm-3" For="password" HelpText="Enter the password for your SMTP account" ResourceKey="SmtpPassword">Password: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" autocomplete="off"/>
|
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" autocomplete="off" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleSMTPPassword" tabindex="-1">@_togglesmtppassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleSMTPPassword" tabindex="-1">@_togglesmtppassword</button>
|
||||||
</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="sender" HelpText="Enter the email which emails will be sent from. Please note that this email address may need to be authorized with the SMTP server." ResourceKey="SmtpSender">Email Sender: </Label>
|
<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">
|
|
||||||
<input id="sender" class="form-control" @bind="@_smtpsender" />
|
|
||||||
</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 above." ResourceKey="SmtpRelay">Relay Configured? </Label>
|
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="relay" class="form-select" @bind="@_smtprelay" required>
|
<select id="relay" class="form-select" @bind="@_smtprelay" required>
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
@ -251,13 +267,41 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="smtpenabled" HelpText="Specify if SMTP is enabled for this site" ResourceKey="SMTPEnabled">Enabled? </Label>
|
<Label Class="col-sm-3" For="smtpauthority" HelpText="The Authority Url for the SMTP provider" ResourceKey="SmtpAuthority">Authority Url:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="smtpenabled" class="form-select" @bind="@_smtpenabled">
|
<input id="smtpauthority" class="form-control" @bind="@_smtpauthority" />
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
</div>
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
</div>
|
||||||
</select>
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="smtpclientid" HelpText="The Client ID for the SMTP provider" ResourceKey="SmtpClientID">Client ID:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="smtpclientid" class="form-control" @bind="@_smtpclientid" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="smtpclientsecret" HelpText="The Client Secret for the SMTP provider" ResourceKey="SmtpClientSecret">Client Secret:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="@_smtpclientsecrettype" id="smtpclientsecret" class="form-control" @bind="@_smtpclientsecret" />
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleSmtpClientSecret">@_togglesmtpclientsecret</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="smtpscopes" HelpText="A list of Scopes for the SMTP provider (separated by commas)" ResourceKey="SmtpScopes">Scopes:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="smtpscopes" class="form-control" @bind="@_smtpscopes" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="sender" HelpText="Enter the email address which emails will be sent from. Please note that this email address usually needs to be authorized with the SMTP provider." ResourceKey="SmtpSender">Email Sender: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="sender" class="form-control" @bind="@_smtpsender" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -268,6 +312,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="SendEmail">@Localizer["Smtp.TestConfig"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="SendEmail">@Localizer["Smtp.TestConfig"]</button>
|
||||||
<br /><br />
|
<br /><br />
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="PWA" Heading="Progressive Web Application Settings" ResourceKey="PWASettings">
|
<Section Name="PWA" Heading="Progressive Web Application Settings" ResourceKey="PWASettings">
|
||||||
@ -455,16 +500,23 @@
|
|||||||
private string _headcontent = string.Empty;
|
private string _headcontent = string.Empty;
|
||||||
private string _bodycontent = string.Empty;
|
private string _bodycontent = string.Empty;
|
||||||
|
|
||||||
|
private string _smtpenabled = "False";
|
||||||
|
private string _smtpauthentication = "Basic";
|
||||||
private string _smtphost = string.Empty;
|
private string _smtphost = string.Empty;
|
||||||
private string _smtpport = string.Empty;
|
private string _smtpport = string.Empty;
|
||||||
private string _smtpssl = "False";
|
private string _smtpssl = "True";
|
||||||
private string _smtpusername = string.Empty;
|
private string _smtpusername = string.Empty;
|
||||||
private string _smtppassword = string.Empty;
|
private string _smtppassword = string.Empty;
|
||||||
private string _smtppasswordtype = "password";
|
private string _smtppasswordtype = "password";
|
||||||
private string _togglesmtppassword = string.Empty;
|
private string _togglesmtppassword = string.Empty;
|
||||||
|
private string _smtpauthority = string.Empty;
|
||||||
|
private string _smtpclientid = string.Empty;
|
||||||
|
private string _smtpclientsecret = string.Empty;
|
||||||
|
private string _smtpclientsecrettype = "password";
|
||||||
|
private string _togglesmtpclientsecret = string.Empty;
|
||||||
|
private string _smtpscopes = string.Empty;
|
||||||
private string _smtpsender = string.Empty;
|
private string _smtpsender = string.Empty;
|
||||||
private string _smtprelay = "False";
|
private string _smtprelay = "False";
|
||||||
private string _smtpenabled = "True";
|
|
||||||
private int _retention = 30;
|
private int _retention = 30;
|
||||||
|
|
||||||
private string _pwaisenabled;
|
private string _pwaisenabled;
|
||||||
@ -508,7 +560,7 @@
|
|||||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||||
if (site != null)
|
if (site != null)
|
||||||
{
|
{
|
||||||
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
_timezones = TimeZoneService.GetTimeZones();
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||||
|
|
||||||
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
@ -556,15 +608,21 @@
|
|||||||
_bodycontent = site.BodyContent;
|
_bodycontent = site.BodyContent;
|
||||||
|
|
||||||
// SMTP
|
// SMTP
|
||||||
|
_smtpenabled = SettingService.GetSetting(settings, "SMTPEnabled", "False");
|
||||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
||||||
|
_smtpauthentication = SettingService.GetSetting(settings, "SMTPAuthentication", "Basic");
|
||||||
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
||||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||||
|
_smtpauthority = SettingService.GetSetting(settings, "SMTPAuthority", string.Empty);
|
||||||
|
_smtpclientid = SettingService.GetSetting(settings, "SMTPClientId", string.Empty);
|
||||||
|
_smtpclientsecret = SettingService.GetSetting(settings, "SMTPClientSecret", string.Empty);
|
||||||
|
_togglesmtpclientsecret = SharedLocalizer["ShowPassword"];
|
||||||
|
_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");
|
_smtprelay = SettingService.GetSetting(settings, "SMTPRelay", "False");
|
||||||
_smtpenabled = SettingService.GetSetting(settings, "SMTPEnabled", "True");
|
|
||||||
_retention = int.Parse(SettingService.GetSetting(settings, "NotificationRetention", "30"));
|
_retention = int.Parse(SettingService.GetSetting(settings, "NotificationRetention", "30"));
|
||||||
|
|
||||||
// PWA
|
// PWA
|
||||||
@ -745,8 +803,13 @@
|
|||||||
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);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPAuthentication", _smtpauthentication, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPAuthority", _smtpauthority, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPClientId", _smtpclientid, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPClientSecret", _smtpclientsecret, 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, "SMTPRelay", _smtprelay, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
||||||
@ -813,6 +876,46 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SMTPAuthenticationChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_smtpauthentication = (string)e.Value;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SMTPEnabledChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_smtpenabled = (string)e.Value;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleSMTPPassword()
|
||||||
|
{
|
||||||
|
if (_smtppasswordtype == "password")
|
||||||
|
{
|
||||||
|
_smtppasswordtype = "text";
|
||||||
|
_togglesmtppassword = SharedLocalizer["HidePassword"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_smtppasswordtype = "password";
|
||||||
|
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleSmtpClientSecret()
|
||||||
|
{
|
||||||
|
if (_smtpclientsecrettype == "password")
|
||||||
|
{
|
||||||
|
_smtpclientsecrettype = "text";
|
||||||
|
_togglesmtpclientsecret = SharedLocalizer["HidePassword"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_smtpclientsecrettype = "password";
|
||||||
|
_togglesmtpclientsecret = SharedLocalizer["ShowPassword"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SendEmail()
|
private async Task SendEmail()
|
||||||
{
|
{
|
||||||
if (_smtphost != "" && _smtpport != "" && _smtpsender != "")
|
if (_smtphost != "" && _smtpport != "" && _smtpsender != "")
|
||||||
@ -823,8 +926,13 @@
|
|||||||
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);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPAuthentication", _smtpauthentication, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPAuthority", _smtpauthority, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPClientId", _smtpclientid, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPClientSecret", _smtpclientsecret, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPScopes", _smtpscopes, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||||
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");
|
||||||
@ -845,20 +953,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleSMTPPassword()
|
|
||||||
{
|
|
||||||
if (_smtppasswordtype == "password")
|
|
||||||
{
|
|
||||||
_smtppasswordtype = "text";
|
|
||||||
_togglesmtppassword = SharedLocalizer["HidePassword"];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_smtppasswordtype = "password";
|
|
||||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task GetAliases()
|
private async Task GetAliases()
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Install Theme" ResourceKey="InstallTheme" />
|
<ActionLink Action="Add" Text="Install Theme" ResourceKey="InstallTheme" />
|
||||||
<ActionLink Action="Create" Text="Create Theme" ResourceKey="CreateTheme" Class="btn btn-secondary ps-2" />
|
<ActionLink Action="Create" Text="Create Theme" ResourceKey="CreateTheme" Class="btn btn-secondary ms-1" />
|
||||||
<button type="button" class="btn btn-secondary pw-2" @onclick="@Synchronize">@Localizer["Synchronize"]</button>
|
<button type="button" class="btn btn-secondary ms-1" @onclick="@Synchronize">@Localizer["Synchronize"]</button>
|
||||||
|
|
||||||
<Pager Items="@_themes">
|
<Pager Items="@_themes">
|
||||||
<Header>
|
<Header>
|
||||||
|
@ -367,7 +367,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Models.TimeZone> _timezones;
|
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private string _passwordrequirements;
|
private string _passwordrequirements;
|
||||||
private string _username = string.Empty;
|
private string _username = string.Empty;
|
||||||
@ -381,6 +380,7 @@
|
|||||||
private string _displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
private FileManager _filemanager;
|
private FileManager _filemanager;
|
||||||
private int _folderid = -1;
|
private int _folderid = -1;
|
||||||
|
private List<Models.TimeZone> _timezones;
|
||||||
private string _timezoneid = string.Empty;
|
private string _timezoneid = string.Empty;
|
||||||
private int _photofileid = -1;
|
private int _photofileid = -1;
|
||||||
private File _photo = null;
|
private File _photo = null;
|
||||||
@ -404,7 +404,7 @@
|
|||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
_allowtwofactor = (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "true");
|
_allowtwofactor = (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "true");
|
||||||
_profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
_profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||||
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
_timezones = TimeZoneService.GetTimeZones();
|
||||||
|
|
||||||
if (PageState.User != null)
|
if (PageState.User != null)
|
||||||
{
|
{
|
||||||
@ -414,11 +414,6 @@
|
|||||||
_displayname = PageState.User.DisplayName;
|
_displayname = PageState.User.DisplayName;
|
||||||
_timezoneid = PageState.User.TimeZoneId;
|
_timezoneid = PageState.User.TimeZoneId;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_email))
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.User.NoEmail"], MessageType.Warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get user folder
|
// get user folder
|
||||||
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
|
@ -28,6 +28,15 @@
|
|||||||
<input id="email" class="form-control" @bind="@_email" />
|
<input id="email" class="form-control" @bind="@_email" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="confirmed" HelpText="Indicates if the user's email is verified" ResourceKey="Confirmed">Verified?</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="confirmed" class="form-select" @bind="@_confirmed">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName"></Label>
|
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -120,6 +129,7 @@
|
|||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private string _username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private string _email = string.Empty;
|
private string _email = string.Empty;
|
||||||
|
private string _confirmed = "True";
|
||||||
private string _displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
private string _timezoneid = string.Empty;
|
private string _timezoneid = string.Empty;
|
||||||
private string _notify = "True";
|
private string _notify = "True";
|
||||||
@ -133,7 +143,7 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
_timezones = TimeZoneService.GetTimeZones();
|
||||||
_profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
_profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||||
_settings = new Dictionary<string, string>();
|
_settings = new Dictionary<string, string>();
|
||||||
_timezoneid = PageState.Site.TimeZoneId;
|
_timezoneid = PageState.Site.TimeZoneId;
|
||||||
@ -169,6 +179,7 @@
|
|||||||
user.Username = _username;
|
user.Username = _username;
|
||||||
user.Password = ""; // will be auto generated
|
user.Password = ""; // will be auto generated
|
||||||
user.Email = _email;
|
user.Email = _email;
|
||||||
|
user.EmailConfirmed = bool.Parse(_confirmed);
|
||||||
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
||||||
user.TimeZoneId = _timezoneid;
|
user.TimeZoneId = _timezoneid;
|
||||||
user.PhotoFileId = null;
|
user.PhotoFileId = null;
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
</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="confirmed" HelpText="Indicates if the user's email is verified" ResourceKey="Confirmed">Confirmed?</Label>
|
<Label Class="col-sm-3" For="confirmed" HelpText="Indicates if the user's email is verified" ResourceKey="Confirmed">Verified?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="confirmed" class="form-select" @bind="@_confirmed">
|
<select id="confirmed" class="form-select" @bind="@_confirmed">
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
@ -159,7 +159,7 @@
|
|||||||
}
|
}
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && _isdeleted == "True")
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && _isdeleted == "True")
|
||||||
{
|
{
|
||||||
<ActionDialog Header="Delete User" Message="Are You Sure You Wish To Permanently Delete This User?" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteUser())" ResourceKey="DeleteUser" />
|
<ActionDialog Header="Delete User" Message="Are You Sure You Wish To Permanently Delete This User?" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger ms-1" OnClick="@(async () => await DeleteUser())" ResourceKey="DeleteUser" />
|
||||||
}
|
}
|
||||||
<br /><br />
|
<br /><br />
|
||||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
||||||
@ -204,7 +204,7 @@
|
|||||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
_profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
_profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
||||||
_timezones = await TimeZoneService.GetTimeZonesAsync();
|
_timezones = TimeZoneService.GetTimeZones();
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int UserId))
|
if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int UserId))
|
||||||
{
|
{
|
||||||
|
@ -74,10 +74,19 @@ else
|
|||||||
<input id="profileurl" class="form-control" @bind="@_profileurl" />
|
<input id="profileurl" class="form-control" @bind="@_profileurl" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="requireconfirmedemail" HelpText="Do you want to require registered users to verify their email address before they are allowed to log in?" ResourceKey="RequireConfirmedEmail">Require Verified Email?</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="requireconfirmedemail" class="form-select" @bind="@_requireconfirmedemail">
|
||||||
|
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="false">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="twofactor" HelpText="Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out." ResourceKey="TwoFactor">Two Factor?</Label>
|
<Label Class="col-sm-3" For="twofactor" HelpText="Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out." ResourceKey="TwoFactor">Two Factor Authentication?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="twofactor" class="form-select" @bind="@_twofactor">
|
<select id="twofactor" class="form-select" @bind="@_twofactor">
|
||||||
<option value="false">@Localizer["Disabled"]</option>
|
<option value="false">@Localizer["Disabled"]</option>
|
||||||
@ -490,6 +499,7 @@ else
|
|||||||
private string _allowregistration;
|
private string _allowregistration;
|
||||||
private string _registerurl;
|
private string _registerurl;
|
||||||
private string _profileurl;
|
private string _profileurl;
|
||||||
|
private string _requireconfirmedemail;
|
||||||
private string _twofactor;
|
private string _twofactor;
|
||||||
private string _cookiename;
|
private string _cookiename;
|
||||||
private string _cookieexpiration;
|
private string _cookieexpiration;
|
||||||
@ -560,6 +570,7 @@ else
|
|||||||
_allowregistration = PageState.Site.AllowRegistration.ToString().ToLower();
|
_allowregistration = PageState.Site.AllowRegistration.ToString().ToLower();
|
||||||
_registerurl = SettingService.GetSetting(settings, "LoginOptions:RegisterUrl", "");
|
_registerurl = SettingService.GetSetting(settings, "LoginOptions:RegisterUrl", "");
|
||||||
_profileurl = SettingService.GetSetting(settings, "LoginOptions:ProfileUrl", "");
|
_profileurl = SettingService.GetSetting(settings, "LoginOptions:ProfileUrl", "");
|
||||||
|
_requireconfirmedemail = SettingService.GetSetting(settings, "LoginOptions:RequireConfirmedEmail", "true");
|
||||||
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
@ -685,6 +696,7 @@ else
|
|||||||
{
|
{
|
||||||
settings = SettingService.SetSetting(settings, "LoginOptions:RegisterUrl", _registerurl, false);
|
settings = SettingService.SetSetting(settings, "LoginOptions:RegisterUrl", _registerurl, false);
|
||||||
settings = SettingService.SetSetting(settings, "LoginOptions:ProfileUrl", _profileurl, false);
|
settings = SettingService.SetSetting(settings, "LoginOptions:ProfileUrl", _profileurl, false);
|
||||||
|
settings = SettingService.SetSetting(settings, "LoginOptions:RequireConfirmedEmail", _requireconfirmedemail, false);
|
||||||
settings = SettingService.SetSetting(settings, "LoginOptions:TwoFactor", _twofactor, false);
|
settings = SettingService.SetSetting(settings, "LoginOptions:TwoFactor", _twofactor, false);
|
||||||
settings = SettingService.SetSetting(settings, "LoginOptions:CookieName", _cookiename, true);
|
settings = SettingService.SetSetting(settings, "LoginOptions:CookieName", _cookiename, true);
|
||||||
settings = SettingService.SetSetting(settings, "LoginOptions:CookieExpiration", _cookieexpiration, true);
|
settings = SettingService.SetSetting(settings, "LoginOptions:CookieExpiration", _cookieexpiration, true);
|
||||||
|
@ -157,6 +157,9 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool AnonymizeUploadFilenames { get; set; } = false; // optional - indicate if file names should be anonymized on upload - default false
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int ChunkSize { get; set; } = 1; // optional - size of file chunks to upload in MB
|
public int ChunkSize { get; set; } = 1; // optional - size of file chunks to upload in MB
|
||||||
|
|
||||||
@ -408,7 +411,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// upload files
|
// upload files
|
||||||
var success = await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken, jwt, chunksize, tokenSource.Token);
|
var success = await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken, jwt, chunksize, AnonymizeUploadFilenames, tokenSource.Token);
|
||||||
|
|
||||||
// reset progress indicators
|
// reset progress indicators
|
||||||
if (ShowProgress)
|
if (ShowProgress)
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
@if (_permissions != null)
|
@if (_permissions != null)
|
||||||
{
|
{
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
@ -28,7 +28,7 @@
|
|||||||
@foreach (var permissionname in _permissionnames)
|
@foreach (var permissionname in _permissionnames)
|
||||||
{
|
{
|
||||||
<td style="text-align: center;">
|
<td style="text-align: center;">
|
||||||
<TriStateCheckBox Value=@GetPermissionValue(permissionname, role.Name, -1) Disabled="@GetPermissionDisabled(permissionname, role.Name)" OnChange="@(e => PermissionChanged(e, permissionname, role.Name, -1))" />
|
<TriStateCheckBox Value="@GetPermissionValue(permissionname, role.Name, -1)" Disabled="@GetPermissionDisabled(permissionname, role.Name)" OnChange="@(e => PermissionChanged(e, permissionname, role.Name, -1))" />
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
@ -64,7 +64,7 @@
|
|||||||
@foreach (var permissionname in _permissionnames)
|
@foreach (var permissionname in _permissionnames)
|
||||||
{
|
{
|
||||||
<td style="text-align: center; width: 1px;">
|
<td style="text-align: center; width: 1px;">
|
||||||
<TriStateCheckBox Value=@GetPermissionValue(permissionname, "", user.UserId) Disabled="@GetPermissionDisabled(permissionname, "")" OnChange="@(e => PermissionChanged(e, permissionname, "", user.UserId))" />
|
<TriStateCheckBox Value="@GetPermissionValue(permissionname, "", user.UserId)" Disabled="@GetPermissionDisabled(permissionname, "")" OnChange="@(e => PermissionChanged(e, permissionname, "", user.UserId))" />
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
@ -88,7 +88,7 @@
|
|||||||
<ModuleMessage Type="MessageType.Warning" Message="@_message" />
|
<ModuleMessage Type="MessageType.Warning" Message="@_message" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
@ -119,10 +119,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId, true);
|
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId, true);
|
||||||
if (!UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
_roles.RemoveAll(item => item.Name == RoleNames.Host); // remove host role
|
||||||
{
|
|
||||||
_roles.RemoveAll(item => item.Name == RoleNames.Host);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get permission names
|
// get permission names
|
||||||
if (string.IsNullOrEmpty(PermissionNames))
|
if (string.IsNullOrEmpty(PermissionNames))
|
||||||
@ -222,24 +219,24 @@
|
|||||||
|
|
||||||
private bool GetPermissionDisabled(string permissionName, string roleName)
|
private bool GetPermissionDisabled(string permissionName, string roleName)
|
||||||
{
|
{
|
||||||
|
var disabled = false;
|
||||||
|
|
||||||
|
// administrator role permissions can only be changed by a host
|
||||||
if (roleName == RoleNames.Admin && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (roleName == RoleNames.Admin && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
return true;
|
disabled = true;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (GetEntityName(permissionName) != EntityName && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PermissionChanged(bool? value, string permissionName, string roleName, int userId)
|
// API permissions can only be changed by an administrator
|
||||||
|
if (GetEntityName(permissionName) != EntityName && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
|
{
|
||||||
|
disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool? PermissionChanged(bool? value, string permissionName, string roleName, int userId)
|
||||||
{
|
{
|
||||||
if (roleName != "")
|
if (roleName != "")
|
||||||
{
|
{
|
||||||
@ -248,6 +245,14 @@
|
|||||||
{
|
{
|
||||||
_permissions.Remove(permission);
|
_permissions.Remove(permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// system roles cannot be denied - only custom roles can be denied
|
||||||
|
var role = _roles.FirstOrDefault(item => item.Name == roleName);
|
||||||
|
if (value != null && !value.Value && role.IsSystem)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionName), GetPermissionName(permissionName), roleName, null, value.Value));
|
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionName), GetPermissionName(permissionName), roleName, null, value.Value));
|
||||||
@ -265,6 +270,7 @@
|
|||||||
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionName), GetPermissionName(permissionName), null, userId, value.Value));
|
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionName), GetPermissionName(permissionName), null, userId, value.Value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Dictionary<string, string>> GetUsers(string filter)
|
private async Task<Dictionary<string, string>> GetUsers(string filter)
|
||||||
@ -305,29 +311,20 @@
|
|||||||
|
|
||||||
private void ValidatePermissions()
|
private void ValidatePermissions()
|
||||||
{
|
{
|
||||||
// remove deny all users, unauthenticated, and registered users
|
|
||||||
var permissions = _permissions.Where(item => !item.IsAuthorized &&
|
|
||||||
(item.RoleName == RoleNames.Everyone || item.RoleName == RoleNames.Unauthenticated || item.RoleName == RoleNames.Registered)).ToList();
|
|
||||||
foreach (var permission in permissions)
|
|
||||||
{
|
|
||||||
_permissions.Remove(permission);
|
|
||||||
}
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
// remove deny administrators and host users
|
// remove host role permissions
|
||||||
permissions = _permissions.Where(item => !item.IsAuthorized &&
|
var permissions = _permissions.Where(item => item.RoleName == RoleNames.Host).ToList();
|
||||||
(item.RoleName == RoleNames.Admin || item.RoleName == RoleNames.Host)).ToList();
|
|
||||||
foreach (var permission in permissions)
|
foreach (var permission in permissions)
|
||||||
{
|
{
|
||||||
_permissions.Remove(permission);
|
_permissions.Remove(permission);
|
||||||
}
|
}
|
||||||
|
// add host role permissions if administrator role is not assigned (to prevent lockout)
|
||||||
foreach (var permissionname in _permissionnames)
|
foreach (var permissionname in _permissionnames)
|
||||||
{
|
{
|
||||||
// add administrators role if neither host or administrator is assigned
|
if (!_permissions.Any(item => item.EntityName == GetEntityName(permissionname) && item.PermissionName == GetPermissionName(permissionname) && item.RoleName == RoleNames.Admin))
|
||||||
if (!_permissions.Any(item => item.EntityName == GetEntityName(permissionname) && item.PermissionName == GetPermissionName(permissionname) &&
|
|
||||||
(item.RoleName == RoleNames.Admin || item.RoleName == RoleNames.Host)))
|
|
||||||
{
|
{
|
||||||
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionname), GetPermissionName(permissionname), RoleNames.Admin, null, true));
|
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionname), GetPermissionName(permissionname), RoleNames.Host, null, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
public bool Disabled { get; set; }
|
public bool Disabled { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Action<bool?> OnChange { get; set; }
|
public Func<bool?, bool?> OnChange { get; set; }
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
@ -41,12 +41,14 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_value = OnChange(_value);
|
||||||
SetImage();
|
SetImage();
|
||||||
OnChange(_value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetImage()
|
private void SetImage()
|
||||||
|
{
|
||||||
|
if (!Disabled)
|
||||||
{
|
{
|
||||||
switch (_value)
|
switch (_value)
|
||||||
{
|
{
|
||||||
@ -63,6 +65,12 @@
|
|||||||
_title = string.Empty;
|
_title = string.Empty;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_src = "images/disabled.png";
|
||||||
|
_title = Localizer["PermissionDisabled"];
|
||||||
|
}
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
@ -500,33 +500,45 @@ namespace Oqtane.Modules
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// date methods
|
// date conversion methods
|
||||||
public DateTime? UtcToLocal(DateTime? datetime)
|
public DateTime? UtcToLocal(DateTime? datetime)
|
||||||
{
|
{
|
||||||
TimeZoneInfo timezone = null;
|
// Early return if input is null
|
||||||
|
if (datetime == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
string timezoneId = null;
|
||||||
|
|
||||||
if (PageState.User != null && !string.IsNullOrEmpty(PageState.User.TimeZoneId))
|
if (PageState.User != null && !string.IsNullOrEmpty(PageState.User.TimeZoneId))
|
||||||
{
|
{
|
||||||
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.User.TimeZoneId);
|
timezoneId = PageState.User.TimeZoneId;
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(PageState.Site.TimeZoneId))
|
else if (!string.IsNullOrEmpty(PageState.Site.TimeZoneId))
|
||||||
{
|
{
|
||||||
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.Site.TimeZoneId);
|
timezoneId = PageState.Site.TimeZoneId;
|
||||||
}
|
}
|
||||||
return Utilities.UtcAsLocalDateTime(datetime, timezone);
|
|
||||||
|
return Utilities.UtcAsLocalDateTime(datetime, timezoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime? LocalToUtc(DateTime? datetime)
|
public DateTime? LocalToUtc(DateTime? datetime)
|
||||||
{
|
{
|
||||||
TimeZoneInfo timezone = null;
|
// Early return if input is null
|
||||||
|
if (datetime == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
string timezoneId = null;
|
||||||
|
|
||||||
if (PageState.User != null && !string.IsNullOrEmpty(PageState.User.TimeZoneId))
|
if (PageState.User != null && !string.IsNullOrEmpty(PageState.User.TimeZoneId))
|
||||||
{
|
{
|
||||||
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.User.TimeZoneId);
|
timezoneId = PageState.User.TimeZoneId;
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(PageState.Site.TimeZoneId))
|
else if (!string.IsNullOrEmpty(PageState.Site.TimeZoneId))
|
||||||
{
|
{
|
||||||
timezone = TimeZoneInfo.FindSystemTimeZoneById(PageState.Site.TimeZoneId);
|
timezoneId = PageState.Site.TimeZoneId;
|
||||||
}
|
}
|
||||||
return Utilities.LocalDateAndTimeAsUtc(datetime, timezone);
|
|
||||||
|
return Utilities.LocalDateAndTimeAsUtc(datetime, timezoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// logging methods
|
// logging methods
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>6.1.3</Version>
|
<Version>6.1.4</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -12,7 +12,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/v6.1.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
@ -22,10 +22,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
<value>External Login Could Not Be Linked. Please Contact Your Administrator For Further Instructions.</value>
|
<value>External Login Could Not Be Linked. Please Contact Your Administrator For Further Instructions.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Login.Fail" xml:space="preserve">
|
<data name="Error.Login.Fail" xml:space="preserve">
|
||||||
<value>Login Failed. Please Remember That Passwords Are Case Sensitive. If You Have Attempted To Sign In Multiple Times Unsuccessfully, Your Account Will Be Locked Out For A Period Of Time. Note That User Accounts Often Require Email Address Verification So You May Wish To Check Your Email For A Notification.</value>
|
<value>Login Failed. Please Remember That Passwords Are Case Sensitive. If You Have Attempted To Sign In Multiple Times Unsuccessfully, Your Account Will Be Locked Out For A Period Of Time. Note That New User Accounts Often Require Email Address Verification So You May Wish To Check Your Email For A Notification Containing Further Instructions.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Required.UserInfo" xml:space="preserve">
|
<data name="Message.Required.UserInfo" xml:space="preserve">
|
||||||
<value>Please Provide All Required Fields</value>
|
<value>Please Provide All Required Fields</value>
|
||||||
|
@ -192,7 +192,7 @@
|
|||||||
<data name="Port.HelpText" xml:space="preserve">
|
<data name="Port.HelpText" xml:space="preserve">
|
||||||
<value>Enter the port number for the SMTP server. Please note this field is required if you provide a host name.</value>
|
<value>Enter the port number for the SMTP server. Please note this field is required if you provide a host name.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UseSsl.HelpText" xml:space="preserve">
|
<data name="SmtpSSL.HelpText" xml:space="preserve">
|
||||||
<value>Specify if SSL is required for your SMTP server</value>
|
<value>Specify if SSL is required for your SMTP server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SmtpUsername.HelpText" xml:space="preserve">
|
<data name="SmtpUsername.HelpText" xml:space="preserve">
|
||||||
@ -202,7 +202,7 @@
|
|||||||
<value>Enter the password for your SMTP account</value>
|
<value>Enter the password for your SMTP account</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SmtpSender.HelpText" xml:space="preserve">
|
<data name="SmtpSender.HelpText" xml:space="preserve">
|
||||||
<value>Enter the email which emails will be sent from. Please note that this email address may need to be authorized with the SMTP server.</value>
|
<value>Enter the email address which emails will be sent from. Please note that this email address usually needs to be authorized with the SMTP server.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EnablePWA.HelpText" xml:space="preserve">
|
<data name="EnablePWA.HelpText" xml:space="preserve">
|
||||||
<value>Select whether you would like this site to be available as a Progressive Web Application (PWA)</value>
|
<value>Select whether you would like this site to be available as a Progressive Web Application (PWA)</value>
|
||||||
@ -240,8 +240,8 @@
|
|||||||
<data name="Port.Text" xml:space="preserve">
|
<data name="Port.Text" xml:space="preserve">
|
||||||
<value>Port: </value>
|
<value>Port: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UseSsl.Text" xml:space="preserve">
|
<data name="SmtpSSL.Text" xml:space="preserve">
|
||||||
<value>SSL Enabled: </value>
|
<value>SSL Required: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SmtpUsername.Text" xml:space="preserve">
|
<data name="SmtpUsername.Text" xml:space="preserve">
|
||||||
<value>Username: </value>
|
<value>Username: </value>
|
||||||
@ -372,10 +372,10 @@
|
|||||||
<data name="PageContent.Heading" xml:space="preserve">
|
<data name="PageContent.Heading" xml:space="preserve">
|
||||||
<value>Page Content</value>
|
<value>Page Content</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SMTPEnabled.HelpText" xml:space="preserve">
|
<data name="SmtpEnabled.HelpText" xml:space="preserve">
|
||||||
<value>Specify if SMTP is enabled for this site</value>
|
<value>Specify if SMTP is enabled for this site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SMTPEnabled.Text" xml:space="preserve">
|
<data name="SmtpEnabled.Text" xml:space="preserve">
|
||||||
<value>Enabled?</value>
|
<value>Enabled?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Version.HelpText" xml:space="preserve">
|
<data name="Version.HelpText" xml:space="preserve">
|
||||||
@ -453,4 +453,40 @@
|
|||||||
<data name="TimeZone.HelpText" xml:space="preserve">
|
<data name="TimeZone.HelpText" xml:space="preserve">
|
||||||
<value>The default time zone for the site</value>
|
<value>The default time zone for the site</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Basic" xml:space="preserve">
|
||||||
|
<value>Basic</value>
|
||||||
|
</data>
|
||||||
|
<data name="OAuth2" xml:space="preserve">
|
||||||
|
<value>OAuth 2.0 (OAuth2)</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpAuthentication.Text" xml:space="preserve">
|
||||||
|
<value>Authentication:</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpAuthentication.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the SMTP authentication type</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpClientID.Text" xml:space="preserve">
|
||||||
|
<value>Client ID:</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpClientID.HelpText" xml:space="preserve">
|
||||||
|
<value>The Client ID for the SMTP provider</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpClientSecret.Text" xml:space="preserve">
|
||||||
|
<value>Client Secret:</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpClientSecret.HelpText" xml:space="preserve">
|
||||||
|
<value>The Client Secret for the SMTP provider</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpScopes.Text" xml:space="preserve">
|
||||||
|
<value>Scopes:</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpScopes.HelpText" xml:space="preserve">
|
||||||
|
<value>A list of Scopes for the SMTP provider (separated by commas)</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpAuthority.Text" xml:space="preserve">
|
||||||
|
<value>Authority Url:</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpAuthority.HelpText" xml:space="preserve">
|
||||||
|
<value>The Authority Url for the SMTP provider</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -147,9 +147,6 @@
|
|||||||
<data name="Message.User.NoLogIn" xml:space="preserve">
|
<data name="Message.User.NoLogIn" xml:space="preserve">
|
||||||
<value>Current User Is Not Logged In</value>
|
<value>Current User Is Not Logged In</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.User.NoEmail" xml:space="preserve">
|
|
||||||
<value>You Must Provide An Email Address For Your User Account</value>
|
|
||||||
</data>
|
|
||||||
<data name="Error.Profile.Load" xml:space="preserve">
|
<data name="Error.Profile.Load" xml:space="preserve">
|
||||||
<value>Error Loading User Profile</value>
|
<value>Error Loading User Profile</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -162,4 +162,10 @@
|
|||||||
<data name="TimeZone.HelpText" xml:space="preserve">
|
<data name="TimeZone.HelpText" xml:space="preserve">
|
||||||
<value>The user's time zone</value>
|
<value>The user's time zone</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Confirmed.Text" xml:space="preserve">
|
||||||
|
<value>Verified?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Confirmed.HelpText" xml:space="preserve">
|
||||||
|
<value>Indicates if the user's email is verified</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -217,7 +217,7 @@
|
|||||||
<value>The user's time zone</value>
|
<value>The user's time zone</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Confirmed.Text" xml:space="preserve">
|
<data name="Confirmed.Text" xml:space="preserve">
|
||||||
<value>Confirmed?</value>
|
<value>Verified?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Confirmed.HelpText" xml:space="preserve">
|
<data name="Confirmed.HelpText" xml:space="preserve">
|
||||||
<value>Indicates if the user's email is verified</value>
|
<value>Indicates if the user's email is verified</value>
|
||||||
|
@ -370,7 +370,13 @@
|
|||||||
<value>Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out.</value>
|
<value>Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TwoFactor.Text" xml:space="preserve">
|
<data name="TwoFactor.Text" xml:space="preserve">
|
||||||
<value>Two Factor?</value>
|
<value>Two Factor Authentication?</value>
|
||||||
|
</data>
|
||||||
|
<data name="RequireConfirmedEmail.HelpText" xml:space="preserve">
|
||||||
|
<value>Do you want to require registered users to verify their email address before they are allowed to log in?</value>
|
||||||
|
</data>
|
||||||
|
<data name="RequireConfirmedEmail.Text" xml:space="preserve">
|
||||||
|
<value>Require Verified Email?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Disabled" xml:space="preserve">
|
<data name="Disabled" xml:space="preserve">
|
||||||
<value>Disabled</value>
|
<value>Disabled</value>
|
||||||
@ -502,7 +508,7 @@
|
|||||||
<value>Info</value>
|
<value>Info</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="OAuth2" xml:space="preserve">
|
<data name="OAuth2" xml:space="preserve">
|
||||||
<value>OAuth 2.0</value>
|
<value>OAuth 2.0 (OAuth2)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="OIDC" xml:space="preserve">
|
<data name="OIDC" xml:space="preserve">
|
||||||
<value>OpenID Connect (OIDC)</value>
|
<value>OpenID Connect (OIDC)</value>
|
||||||
|
@ -123,4 +123,7 @@
|
|||||||
<data name="PermissionDenied" xml:space="preserve">
|
<data name="PermissionDenied" xml:space="preserve">
|
||||||
<value>Permission Denied</value>
|
<value>Permission Denied</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="PermissionDisabled" xml:space="preserve">
|
||||||
|
<value>Permission Disabled</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
120
Oqtane.Client/Resources/TimeZoneResources.resx
Normal file
120
Oqtane.Client/Resources/TimeZoneResources.resx
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
@ -256,7 +256,7 @@ namespace Oqtane.Services
|
|||||||
|
|
||||||
Dictionary<string, string> SetSetting(Dictionary<string, string> settings, string settingName, string settingValue, bool isPrivate);
|
Dictionary<string, string> SetSetting(Dictionary<string, string> settings, string settingName, string settingValue, bool isPrivate);
|
||||||
|
|
||||||
Dictionary<string, string> MergeSettings(Dictionary<string, string> settings1, Dictionary<string, string> settings2);
|
Dictionary<string, string> MergeSettings(Dictionary<string, string> baseSettings, Dictionary<string, string> overwriteSettings);
|
||||||
|
|
||||||
|
|
||||||
[Obsolete("GetSettingAsync(int settingId) is deprecated. Use GetSettingAsync(string entityName, int settingId) instead.", false)]
|
[Obsolete("GetSettingAsync(int settingId) is deprecated. Use GetSettingAsync(string entityName, int settingId) instead.", false)]
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Service to store and retrieve <see cref="TimeZone"/> entries
|
/// Service to retrieve <see cref="TimeZone"/> entries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ITimeZoneService
|
public interface ITimeZoneService
|
||||||
{
|
{
|
||||||
@ -13,6 +12,6 @@ namespace Oqtane.Services
|
|||||||
/// Get the list of time zones
|
/// Get the list of time zones
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<List<TimeZone>> GetTimeZonesAsync();
|
List<TimeZone> GetTimeZones();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,27 +266,25 @@ namespace Oqtane.Services
|
|||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, string> MergeSettings(Dictionary<string, string> settings1, Dictionary<string, string> settings2)
|
public Dictionary<string, string> MergeSettings(Dictionary<string, string> baseSettings, Dictionary<string, string> overwriteSettings)
|
||||||
{
|
{
|
||||||
if (settings1 == null)
|
var settings = baseSettings != null ? new Dictionary<string, string>(baseSettings) : new Dictionary<string, string>();
|
||||||
|
if (overwriteSettings != null)
|
||||||
{
|
{
|
||||||
settings1 = new Dictionary<string, string>();
|
foreach (var setting in overwriteSettings)
|
||||||
}
|
|
||||||
if (settings2 != null)
|
|
||||||
{
|
{
|
||||||
foreach (var setting in settings2)
|
if (settings.ContainsKey(setting.Key))
|
||||||
{
|
{
|
||||||
if (settings1.ContainsKey(setting.Key))
|
settings[setting.Key] = setting.Value;
|
||||||
{
|
|
||||||
settings1[setting.Key] = setting.Value;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
settings1.Add(setting.Key, setting.Value);
|
settings.Add(setting.Key, setting.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return settings1;
|
|
||||||
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("GetSettingAsync(int settingId) is deprecated. Use GetSettingAsync(string entityName, int settingId) instead.", false)]
|
[Obsolete("GetSettingAsync(int settingId) is deprecated. Use GetSettingAsync(string entityName, int settingId) instead.", false)]
|
||||||
|
@ -1,22 +1,58 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using Microsoft.Extensions.Localization;
|
||||||
|
using NodaTime.TimeZones;
|
||||||
|
using NodaTime;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
using Oqtane.Models;
|
using NodaTime.Extensions;
|
||||||
using Oqtane.Shared;
|
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
public class TimeZoneService : ServiceBase, ITimeZoneService
|
public class TimeZoneService : ITimeZoneService
|
||||||
{
|
{
|
||||||
public TimeZoneService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
private readonly IStringLocalizer<TimeZoneResources> _TimeZoneLocalizer;
|
||||||
|
|
||||||
private string Apiurl => CreateApiUrl("TimeZone");
|
public TimeZoneService(IStringLocalizer<TimeZoneResources> TimeZoneLocalizer)
|
||||||
|
|
||||||
public async Task<List<TimeZone>> GetTimeZonesAsync()
|
|
||||||
{
|
{
|
||||||
return await GetJsonAsync<List<TimeZone>>($"{Apiurl}");
|
_TimeZoneLocalizer = TimeZoneLocalizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Models.TimeZone> GetTimeZones()
|
||||||
|
{
|
||||||
|
var timezones = new List<Models.TimeZone>();
|
||||||
|
|
||||||
|
foreach (var tz in DateTimeZoneProviders.Tzdb.GetAllZones()
|
||||||
|
// only include timezones which have a country code defined or are US timezones
|
||||||
|
.Where(item => !string.IsNullOrEmpty(TzdbDateTimeZoneSource.Default.ZoneLocations.FirstOrDefault(l => l.ZoneId == item.Id)?.CountryCode) || item.Id.ToLower().Contains("us/"))
|
||||||
|
// order by UTC offset (ie. -11:00 to +14:00)
|
||||||
|
.OrderBy(item => item.GetUtcOffset(Instant.FromDateTimeUtc(DateTime.UtcNow)).Ticks))
|
||||||
|
{
|
||||||
|
// get localized display name
|
||||||
|
var displayname = _TimeZoneLocalizer[tz.Id].Value;
|
||||||
|
if (displayname == tz.Id)
|
||||||
|
{
|
||||||
|
// use default "friendly" display format
|
||||||
|
displayname = displayname.Replace("_", " ").Replace("/", " / ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// time zones can be excluded from the list by providing an empty translation in the localization file
|
||||||
|
if (!string.IsNullOrEmpty(displayname))
|
||||||
|
{
|
||||||
|
// include offset prefix
|
||||||
|
var offset = tz.GetUtcOffset(Instant.FromDateTimeUtc(DateTime.UtcNow)).Ticks;
|
||||||
|
displayname = "(UTC" + (offset >= 0 ? "+" : "-") + new DateTime(Math.Abs(offset)).ToString("HH:mm") + ") " + displayname;
|
||||||
|
|
||||||
|
timezones.Add(new Models.TimeZone()
|
||||||
|
{
|
||||||
|
Id = tz.Id,
|
||||||
|
DisplayName = displayname
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return timezones;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
public override List<Resource> Resources => new List<Resource>()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
// obtained from https://cdnjs.com/libraries
|
// obtained from https://cdnjs.com/libraries
|
||||||
new Stylesheet("https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css", "sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg==", "anonymous"),
|
new Stylesheet(Constants.BootstrapStylesheetUrl, Constants.BootstrapStylesheetIntegrity, "anonymous"),
|
||||||
new Stylesheet(ThemePath() + "Theme.css"),
|
new Stylesheet(ThemePath() + "Theme.css"),
|
||||||
new Script(Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous")
|
new Script(Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous")
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
|
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
|
||||||
|
// only include properties required by the ModuleActionsInteractive component
|
||||||
_pageState = new PageState
|
_pageState = new PageState
|
||||||
{
|
{
|
||||||
Alias = PageState.Alias,
|
Alias = PageState.Alias,
|
||||||
|
@ -91,6 +91,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
|
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
|
||||||
|
// only include properties required by the ControlPanelInteractive component
|
||||||
_pageState = new PageState
|
_pageState = new PageState
|
||||||
{
|
{
|
||||||
Alias = PageState.Alias,
|
Alias = PageState.Alias,
|
||||||
|
@ -353,7 +353,7 @@
|
|||||||
module.PageId = PageState.Page.PageId;
|
module.PageId = PageState.Page.PageId;
|
||||||
module.ModuleDefinitionName = _moduleDefinitionName;
|
module.ModuleDefinitionName = _moduleDefinitionName;
|
||||||
module.AllPages = false;
|
module.AllPages = false;
|
||||||
module.PermissionList = GenerateDefaultPermissions(module.SiteId);
|
module.PermissionList = GenerateDefaultPermissions(module.SiteId, module.ModuleDefinitionName);
|
||||||
|
|
||||||
module = await ModuleService.AddModuleAsync(module);
|
module = await ModuleService.AddModuleAsync(module);
|
||||||
newModuleId = module.ModuleId;
|
newModuleId = module.ModuleId;
|
||||||
@ -365,7 +365,7 @@
|
|||||||
module.SiteId = PageState.Page.SiteId;
|
module.SiteId = PageState.Page.SiteId;
|
||||||
module.PageId = PageState.Page.PageId;
|
module.PageId = PageState.Page.PageId;
|
||||||
module.AllPages = false;
|
module.AllPages = false;
|
||||||
module.PermissionList = GenerateDefaultPermissions(module.SiteId);
|
module.PermissionList = GenerateDefaultPermissions(module.SiteId, module.ModuleDefinitionName);
|
||||||
|
|
||||||
module = await ModuleService.AddModuleAsync(module);
|
module = await ModuleService.AddModuleAsync(module);
|
||||||
var moduleContent = await ModuleService.ExportModuleAsync(int.Parse(_moduleId), PageState.Page.PageId);
|
var moduleContent = await ModuleService.ExportModuleAsync(int.Parse(_moduleId), PageState.Page.PageId);
|
||||||
@ -430,9 +430,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Permission> GenerateDefaultPermissions(int siteId)
|
private List<Permission> GenerateDefaultPermissions(int siteId, string moduleDefinitionName)
|
||||||
{
|
{
|
||||||
var permissions = new List<Permission>();
|
var permissions = new List<Permission>();
|
||||||
|
|
||||||
|
// set module view permissions
|
||||||
if (_visibility == "view")
|
if (_visibility == "view")
|
||||||
{
|
{
|
||||||
// set module view permissions to page view permissions
|
// set module view permissions to page view permissions
|
||||||
@ -443,8 +445,22 @@
|
|||||||
// set module view permissions to page edit permissions
|
// set module view permissions to page edit permissions
|
||||||
permissions = SetPermissions(permissions, siteId, PermissionNames.View, PermissionNames.Edit);
|
permissions = SetPermissions(permissions, siteId, PermissionNames.View, PermissionNames.Edit);
|
||||||
}
|
}
|
||||||
// set module edit permissions to page edit permissions
|
|
||||||
permissions = SetPermissions(permissions, siteId, PermissionNames.Edit, PermissionNames.Edit);
|
// set remaining module permissions
|
||||||
|
var permissionNames = PermissionNames.Edit;
|
||||||
|
var moduleDefinition = _allModuleDefinitions.FirstOrDefault(item => item.ModuleDefinitionName == moduleDefinitionName);
|
||||||
|
if (moduleDefinition != null && !string.IsNullOrEmpty(moduleDefinition.PermissionNames))
|
||||||
|
{
|
||||||
|
permissionNames = moduleDefinition.PermissionNames; // custom module permissions
|
||||||
|
}
|
||||||
|
foreach (var permission in permissionNames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
if (permission != PermissionNames.View)
|
||||||
|
{
|
||||||
|
// set module permissions to page edit permissions
|
||||||
|
permissions = SetPermissions(permissions, siteId, permission, PermissionNames.Edit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return permissions;
|
return permissions;
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,9 @@
|
|||||||
{
|
{
|
||||||
var cookieConsentSetting = SettingService.GetSetting(PageState.Site.Settings, "CookieConsent", string.Empty);
|
var cookieConsentSetting = SettingService.GetSetting(PageState.Site.Settings, "CookieConsent", string.Empty);
|
||||||
_enabled = !string.IsNullOrEmpty(cookieConsentSetting);
|
_enabled = !string.IsNullOrEmpty(cookieConsentSetting);
|
||||||
|
|
||||||
|
if (!_enabled) return;
|
||||||
|
|
||||||
_optout = cookieConsentSetting == "optout";
|
_optout = cookieConsentSetting == "optout";
|
||||||
_actioned = await CookieConsentService.IsActionedAsync();
|
_actioned = await CookieConsentService.IsActionedAsync();
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ namespace Oqtane.Themes.OqtaneTheme
|
|||||||
ContainerSettingsType = "Oqtane.Themes.OqtaneTheme.ContainerSettings, Oqtane.Client",
|
ContainerSettingsType = "Oqtane.Themes.OqtaneTheme.ContainerSettings, Oqtane.Client",
|
||||||
Resources = new List<Resource>()
|
Resources = new List<Resource>()
|
||||||
{
|
{
|
||||||
// obtained from https://cdnjs.com/libraries
|
// obtained from https://cdnjs.com/libraries/bootswatch
|
||||||
new Stylesheet("https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/cyborg/bootstrap.min.css", "sha512-M+Wrv9LTvQe81gFD2ZE3xxPTN5V2n1iLCXsldIxXvfs6tP+6VihBCwCMBkkjkQUZVmEHBsowb9Vqsq1et1teEg==", "anonymous"),
|
new Stylesheet("https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.7/cyborg/bootstrap.min.css", "sha512-/LQFzDeXqysGQ/POl5YOEjgVZH1BmqDHvshhnFIChf50bMGQ470qhUrsecD9MRCUwzwqRoshwAbmA2oTW4I6Yg==", "anonymous"),
|
||||||
new Stylesheet("~/Theme.css"),
|
new Stylesheet("~/Theme.css"),
|
||||||
new Script(Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous")
|
new Script(Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous")
|
||||||
}
|
}
|
||||||
|
14
Oqtane.Client/TimeZoneResources.cs
Normal file
14
Oqtane.Client/TimeZoneResources.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace Oqtane
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Dummy class used to collect shared resource strings for this application
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This class is mostly used with IStringLocalizer and IHtmlLocalizer interfaces.
|
||||||
|
/// The class must reside at the project root.
|
||||||
|
/// </remarks>
|
||||||
|
public class TimeZoneResources
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@
|
|||||||
@if (ComponentType != null && _visible)
|
@if (ComponentType != null && _visible)
|
||||||
{
|
{
|
||||||
<a id="@ModuleState.PageModuleId.ToString()"></a>
|
<a id="@ModuleState.PageModuleId.ToString()"></a>
|
||||||
<CascadingValue Value="@ModuleState">
|
<CascadingValue Value="@ModuleState" IsFixed="true">
|
||||||
@if (_useadminborder)
|
@if (_useadminborder)
|
||||||
{
|
{
|
||||||
<div class="app-pane-admin-border">
|
<div class="app-pane-admin-border">
|
||||||
@ -31,6 +31,9 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public Module ModuleState { get; set; }
|
public Module ModuleState { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string ContainerType { get; set; }
|
||||||
|
|
||||||
protected override bool ShouldRender()
|
protected override bool ShouldRender()
|
||||||
{
|
{
|
||||||
return PageState?.RenderId == ModuleState?.RenderId;
|
return PageState?.RenderId == ModuleState?.RenderId;
|
||||||
@ -44,6 +47,10 @@
|
|||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
string container = ModuleState.ContainerType;
|
string container = ModuleState.ContainerType;
|
||||||
|
if (!string.IsNullOrEmpty(ContainerType))
|
||||||
|
{
|
||||||
|
container = ContainerType;
|
||||||
|
}
|
||||||
if (PageState.ModuleId != -1 && PageState.Route.Action != "" && ModuleState.UseAdminContainer)
|
if (PageState.ModuleId != -1 && PageState.Route.Action != "" && ModuleState.UseAdminContainer)
|
||||||
{
|
{
|
||||||
container = (!string.IsNullOrEmpty(PageState.Site.AdminContainerType)) ? PageState.Site.AdminContainerType : Constants.DefaultAdminContainer;
|
container = (!string.IsNullOrEmpty(PageState.Site.AdminContainerType)) ? PageState.Site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||||
|
@ -224,17 +224,17 @@ namespace Oqtane.UI
|
|||||||
|
|
||||||
public Task UploadFiles(string posturl, string folder, string id, string antiforgerytoken, string jwt)
|
public Task UploadFiles(string posturl, string folder, string id, string antiforgerytoken, string jwt)
|
||||||
{
|
{
|
||||||
UploadFiles(posturl, folder, id, antiforgerytoken, jwt, 1);
|
UploadFiles(posturl, folder, id, antiforgerytoken, jwt, 1, false);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask<bool> UploadFiles(string posturl, string folder, string id, string antiforgerytoken, string jwt, int chunksize, CancellationToken cancellationToken = default)
|
public ValueTask<bool> UploadFiles(string posturl, string folder, string id, string antiforgerytoken, string jwt, int chunksize, bool anonymizeuploadfilenames, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return _jsRuntime.InvokeAsync<bool>(
|
return _jsRuntime.InvokeAsync<bool>(
|
||||||
"Oqtane.Interop.uploadFiles", cancellationToken,
|
"Oqtane.Interop.uploadFiles", cancellationToken,
|
||||||
posturl, folder, id, antiforgerytoken, jwt, chunksize);
|
posturl, folder, id, antiforgerytoken, jwt, chunksize, anonymizeuploadfilenames);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
@((MarkupString)_comment)
|
@((MarkupString)_comment)
|
||||||
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static)
|
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static)
|
||||||
{
|
{
|
||||||
<RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" />
|
<RenderModeBoundary ModuleState="@ModuleState" PageState="@_pageState" SiteState="@SiteState" />
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" @rendermode="InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, _prerender)" />
|
<RenderModeBoundary ModuleState="@ModuleState" PageState="@_pageState" SiteState="@SiteState" @rendermode="InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, _prerender)" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@if (PageState.ModuleId == -1)
|
@if (PageState.ModuleId == -1)
|
||||||
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
private bool _prerender;
|
private bool _prerender;
|
||||||
private string _comment;
|
private string _comment;
|
||||||
|
private PageState _pageState;
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
@ -48,11 +49,12 @@
|
|||||||
}
|
}
|
||||||
_comment += " -->";
|
_comment += " -->";
|
||||||
|
|
||||||
|
_pageState = PageState.Clone();
|
||||||
if (PageState.RenderMode == RenderModes.Static && ModuleState.RenderMode == RenderModes.Interactive)
|
if (PageState.RenderMode == RenderModes.Static && ModuleState.RenderMode == RenderModes.Interactive)
|
||||||
{
|
{
|
||||||
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
|
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
|
||||||
// please note that this performance optimization results in the PageState.Pages property not being available for use in Interactive components
|
// please note that this performance optimization results in the PageState.Pages property not being available for use in downstream Interactive components
|
||||||
PageState.Site.Pages = new List<Page>();
|
_pageState.Site.Pages = new List<Page>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,5 +37,34 @@ namespace Oqtane.UI
|
|||||||
{
|
{
|
||||||
get { return Site?.Languages; }
|
get { return Site?.Languages; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PageState Clone()
|
||||||
|
{
|
||||||
|
return new PageState
|
||||||
|
{
|
||||||
|
Alias = Alias,
|
||||||
|
Site = Site,
|
||||||
|
Page = Page,
|
||||||
|
Modules = Modules,
|
||||||
|
User = User,
|
||||||
|
Uri = Uri,
|
||||||
|
Route = Route,
|
||||||
|
QueryString = QueryString,
|
||||||
|
UrlParameters = UrlParameters,
|
||||||
|
ModuleId = ModuleId,
|
||||||
|
Action = Action,
|
||||||
|
EditMode = EditMode,
|
||||||
|
LastSyncDate = LastSyncDate,
|
||||||
|
RenderMode = RenderMode,
|
||||||
|
Runtime = Runtime,
|
||||||
|
VisitorId = VisitorId,
|
||||||
|
RemoteIPAddress = RemoteIPAddress,
|
||||||
|
ReturnUrl = ReturnUrl,
|
||||||
|
IsInternalNavigation = IsInternalNavigation,
|
||||||
|
RenderId = RenderId,
|
||||||
|
Refresh = Refresh,
|
||||||
|
AllowCookies = AllowCookies
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,9 @@ else
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string ContainerType { get; set; }
|
||||||
|
|
||||||
RenderFragment DynamicComponent { get; set; }
|
RenderFragment DynamicComponent { get; set; }
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
@ -45,12 +48,6 @@ else
|
|||||||
{
|
{
|
||||||
foreach (Module module in PageState.Modules)
|
foreach (Module module in PageState.Modules)
|
||||||
{
|
{
|
||||||
// set renderid - this allows the framework to determine which components should be rendered when PageState changes
|
|
||||||
if (module.RenderId != PageState.RenderId)
|
|
||||||
{
|
|
||||||
module.RenderId = PageState.RenderId;
|
|
||||||
}
|
|
||||||
|
|
||||||
var pane = module.Pane;
|
var pane = module.Pane;
|
||||||
if (module.ModuleId == PageState.ModuleId && PageState.Action != Constants.DefaultAction)
|
if (module.ModuleId == PageState.ModuleId && PageState.Action != Constants.DefaultAction)
|
||||||
{
|
{
|
||||||
@ -101,7 +98,7 @@ else
|
|||||||
|
|
||||||
if (authorized)
|
if (authorized)
|
||||||
{
|
{
|
||||||
CreateComponent(builder, module, module.PageModuleId);
|
CreateComponent(builder, module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +109,7 @@ else
|
|||||||
// check if user is authorized to view module
|
// check if user is authorized to view module
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
||||||
{
|
{
|
||||||
CreateComponent(builder, module, -1);
|
CreateComponent(builder, module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,14 +118,12 @@ else
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateComponent(RenderTreeBuilder builder, Module module, int key)
|
private void CreateComponent(RenderTreeBuilder builder, Module module)
|
||||||
{
|
{
|
||||||
builder.OpenComponent(0, typeof(ContainerBuilder));
|
builder.OpenComponent(0, typeof(ContainerBuilder));
|
||||||
builder.AddAttribute(1, "ModuleState", module);
|
builder.AddAttribute(1, "ModuleState", module);
|
||||||
if (key != -1)
|
builder.AddAttribute(2, "ContainerType", ContainerType);
|
||||||
{
|
|
||||||
builder.SetKey(module.PageModuleId);
|
builder.SetKey(module.PageModuleId);
|
||||||
}
|
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
@inject ILogService LoggingService
|
@inject ILogService LoggingService
|
||||||
@inherits ErrorBoundary
|
@inherits ErrorBoundary
|
||||||
|
|
||||||
<CascadingValue Value="@PageState">
|
<CascadingValue Value="@PageState" IsFixed="true">
|
||||||
<CascadingValue Value="@ModuleState">
|
<CascadingValue Value="@ModuleState" IsFixed="true">
|
||||||
@if (CurrentException is null)
|
@if (CurrentException is null)
|
||||||
{
|
{
|
||||||
@if (ModuleType != null)
|
@if (ModuleType != null)
|
||||||
|
@ -48,12 +48,18 @@
|
|||||||
|
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private bool _installed = false;
|
private bool _installed = false;
|
||||||
private string _display = "display: none;";
|
private string _display = "";
|
||||||
|
|
||||||
private PageState _pageState { get; set; }
|
private PageState _pageState { get; set; }
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
|
if (PageState != null && PageState.RenderMode == RenderModes.Interactive && PageState.Site.Prerender)
|
||||||
|
{
|
||||||
|
// prevents flash on initial interactive page load when using prerendering
|
||||||
|
_display = "display: none;";
|
||||||
|
}
|
||||||
|
|
||||||
SiteState.AntiForgeryToken = AntiForgeryToken;
|
SiteState.AntiForgeryToken = AntiForgeryToken;
|
||||||
SiteState.AuthorizationToken = AuthorizationToken;
|
SiteState.AuthorizationToken = AuthorizationToken;
|
||||||
SiteState.Platform = Platform;
|
SiteState.Platform = Platform;
|
||||||
@ -73,8 +79,8 @@
|
|||||||
if (PageState != null)
|
if (PageState != null)
|
||||||
{
|
{
|
||||||
_pageState = PageState;
|
_pageState = PageState;
|
||||||
SiteState.Alias = PageState.Alias;
|
SiteState.Alias = _pageState.Alias;
|
||||||
SiteState.RemoteIPAddress = (PageState != null) ? PageState.RemoteIPAddress : "";
|
SiteState.RemoteIPAddress = _pageState.RemoteIPAddress;
|
||||||
_installed = true;
|
_installed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,9 +91,7 @@
|
|||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
// prevents flash on initial interactive page load
|
|
||||||
_display = "";
|
_display = "";
|
||||||
StateHasChanged();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
{
|
{
|
||||||
if (PageState == null || PageState.Refresh)
|
if (PageState == null || PageState.Refresh)
|
||||||
{
|
{
|
||||||
await Refresh();
|
await Refresh(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +79,7 @@
|
|||||||
{
|
{
|
||||||
_absoluteUri = args.Location;
|
_absoluteUri = args.Location;
|
||||||
_isInternalNavigation = true;
|
_isInternalNavigation = true;
|
||||||
await Refresh();
|
await Refresh(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Task IHandleAfterRender.OnAfterRenderAsync()
|
Task IHandleAfterRender.OnAfterRenderAsync()
|
||||||
@ -93,7 +93,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
|
[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
|
||||||
private async Task Refresh()
|
private async Task Refresh(bool locationChanged)
|
||||||
{
|
{
|
||||||
Site site = null;
|
Site site = null;
|
||||||
Page page = null;
|
Page page = null;
|
||||||
@ -103,6 +103,7 @@
|
|||||||
var refresh = false;
|
var refresh = false;
|
||||||
var lastsyncdate = DateTime.MinValue;
|
var lastsyncdate = DateTime.MinValue;
|
||||||
var visitorId = -1;
|
var visitorId = -1;
|
||||||
|
var renderid = Guid.Empty;
|
||||||
_error = "";
|
_error = "";
|
||||||
|
|
||||||
Route route = new Route(_absoluteUri, SiteState.Alias.Path);
|
Route route = new Route(_absoluteUri, SiteState.Alias.Path);
|
||||||
@ -288,11 +289,21 @@
|
|||||||
modules = PageState.Modules;
|
modules = PageState.Modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// renderid allows the framework to determine which module components should be rendered on a page
|
||||||
|
if (PageState == null || locationChanged)
|
||||||
|
{
|
||||||
|
renderid = Guid.NewGuid();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
renderid = PageState.RenderId;
|
||||||
|
}
|
||||||
|
|
||||||
// load additional metadata for current page
|
// load additional metadata for current page
|
||||||
page = ProcessPage(page, site, user, SiteState.Alias, action);
|
page = ProcessPage(page, site, user, SiteState.Alias, action);
|
||||||
|
|
||||||
// load additional metadata for modules
|
// load additional metadata for modules
|
||||||
(page, modules) = ProcessModules(site, page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias);
|
(page, modules) = ProcessModules(site, page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias, renderid);
|
||||||
|
|
||||||
//cookie consent
|
//cookie consent
|
||||||
var _allowCookies = PageState?.AllowCookies;
|
var _allowCookies = PageState?.AllowCookies;
|
||||||
@ -324,7 +335,7 @@
|
|||||||
RemoteIPAddress = SiteState.RemoteIPAddress,
|
RemoteIPAddress = SiteState.RemoteIPAddress,
|
||||||
ReturnUrl = returnurl,
|
ReturnUrl = returnurl,
|
||||||
IsInternalNavigation = _isInternalNavigation,
|
IsInternalNavigation = _isInternalNavigation,
|
||||||
RenderId = Guid.NewGuid(),
|
RenderId = renderid,
|
||||||
Refresh = false,
|
Refresh = false,
|
||||||
AllowCookies = _allowCookies.GetValueOrDefault(true)
|
AllowCookies = _allowCookies.GetValueOrDefault(true)
|
||||||
};
|
};
|
||||||
@ -447,7 +458,7 @@
|
|||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Page Page, List<Module> Modules) ProcessModules(Site site, Page page, List<Module> modules, int moduleid, string action, string defaultcontainertype, Alias alias)
|
private (Page Page, List<Module> Modules) ProcessModules(Site site, Page page, List<Module> modules, int moduleid, string action, string defaultcontainertype, Alias alias, Guid renderid)
|
||||||
{
|
{
|
||||||
var paneindex = new Dictionary<string, int>();
|
var paneindex = new Dictionary<string, int>();
|
||||||
|
|
||||||
@ -592,6 +603,8 @@
|
|||||||
{
|
{
|
||||||
module.ContainerType = defaultcontainertype;
|
module.ContainerType = defaultcontainertype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.RenderId = renderid;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Module module in modules.Where(item => item.PageId == page.PageId))
|
foreach (Module module in modules.Where(item => item.PageId == page.PageId))
|
||||||
|
@ -20,13 +20,6 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// force authenticated user to provide email address (email may be missing if using external login)
|
|
||||||
if (PageState.User != null && PageState.User.IsAuthenticated && string.IsNullOrEmpty(PageState.User.Email) && PageState.Route.PagePath != "profile")
|
|
||||||
{
|
|
||||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, "profile", "returnurl=" + WebUtility.UrlEncode(PageState.Route.PathAndQuery)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set page title
|
// set page title
|
||||||
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
if (!string.IsNullOrEmpty(PageState.Page.Title))
|
||||||
{
|
{
|
||||||
|
@ -75,13 +75,9 @@ namespace Oqtane.Database.MySQL
|
|||||||
return dr;
|
return dr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string RewriteName(string name, bool isQuery)
|
public override string DelimitName(string name)
|
||||||
{
|
{
|
||||||
if (name.ToLower() == "rows" && isQuery)
|
return $"`{name}`";
|
||||||
{
|
|
||||||
name = $"`{name}`"; // escape reserved word in SQL query
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Version>6.1.3</Version>
|
<Version>6.1.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/v6.1.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MySql.Data" Version="9.3.0" />
|
<PackageReference Include="MySql.Data" Version="9.4.0" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0-preview.3.efcore.9.0.0" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0-preview.3.efcore.9.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Version>6.1.3</Version>
|
<Version>6.1.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/v6.1.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="EFCore.NamingConventions" Version="9.0.0" />
|
<PackageReference Include="EFCore.NamingConventions" Version="9.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.7" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -87,9 +87,9 @@ namespace Oqtane.Database.PostgreSQL
|
|||||||
return _rewriter.RewriteName(name);
|
return _rewriter.RewriteName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string RewriteName(string name, bool isQuery)
|
public override string DelimitName(string name)
|
||||||
{
|
{
|
||||||
return _rewriter.RewriteName(name);
|
return $"\"{name}\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string RewriteValue(string value, string type)
|
public override string RewriteValue(string value, string type)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Version>6.1.3</Version>
|
<Version>6.1.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/v6.1.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -46,6 +46,11 @@ namespace Oqtane.Database.SqlServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string DelimitName(string name)
|
||||||
|
{
|
||||||
|
return $"[{name}]";
|
||||||
|
}
|
||||||
|
|
||||||
public override int ExecuteNonQuery(string connectionString, string query)
|
public override int ExecuteNonQuery(string connectionString, string query)
|
||||||
{
|
{
|
||||||
var conn = new SqlConnection(FormatConnectionString(connectionString));
|
var conn = new SqlConnection(FormatConnectionString(connectionString));
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Version>6.1.3</Version>
|
<Version>6.1.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/v6.1.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -84,6 +84,11 @@ namespace Oqtane.Database.Sqlite
|
|||||||
return dr;
|
return dr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string DelimitName(string name)
|
||||||
|
{
|
||||||
|
return $"\"{name}\"";
|
||||||
|
}
|
||||||
|
|
||||||
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
||||||
{
|
{
|
||||||
return optionsBuilder.UseSqlite(connectionString)
|
return optionsBuilder.UseSqlite(connectionString)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<!-- <TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks> -->
|
<!-- <TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks> -->
|
||||||
<!-- <TargetFrameworks>$(TargetFrameworks);net9.0-tizen</TargetFrameworks> -->
|
<!-- <TargetFrameworks>$(TargetFrameworks);net9.0-tizen</TargetFrameworks> -->
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<Version>6.1.3</Version>
|
<Version>6.1.4</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -14,7 +14,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/v6.1.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane.Maui</RootNamespace>
|
<RootNamespace>Oqtane.Maui</RootNamespace>
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<ApplicationId>com.oqtane.maui</ApplicationId>
|
<ApplicationId>com.oqtane.maui</ApplicationId>
|
||||||
|
|
||||||
<!-- Versions -->
|
<!-- Versions -->
|
||||||
<ApplicationDisplayVersion>6.1.3</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>6.1.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 -->
|
||||||
@ -67,14 +67,14 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.7" />
|
||||||
<PackageReference Include="System.Net.Http.Json" Version="9.0.5" />
|
<PackageReference Include="System.Net.Http.Json" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls" Version="9.0.61" />
|
<PackageReference Include="Microsoft.Maui.Controls" Version="9.0.90" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="9.0.61" />
|
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="9.0.90" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="9.0.61" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="9.0.90" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -75,6 +75,10 @@ app {
|
|||||||
color: gray;
|
color: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-moduleactions .dropdown-menu {
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
.app-moduleactions .dropdown-submenu {
|
.app-moduleactions .dropdown-submenu {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@ -235,18 +239,19 @@ app {
|
|||||||
.app-form-inline {
|
.app-form-inline {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
.app-search{
|
|
||||||
|
.app-search {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.app-search input + button{
|
.app-search input + button {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
.app-search input + button .oi{
|
.app-search input + button .oi {
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
.app-search-noinput {
|
.app-search-noinput {
|
||||||
@ -271,3 +276,13 @@ app {
|
|||||||
.app-logo .navbar-brand {
|
.app-logo .navbar-brand {
|
||||||
padding: 5px 20px 5px 20px;
|
padding: 5px 20px 5px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* cookie consent */
|
||||||
|
.gdpr-consent-bar .btn-show {
|
||||||
|
bottom: -3px;
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
.gdpr-consent-bar .btn-hide {
|
||||||
|
top: 0;
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
@ -311,7 +311,7 @@ Oqtane.Interop = {
|
|||||||
}
|
}
|
||||||
return files;
|
return files;
|
||||||
},
|
},
|
||||||
uploadFiles: async function (posturl, folder, id, antiforgerytoken, jwt, chunksize) {
|
uploadFiles: async function (posturl, folder, id, antiforgerytoken, jwt, chunksize, anonymizeuploadfilenames) {
|
||||||
var success = true;
|
var success = true;
|
||||||
var fileinput = document.getElementById('FileInput_' + id);
|
var fileinput = document.getElementById('FileInput_' + id);
|
||||||
var progressinfo = document.getElementById('ProgressInfo_' + id);
|
var progressinfo = document.getElementById('ProgressInfo_' + id);
|
||||||
@ -344,16 +344,22 @@ Oqtane.Interop = {
|
|||||||
const totalParts = Math.ceil(file.size / chunkSize);
|
const totalParts = Math.ceil(file.size / chunkSize);
|
||||||
let partCount = 0;
|
let partCount = 0;
|
||||||
|
|
||||||
|
let filename = file.name;
|
||||||
|
if (anonymizeuploadfilenames) {
|
||||||
|
filename = crypto.randomUUID() + '.' + filename.split('.').pop();
|
||||||
|
}
|
||||||
|
|
||||||
const uploadPart = () => {
|
const uploadPart = () => {
|
||||||
const start = partCount * chunkSize;
|
const start = partCount * chunkSize;
|
||||||
const end = Math.min(start + chunkSize, file.size);
|
const end = Math.min(start + chunkSize, file.size);
|
||||||
const chunk = file.slice(start, end);
|
const chunk = file.slice(start, end);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
let formdata = new FormData();
|
let formdata = new FormData();
|
||||||
formdata.append('__RequestVerificationToken', antiforgerytoken);
|
formdata.append('__RequestVerificationToken', antiforgerytoken);
|
||||||
formdata.append('folder', folder);
|
formdata.append('folder', folder);
|
||||||
formdata.append('formfile', chunk, file.name);
|
formdata.append('formfile', chunk, filename);
|
||||||
|
|
||||||
var credentials = 'same-origin';
|
var credentials = 'same-origin';
|
||||||
var headers = new Headers();
|
var headers = new Headers();
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Client</id>
|
<id>Oqtane.Client</id>
|
||||||
<version>6.1.3</version>
|
<version>6.1.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/v6.1.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Framework</id>
|
<id>Oqtane.Framework</id>
|
||||||
<version>6.1.3</version>
|
<version>6.1.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/v6.1.3/Oqtane.Framework.6.1.3.Upgrade.zip</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v6.1.4/Oqtane.Framework.6.1.4.Upgrade.zip</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.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>6.1.3</version>
|
<version>6.1.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/v6.1.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Shared</id>
|
<id>Oqtane.Shared</id>
|
||||||
<version>6.1.3</version>
|
<version>6.1.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/v6.1.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Updater</id>
|
<id>Oqtane.Updater</id>
|
||||||
<version>6.1.3</version>
|
<version>6.1.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/v6.1.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.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\net9.0\publish\*" -DestinationPath "Oqtane.Framework.6.1.3.Install.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net9.0\publish\*" -DestinationPath "Oqtane.Framework.6.1.4.Install.zip" -Force
|
||||||
|
@ -1 +1 @@
|
|||||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net9.0\publish\*" -DestinationPath "Oqtane.Framework.6.1.3.Upgrade.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net9.0\publish\*" -DestinationPath "Oqtane.Framework.6.1.4.Upgrade.zip" -Force
|
||||||
|
@ -345,6 +345,7 @@
|
|||||||
DateTime expiry = DateTime.MinValue;
|
DateTime expiry = DateTime.MinValue;
|
||||||
if (visitorCookieValue != null && visitorCookieValue.Contains("|"))
|
if (visitorCookieValue != null && visitorCookieValue.Contains("|"))
|
||||||
{
|
{
|
||||||
|
// visitor cookies contain the visitor id and an expiry date separated by a pipe symbol
|
||||||
var values = visitorCookieValue.Split('|');
|
var values = visitorCookieValue.Split('|');
|
||||||
int.TryParse(values[0], out _visitorId);
|
int.TryParse(values[0], out _visitorId);
|
||||||
DateTime.TryParseExact(values[1], "M/d/yyyy hh:mm:ss tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out expiry);
|
DateTime.TryParseExact(values[1], "M/d/yyyy hh:mm:ss tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out expiry);
|
||||||
|
@ -444,9 +444,14 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ensure filename is valid
|
// ensure filename is valid
|
||||||
if (!formfile.FileName.IsPathOrFileValid() || !HasValidFileExtension(formfile.FileName))
|
string fileName = formfile.FileName;
|
||||||
|
if (Path.GetExtension(fileName).Contains(':'))
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "File Upload File Name Is Invalid Or Contains Invalid Extension {File}", formfile.FileName);
|
fileName = fileName.Substring(0, fileName.LastIndexOf(':')); // remove invalid suffix from extension
|
||||||
|
}
|
||||||
|
if (!fileName.IsPathOrFileValid() || !HasValidFileExtension(fileName))
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "File Upload File Name Is Invalid Or Contains Invalid Extension {File}", fileName);
|
||||||
return StatusCode((int)HttpStatusCode.Forbidden);
|
return StatusCode((int)HttpStatusCode.Forbidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,8 +463,8 @@ namespace Oqtane.Controllers
|
|||||||
return StatusCode((int)HttpStatusCode.Forbidden);
|
return StatusCode((int)HttpStatusCode.Forbidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create file name using header values
|
// create file name using header part values
|
||||||
string fileName = formfile.FileName + ".part_" + partCount.ToString("000") + "_" + totalParts.ToString("000");
|
fileName += ".part_" + partCount.ToString("000") + "_" + totalParts.ToString("000");
|
||||||
string folderPath = "";
|
string folderPath = "";
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -532,13 +537,13 @@ namespace Oqtane.Controllers
|
|||||||
string parts = Path.GetExtension(filename)?.Replace(token, ""); // returns "001_999"
|
string parts = Path.GetExtension(filename)?.Replace(token, ""); // returns "001_999"
|
||||||
int totalparts = int.Parse(parts?.Substring(parts.IndexOf("_") + 1));
|
int totalparts = int.Parse(parts?.Substring(parts.IndexOf("_") + 1));
|
||||||
|
|
||||||
filename = Path.GetFileNameWithoutExtension(filename); // base filename
|
filename = Path.GetFileNameWithoutExtension(filename); // base filename including original file extension
|
||||||
string[] fileparts = Directory.GetFiles(folder, filename + token + "*"); // list of all file parts
|
string[] fileparts = Directory.GetFiles(folder, filename + token + "*"); // list of all file parts
|
||||||
|
|
||||||
// if all of the file parts exist (note that file parts can arrive out of order)
|
// if all of the file parts exist (note that file parts can arrive out of order)
|
||||||
if (fileparts.Length == totalparts && CanAccessFiles(fileparts))
|
if (fileparts.Length == totalparts && CanAccessFiles(fileparts))
|
||||||
{
|
{
|
||||||
// merge file parts into temp file (in case another user is trying to get the file)
|
// merge file parts into temp file (in case another user is trying to read the file)
|
||||||
bool success = true;
|
bool success = true;
|
||||||
using (var stream = new FileStream(Path.Combine(folder, filename + ".tmp"), FileMode.Create))
|
using (var stream = new FileStream(Path.Combine(folder, filename + ".tmp"), FileMode.Create))
|
||||||
{
|
{
|
||||||
@ -559,9 +564,7 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// clean up file parts
|
// clean up file parts
|
||||||
foreach (var file in Directory.GetFiles(folder, "*" + token + "*"))
|
foreach (var file in fileparts)
|
||||||
{
|
|
||||||
if (fileparts.Contains(file))
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -572,12 +575,11 @@ namespace Oqtane.Controllers
|
|||||||
// unable to delete part - ignore
|
// unable to delete part - ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// rename temp file
|
// rename temp file
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
// remove file if it already exists (as well as any thumbnails which may exist)
|
// remove existing file (as well as any thumbnails)
|
||||||
foreach (var file in Directory.GetFiles(folder, Path.GetFileNameWithoutExtension(filename) + ".*"))
|
foreach (var file in Directory.GetFiles(folder, Path.GetFileNameWithoutExtension(filename) + ".*"))
|
||||||
{
|
{
|
||||||
if (Path.GetExtension(file) != ".tmp")
|
if (Path.GetExtension(file) != ".tmp")
|
||||||
|
@ -43,7 +43,6 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
private readonly Alias _alias;
|
private readonly Alias _alias;
|
||||||
private readonly string _visitorCookie;
|
|
||||||
|
|
||||||
public SettingController(ISettingRepository settings, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager,
|
public SettingController(ISettingRepository settings, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager,
|
||||||
IOptions<CookieAuthenticationOptions> cookieOptions, IOptionsSnapshot<CookieAuthenticationOptions> cookieOptionsSnapshot, IOptionsMonitorCache<CookieAuthenticationOptions> cookieOptionsMonitorCache,
|
IOptions<CookieAuthenticationOptions> cookieOptions, IOptionsSnapshot<CookieAuthenticationOptions> cookieOptionsSnapshot, IOptionsMonitorCache<CookieAuthenticationOptions> cookieOptionsMonitorCache,
|
||||||
@ -70,7 +69,6 @@ namespace Oqtane.Controllers
|
|||||||
_identityOptionsMonitorCache = identityOptionsMonitorCache;
|
_identityOptionsMonitorCache = identityOptionsMonitorCache;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_alias = tenantManager.GetAlias();
|
_alias = tenantManager.GetAlias();
|
||||||
_visitorCookie = Constants.VisitorCookiePrefix + _alias.SiteId.ToString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: api/<controller>
|
// GET: api/<controller>
|
||||||
@ -299,11 +297,8 @@ namespace Oqtane.Controllers
|
|||||||
authorized = User.IsInRole(RoleNames.Admin);
|
authorized = User.IsInRole(RoleNames.Admin);
|
||||||
if (!authorized)
|
if (!authorized)
|
||||||
{
|
{
|
||||||
// a visitor may have cookies disabled
|
var visitorCookieName = Constants.VisitorCookiePrefix + _alias.SiteId.ToString();
|
||||||
if (int.TryParse(Request.Cookies[_visitorCookie], out int visitorId))
|
authorized = (entityId == GetVisitorCookieId(Request.Cookies[visitorCookieName]));
|
||||||
{
|
|
||||||
authorized = (visitorId == entityId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: // custom entity
|
default: // custom entity
|
||||||
@ -344,11 +339,8 @@ namespace Oqtane.Controllers
|
|||||||
case EntityNames.Visitor:
|
case EntityNames.Visitor:
|
||||||
if (!User.IsInRole(RoleNames.Admin))
|
if (!User.IsInRole(RoleNames.Admin))
|
||||||
{
|
{
|
||||||
filter = true;
|
var visitorCookieName = Constants.VisitorCookiePrefix + _alias.SiteId.ToString();
|
||||||
if (int.TryParse(Request.Cookies[_visitorCookie], out int visitorId))
|
filter = (entityId != GetVisitorCookieId(Request.Cookies[visitorCookieName]));
|
||||||
{
|
|
||||||
filter = (visitorId != entityId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: // custom entity
|
default: // custom entity
|
||||||
@ -358,6 +350,13 @@ namespace Oqtane.Controllers
|
|||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int GetVisitorCookieId(string visitorCookie)
|
||||||
|
{
|
||||||
|
// visitor cookies contain the visitor id and an expiry date separated by a pipe symbol
|
||||||
|
visitorCookie = (visitorCookie.Contains("|")) ? visitorCookie.Split('|')[0] : visitorCookie;
|
||||||
|
return (int.TryParse(visitorCookie, out int visitorId)) ? visitorId : -1;
|
||||||
|
}
|
||||||
|
|
||||||
private void AddSyncEvent(string EntityName, int EntityId, int SettingId, string Action)
|
private void AddSyncEvent(string EntityName, int EntityId, int SettingId, string Action)
|
||||||
{
|
{
|
||||||
_syncManager.AddSyncEvent(_alias, EntityName + "Setting", SettingId, Action);
|
_syncManager.AddSyncEvent(_alias, EntityName + "Setting", SettingId, Action);
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Oqtane.Models;
|
|
||||||
using Oqtane.Shared;
|
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
|
||||||
{
|
|
||||||
[Route(ControllerRoutes.ApiRoute)]
|
|
||||||
public class TimeZoneController : Controller
|
|
||||||
{
|
|
||||||
public TimeZoneController() {}
|
|
||||||
|
|
||||||
// GET: api/<controller>
|
|
||||||
[HttpGet]
|
|
||||||
public IEnumerable<Models.TimeZone> Get()
|
|
||||||
{
|
|
||||||
return TimeZoneInfo.GetSystemTimeZones()
|
|
||||||
.Select(item => new Models.TimeZone
|
|
||||||
{
|
|
||||||
Id = item.Id,
|
|
||||||
DisplayName = item.DisplayName
|
|
||||||
})
|
|
||||||
.OrderBy(item => item.DisplayName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -165,14 +165,13 @@ namespace Oqtane.Controllers
|
|||||||
bool allowregistration;
|
bool allowregistration;
|
||||||
if (_userPermissions.IsAuthorized(User, user.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin))
|
if (_userPermissions.IsAuthorized(User, user.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin))
|
||||||
{
|
{
|
||||||
user.EmailConfirmed = true;
|
user.IsAuthenticated = true; // admins can add any existing user to a site
|
||||||
user.IsAuthenticated = true;
|
|
||||||
allowregistration = true;
|
allowregistration = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
user.EmailConfirmed = false;
|
user.EmailConfirmed = false; // standard users cannot specify that their email is verified
|
||||||
user.IsAuthenticated = false;
|
user.IsAuthenticated = false; // existing users can only be added to a site if they provide a valid username and password
|
||||||
allowregistration = _sites.GetSite(user.SiteId).AllowRegistration;
|
allowregistration = _sites.GetSite(user.SiteId).AllowRegistration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,11 +51,8 @@ namespace Oqtane.Controllers
|
|||||||
bool authorized = User.IsInRole(RoleNames.Admin);
|
bool authorized = User.IsInRole(RoleNames.Admin);
|
||||||
if (!authorized)
|
if (!authorized)
|
||||||
{
|
{
|
||||||
var visitorCookie = Constants.VisitorCookiePrefix + _alias.SiteId.ToString();
|
var visitorCookieName = Constants.VisitorCookiePrefix + _alias.SiteId.ToString();
|
||||||
if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId))
|
authorized = (id == GetVisitorCookieId(Request.Cookies[visitorCookieName]));
|
||||||
{
|
|
||||||
authorized = (visitorId == id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var visitor = _visitors.GetVisitor(id);
|
var visitor = _visitors.GetVisitor(id);
|
||||||
@ -77,5 +74,12 @@ namespace Oqtane.Controllers
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int GetVisitorCookieId(string visitorCookie)
|
||||||
|
{
|
||||||
|
// visitor cookies contain the visitor id and an expiry date separated by a pipe symbol
|
||||||
|
visitorCookie = (visitorCookie.Contains("|")) ? visitorCookie.Split('|')[0] : visitorCookie;
|
||||||
|
return (int.TryParse(visitorCookie, out int visitorId)) ? visitorId : -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,12 +61,12 @@ namespace Oqtane.Databases
|
|||||||
|
|
||||||
public abstract IDataReader ExecuteReader(string connectionString, string query);
|
public abstract IDataReader ExecuteReader(string connectionString, string query);
|
||||||
|
|
||||||
public virtual string RewriteName(string name)
|
public virtual string DelimitName(string name)
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual string RewriteName(string name, bool isQuery)
|
public virtual string RewriteName(string name)
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,9 @@ namespace Oqtane.Databases.Interfaces
|
|||||||
|
|
||||||
public IDataReader ExecuteReader(string connectionString, string query);
|
public IDataReader ExecuteReader(string connectionString, string query);
|
||||||
|
|
||||||
public string RewriteName(string name);
|
public string DelimitName(string name); // only used in conjunction with method using MigrationBuilder.Sql()
|
||||||
|
|
||||||
public string RewriteName(string name, bool isQuery);
|
public string RewriteName(string name);
|
||||||
|
|
||||||
public string RewriteValue(string value, string type);
|
public string RewriteValue(string value, string type);
|
||||||
|
|
||||||
|
@ -228,11 +228,12 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
options.Lockout.AllowedForNewUsers = false;
|
options.Lockout.AllowedForNewUsers = false;
|
||||||
|
|
||||||
// SignIn settings
|
// SignIn settings
|
||||||
options.SignIn.RequireConfirmedEmail = true;
|
options.SignIn.RequireConfirmedEmail = false;
|
||||||
|
options.SignIn.RequireConfirmedAccount = false;
|
||||||
options.SignIn.RequireConfirmedPhoneNumber = false;
|
options.SignIn.RequireConfirmedPhoneNumber = false;
|
||||||
|
|
||||||
// User settings
|
// User settings
|
||||||
options.User.RequireUniqueEmail = false; // changing to true will cause issues for legacy data
|
options.User.RequireUniqueEmail = false;
|
||||||
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
|
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -404,13 +404,13 @@ namespace Oqtane.Extensions
|
|||||||
else if (!string.IsNullOrEmpty(name)) // name claim provided
|
else if (!string.IsNullOrEmpty(name)) // name claim provided
|
||||||
{
|
{
|
||||||
username = name.ToLower().Replace(" ", "") + DateTime.UtcNow.ToString("mmss");
|
username = name.ToLower().Replace(" ", "") + DateTime.UtcNow.ToString("mmss");
|
||||||
emailaddress = ""; // unknown - will need to be requested from user later
|
emailaddress = username + "@unknown.com";
|
||||||
displayname = name;
|
displayname = name;
|
||||||
}
|
}
|
||||||
else // neither email nor name provided
|
else // neither email nor name provided
|
||||||
{
|
{
|
||||||
username = Guid.NewGuid().ToString("N");
|
username = Guid.NewGuid().ToString("N");
|
||||||
emailaddress = ""; // unknown - will need to be requested from user later
|
emailaddress = username + "@unknown.com";
|
||||||
displayname = username;
|
displayname = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -738,7 +738,7 @@ namespace Oqtane.Infrastructure
|
|||||||
databases += "{ \"Name\": \"LocalDB\", \"ControlType\": \"Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },";
|
databases += "{ \"Name\": \"LocalDB\", \"ControlType\": \"Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },";
|
||||||
databases += "{ \"Name\": \"SQL Server\", \"ControlType\": \"Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },";
|
databases += "{ \"Name\": \"SQL Server\", \"ControlType\": \"Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },";
|
||||||
databases += "{ \"Name\": \"SQLite\", \"ControlType\": \"Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Database.Sqlite\" },";
|
databases += "{ \"Name\": \"SQLite\", \"ControlType\": \"Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Database.Sqlite\" },";
|
||||||
databases += "{ \"Name\": \"MySQL\", \"ControlType\": \"Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.MySQL.SqlServerDatabase, Oqtane.Database.MySQL\" },";
|
databases += "{ \"Name\": \"MySQL\", \"ControlType\": \"Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.MySQL.MySQLDatabase, Oqtane.Database.MySQL\" },";
|
||||||
databases += "{ \"Name\": \"PostgreSQL\", \"ControlType\": \"Oqtane.Installer.Controls.PostgreSQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Database.PostgreSQL\" }";
|
databases += "{ \"Name\": \"PostgreSQL\", \"ControlType\": \"Oqtane.Installer.Controls.PostgreSQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Database.PostgreSQL\" }";
|
||||||
databases += "]";
|
databases += "]";
|
||||||
_configManager.AddOrUpdateSetting(SettingKeys.AvailableDatabasesSection, databases, true);
|
_configManager.AddOrUpdateSetting(SettingKeys.AvailableDatabasesSection, databases, true);
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Threading.Tasks;
|
||||||
using System.Net.Mail;
|
using MailKit.Net.Smtp;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Identity.Client;
|
||||||
|
using MimeKit;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
using MailKit.Security;
|
||||||
|
|
||||||
namespace Oqtane.Infrastructure
|
namespace Oqtane.Infrastructure
|
||||||
{
|
{
|
||||||
@ -23,7 +26,7 @@ namespace Oqtane.Infrastructure
|
|||||||
}
|
}
|
||||||
|
|
||||||
// job is executed for each tenant in installation
|
// job is executed for each tenant in installation
|
||||||
public override string ExecuteJob(IServiceProvider provider)
|
public async override Task<string> ExecuteJobAsync(IServiceProvider provider)
|
||||||
{
|
{
|
||||||
string log = "";
|
string log = "";
|
||||||
|
|
||||||
@ -44,24 +47,75 @@ namespace Oqtane.Infrastructure
|
|||||||
|
|
||||||
if (!site.IsDeleted && settingRepository.GetSettingValue(settings, "SMTPEnabled", "True") == "True")
|
if (!site.IsDeleted && settingRepository.GetSettingValue(settings, "SMTPEnabled", "True") == "True")
|
||||||
{
|
{
|
||||||
if (settingRepository.GetSettingValue(settings, "SMTPHost", "") != "" &&
|
bool valid = true;
|
||||||
settingRepository.GetSettingValue(settings, "SMTPPort", "") != "" &&
|
if (settingRepository.GetSettingValue(settings, "SMTPAuthentication", "Basic") == "Basic")
|
||||||
settingRepository.GetSettingValue(settings, "SMTPSender", "") != "")
|
|
||||||
{
|
{
|
||||||
// construct SMTP Client
|
// basic
|
||||||
var client = new SmtpClient()
|
if (settingRepository.GetSettingValue(settings, "SMTPHost", "") == "" ||
|
||||||
|
settingRepository.GetSettingValue(settings, "SMTPPort", "") == "" ||
|
||||||
|
settingRepository.GetSettingValue(settings, "SMTPSender", "") == "")
|
||||||
{
|
{
|
||||||
DeliveryMethod = SmtpDeliveryMethod.Network,
|
log += "SMTP Not Configured Properly In Site Settings - Host, Port, And Sender Are All Required" + "<br />";
|
||||||
UseDefaultCredentials = false,
|
valid = false;
|
||||||
Host = settingRepository.GetSettingValue(settings, "SMTPHost", ""),
|
}
|
||||||
Port = int.Parse(settingRepository.GetSettingValue(settings, "SMTPPort", "")),
|
}
|
||||||
EnableSsl = bool.Parse(settingRepository.GetSettingValue(settings, "SMTPSSL", "False"))
|
else
|
||||||
};
|
|
||||||
if (settingRepository.GetSettingValue(settings, "SMTPUsername", "") != "" && settingRepository.GetSettingValue(settings, "SMTPPassword", "") != "")
|
|
||||||
{
|
{
|
||||||
client.Credentials = new NetworkCredential(settingRepository.GetSettingValue(settings, "SMTPUsername", ""), settingRepository.GetSettingValue(settings, "SMTPPassword", ""));
|
// oauth
|
||||||
|
if (settingRepository.GetSettingValue(settings, "SMTPHost", "") == "" ||
|
||||||
|
settingRepository.GetSettingValue(settings, "SMTPPort", "") == "" ||
|
||||||
|
settingRepository.GetSettingValue(settings, "SMTPAuthority", "") == "" ||
|
||||||
|
settingRepository.GetSettingValue(settings, "SMTPClientId", "") == "" ||
|
||||||
|
settingRepository.GetSettingValue(settings, "SMTPClientSecret", "") == "" ||
|
||||||
|
settingRepository.GetSettingValue(settings, "SMTPScopes", "") == "" ||
|
||||||
|
settingRepository.GetSettingValue(settings, "SMTPSender", "") == "")
|
||||||
|
{
|
||||||
|
log += "SMTP Not Configured Properly In Site Settings - Host, Port, Authority, Client ID, Client Secret, Scopes, And Sender Are All Required" + "<br />";
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
// construct SMTP Client
|
||||||
|
using var client = new SmtpClient();
|
||||||
|
|
||||||
|
await client.ConnectAsync(settingRepository.GetSettingValue(settings, "SMTPHost", ""),
|
||||||
|
int.Parse(settingRepository.GetSettingValue(settings, "SMTPPort", "")),
|
||||||
|
bool.Parse(settingRepository.GetSettingValue(settings, "SMTPSSL", "False")) ? SecureSocketOptions.StartTls : SecureSocketOptions.None);
|
||||||
|
|
||||||
|
if (settingRepository.GetSettingValue(settings, "SMTPAuthentication", "Basic") == "Basic")
|
||||||
|
{
|
||||||
|
// it is possible to use basic without any authentication (not recommended)
|
||||||
|
if (settingRepository.GetSettingValue(settings, "SMTPUsername", "") != "" && settingRepository.GetSettingValue(settings, "SMTPPassword", "") != "")
|
||||||
|
{
|
||||||
|
await client.AuthenticateAsync(settingRepository.GetSettingValue(settings, "SMTPUsername", ""),
|
||||||
|
settingRepository.GetSettingValue(settings, "SMTPPassword", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// oauth authentication
|
||||||
|
var confidentialClientApplication = ConfidentialClientApplicationBuilder.Create(settingRepository.GetSettingValue(settings, "SMTPClientId", ""))
|
||||||
|
.WithAuthority(settingRepository.GetSettingValue(settings, "SMTPAuthority", ""))
|
||||||
|
.WithClientSecret(settingRepository.GetSettingValue(settings, "SMTPClientSecret", ""))
|
||||||
|
.Build();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await confidentialClientApplication.AcquireTokenForClient(settingRepository.GetSettingValue(settings, "SMTPScopes", "").Split(',')).ExecuteAsync();
|
||||||
|
var oauth2 = new SaslMechanismOAuth2(settingRepository.GetSettingValue(settings, "SMTPSender", ""), result.AccessToken);
|
||||||
|
await client.AuthenticateAsync(oauth2);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
log += "SMTP Not Configured Properly In Site Settings - OAuth Token Could Not Be Retrieved From Authority - " + ex.Message + "<br />";
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
// iterate through undelivered notifications
|
// iterate through undelivered notifications
|
||||||
int sent = 0;
|
int sent = 0;
|
||||||
List<Notification> notifications = notificationRepository.GetNotifications(site.SiteId, -1, -1).ToList();
|
List<Notification> notifications = notificationRepository.GetNotifications(site.SiteId, -1, -1).ToList();
|
||||||
@ -88,7 +142,7 @@ namespace Oqtane.Infrastructure
|
|||||||
}
|
}
|
||||||
|
|
||||||
// validate recipient
|
// validate recipient
|
||||||
if (string.IsNullOrEmpty(notification.ToEmail) || !MailAddress.TryCreate(notification.ToEmail, out _))
|
if (string.IsNullOrEmpty(notification.ToEmail) || !MailboxAddress.TryParse(notification.ToEmail, out _))
|
||||||
{
|
{
|
||||||
log += $"NotificationId: {notification.NotificationId} - Has Missing Or Invalid Recipient {notification.ToEmail}<br />";
|
log += $"NotificationId: {notification.NotificationId} - Has Missing Or Invalid Recipient {notification.ToEmail}<br />";
|
||||||
notification.IsDeleted = true;
|
notification.IsDeleted = true;
|
||||||
@ -96,55 +150,57 @@ namespace Oqtane.Infrastructure
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MailMessage mailMessage = new MailMessage();
|
MimeMessage mailMessage = new MimeMessage();
|
||||||
|
|
||||||
// sender
|
// sender
|
||||||
if (settingRepository.GetSettingValue(settings, "SMTPRelay", "False") == "True" && !string.IsNullOrEmpty(notification.FromEmail))
|
if (settingRepository.GetSettingValue(settings, "SMTPRelay", "False") == "True" && !string.IsNullOrEmpty(notification.FromEmail))
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(notification.FromDisplayName))
|
if (!string.IsNullOrEmpty(notification.FromDisplayName))
|
||||||
{
|
{
|
||||||
mailMessage.From = new MailAddress(notification.FromEmail, notification.FromDisplayName);
|
mailMessage.From.Add(new MailboxAddress(notification.FromDisplayName, notification.FromEmail));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mailMessage.From = new MailAddress(notification.FromEmail);
|
mailMessage.From.Add(new MailboxAddress("", notification.FromEmail));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mailMessage.From = new MailAddress(settingRepository.GetSettingValue(settings, "SMTPSender", ""), (!string.IsNullOrEmpty(notification.FromDisplayName)) ? notification.FromDisplayName : site.Name);
|
mailMessage.From.Add(new MailboxAddress((!string.IsNullOrEmpty(notification.FromDisplayName)) ? notification.FromDisplayName : site.Name,
|
||||||
|
settingRepository.GetSettingValue(settings, "SMTPSender", "")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// recipient
|
// recipient
|
||||||
if (!string.IsNullOrEmpty(notification.ToDisplayName))
|
if (!string.IsNullOrEmpty(notification.ToDisplayName))
|
||||||
{
|
{
|
||||||
mailMessage.To.Add(new MailAddress(notification.ToEmail, notification.ToDisplayName));
|
mailMessage.To.Add(new MailboxAddress(notification.ToDisplayName, notification.ToEmail));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mailMessage.To.Add(new MailAddress(notification.ToEmail));
|
mailMessage.To.Add(new MailboxAddress("", notification.ToEmail));
|
||||||
}
|
}
|
||||||
|
|
||||||
// subject
|
// subject
|
||||||
mailMessage.Subject = notification.Subject;
|
mailMessage.Subject = notification.Subject;
|
||||||
|
|
||||||
//body
|
//body
|
||||||
mailMessage.Body = notification.Body;
|
var bodyText = notification.Body;
|
||||||
if (!mailMessage.Body.Contains("<") || !mailMessage.Body.Contains(">"))
|
|
||||||
|
if (!bodyText.Contains('<') || !bodyText.Contains('>'))
|
||||||
{
|
{
|
||||||
// plain text messages should convert line breaks to HTML tags to preserve formatting
|
// plain text messages should convert line breaks to HTML tags to preserve formatting
|
||||||
mailMessage.Body = mailMessage.Body.Replace("\n", "<br />");
|
bodyText = bodyText.Replace("\n", "<br />");
|
||||||
}
|
}
|
||||||
|
|
||||||
// encoding
|
mailMessage.Body = new TextPart("html", System.Text.Encoding.UTF8)
|
||||||
mailMessage.SubjectEncoding = System.Text.Encoding.UTF8;
|
{
|
||||||
mailMessage.BodyEncoding = System.Text.Encoding.UTF8;
|
Text = bodyText
|
||||||
mailMessage.IsBodyHtml = true;
|
};
|
||||||
|
|
||||||
// send mail
|
// send mail
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
client.Send(mailMessage);
|
await client.SendAsync(mailMessage);
|
||||||
sent++;
|
sent++;
|
||||||
notification.IsDelivered = true;
|
notification.IsDelivered = true;
|
||||||
notification.DeliveredOn = DateTime.UtcNow;
|
notification.DeliveredOn = DateTime.UtcNow;
|
||||||
@ -157,11 +213,9 @@ namespace Oqtane.Infrastructure
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await client.DisconnectAsync(true);
|
||||||
log += "Notifications Delivered: " + sent + "<br />";
|
log += "Notifications Delivered: " + sent + "<br />";
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
log += "SMTP Not Configured Properly In Site Settings - Host, Port, And Sender Are All Required" + "<br />";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -180,7 +180,7 @@ namespace Oqtane.Managers
|
|||||||
if (User != null)
|
if (User != null)
|
||||||
{
|
{
|
||||||
string siteName = _sites.GetSite(user.SiteId).Name;
|
string siteName = _sites.GetSite(user.SiteId).Name;
|
||||||
if (!user.EmailConfirmed)
|
if (!user.EmailConfirmed && bool.Parse(_settings.GetSettingValue(EntityNames.Site, alias.SiteId, "LoginOptions:RequireConfirmedEmail", "true")))
|
||||||
{
|
{
|
||||||
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||||
string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||||
@ -252,6 +252,8 @@ namespace Oqtane.Managers
|
|||||||
await _identityUserManager.UpdateAsync(identityuser); // security stamp not updated
|
await _identityUserManager.UpdateAsync(identityuser); // security stamp not updated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bool.Parse(_settings.GetSettingValue(EntityNames.Site, alias.SiteId, "LoginOptions:RequireConfirmedEmail", "true")))
|
||||||
|
{
|
||||||
if (user.EmailConfirmed)
|
if (user.EmailConfirmed)
|
||||||
{
|
{
|
||||||
if (!identityuser.EmailConfirmed)
|
if (!identityuser.EmailConfirmed)
|
||||||
@ -275,6 +277,7 @@ namespace Oqtane.Managers
|
|||||||
var notification = new Notification(user.SiteId, user, "User Account Verification", body);
|
var notification = new Notification(user.SiteId, user, "User Account Verification", body);
|
||||||
_notifications.AddNotification(notification);
|
_notifications.AddNotification(notification);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user = _users.UpdateUser(user);
|
user = _users.UpdateUser(user);
|
||||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.User, user.UserId, SyncEventActions.Update);
|
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.User, user.UserId, SyncEventActions.Update);
|
||||||
@ -354,15 +357,14 @@ namespace Oqtane.Managers
|
|||||||
if (!user.IsDeleted)
|
if (!user.IsDeleted)
|
||||||
{
|
{
|
||||||
var alias = _tenantManager.GetAlias();
|
var alias = _tenantManager.GetAlias();
|
||||||
var twoFactorSetting = _settings.GetSetting(EntityNames.Site, alias.SiteId, "LoginOptions:TwoFactor")?.SettingValue ?? "false";
|
string siteName = _sites.GetSite(alias.SiteId).Name;
|
||||||
var twoFactorRequired = twoFactorSetting == "required" || user.TwoFactorRequired;
|
var twoFactorRequired = _settings.GetSettingValue(EntityNames.Site, alias.SiteId, "LoginOptions:TwoFactor", "false") == "required" || user.TwoFactorRequired;
|
||||||
if (twoFactorRequired)
|
if (twoFactorRequired)
|
||||||
{
|
{
|
||||||
var token = await _identityUserManager.GenerateTwoFactorTokenAsync(identityuser, "Email");
|
var token = await _identityUserManager.GenerateTwoFactorTokenAsync(identityuser, "Email");
|
||||||
user.TwoFactorCode = token;
|
user.TwoFactorCode = token;
|
||||||
user.TwoFactorExpiry = DateTime.UtcNow.AddMinutes(10);
|
user.TwoFactorExpiry = DateTime.UtcNow.AddMinutes(10);
|
||||||
_users.UpdateUser(user);
|
_users.UpdateUser(user);
|
||||||
string siteName = _sites.GetSite(alias.SiteId).Name;
|
|
||||||
string subject = _localizer["TwoFactorEmailSubject"];
|
string subject = _localizer["TwoFactorEmailSubject"];
|
||||||
subject = subject.Replace("[SiteName]", siteName);
|
subject = subject.Replace("[SiteName]", siteName);
|
||||||
string body = _localizer["TwoFactorEmailBody"].Value;
|
string body = _localizer["TwoFactorEmailBody"].Value;
|
||||||
@ -377,7 +379,7 @@ namespace Oqtane.Managers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (await _identityUserManager.IsEmailConfirmedAsync(identityuser))
|
if (!bool.Parse(_settings.GetSettingValue(EntityNames.Site, alias.SiteId, "LoginOptions:RequireConfirmedEmail", "true")) || await _identityUserManager.IsEmailConfirmedAsync(identityuser))
|
||||||
{
|
{
|
||||||
user = GetUser(identityuser.UserName, alias.SiteId);
|
user = GetUser(identityuser.UserName, alias.SiteId);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
@ -400,13 +402,25 @@ namespace Oqtane.Managers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User {Username} Is Not An Active Member Of Site {SiteId}", user.Username, alias.SiteId);
|
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Login Denied - User {Username} Is Not An Active Member Of Site {SiteId}", user.Username, alias.SiteId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Email Address Not Verified {Username}", user.Username);
|
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Login Denied - User Email Address Not Verified For {Username}", user.Username);
|
||||||
|
|
||||||
|
// send verification email again
|
||||||
|
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||||
|
string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||||
|
string subject = _localizer["VerificationEmailSubject"];
|
||||||
|
subject = subject.Replace("[SiteName]", siteName);
|
||||||
|
string body = _localizer["VerificationEmailBody"].Value;
|
||||||
|
body = body.Replace("[UserDisplayName]", user.DisplayName);
|
||||||
|
body = body.Replace("[URL]", url);
|
||||||
|
body = body.Replace("[SiteName]", siteName);
|
||||||
|
var notification = new Notification(alias.SiteId, user, subject, body);
|
||||||
|
_notifications.AddNotification(notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -538,8 +552,7 @@ namespace Oqtane.Managers
|
|||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
var alias = _tenantManager.GetAlias();
|
var alias = _tenantManager.GetAlias();
|
||||||
var twoFactorSetting = _settings.GetSetting(EntityNames.Site, alias.SiteId, "LoginOptions:TwoFactor")?.SettingValue ?? "false";
|
var twoFactorRequired = _settings.GetSettingValue(EntityNames.Site, alias.SiteId, "LoginOptions:TwoFactor", "false") == "required" || user.TwoFactorRequired;
|
||||||
var twoFactorRequired = twoFactorSetting == "required" || user.TwoFactorRequired;
|
|
||||||
if (twoFactorRequired && user.TwoFactorCode == token && DateTime.UtcNow < user.TwoFactorExpiry)
|
if (twoFactorRequired && user.TwoFactorCode == token && DateTime.UtcNow < user.TwoFactorExpiry)
|
||||||
{
|
{
|
||||||
user.IsAuthenticated = true;
|
user.IsAuthenticated = true;
|
||||||
|
@ -33,28 +33,28 @@ namespace Oqtane.Migrations.EntityBuilders
|
|||||||
|
|
||||||
protected string Schema { get; init; }
|
protected string Schema { get; init; }
|
||||||
|
|
||||||
private string RewriteSqlEntityTableName(string name)
|
private string AddSchema(string name)
|
||||||
{
|
{
|
||||||
if (Schema == null)
|
if (string.IsNullOrEmpty(Schema))
|
||||||
{
|
{
|
||||||
return RewriteName(name);
|
return name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return $"{Schema}.{RewriteName(name)}";
|
return $"{Schema}.{name}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string DelimitName(string name)
|
||||||
|
{
|
||||||
|
return ActiveDatabase.DelimitName(name);
|
||||||
|
}
|
||||||
|
|
||||||
private string RewriteName(string name)
|
private string RewriteName(string name)
|
||||||
{
|
{
|
||||||
return ActiveDatabase.RewriteName(name);
|
return ActiveDatabase.RewriteName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string RewriteName(string name, bool isQuery)
|
|
||||||
{
|
|
||||||
return ActiveDatabase.RewriteName(name, isQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string RewriteValue(string value, string type)
|
private string RewriteValue(string value, string type)
|
||||||
{
|
{
|
||||||
return ActiveDatabase.RewriteValue(value, type);
|
return ActiveDatabase.RewriteValue(value, type);
|
||||||
@ -468,9 +468,10 @@ namespace Oqtane.Migrations.EntityBuilders
|
|||||||
|
|
||||||
public void DeleteFromTable(string condition = "")
|
public void DeleteFromTable(string condition = "")
|
||||||
{
|
{
|
||||||
var deleteSql = $"DELETE FROM {RewriteSqlEntityTableName(EntityTableName)} ";
|
var deleteSql = $"DELETE FROM {AddSchema(DelimitName(RewriteName(EntityTableName)))} ";
|
||||||
if(!string.IsNullOrEmpty(condition))
|
if(!string.IsNullOrEmpty(condition))
|
||||||
{
|
{
|
||||||
|
// note that condition values must be created using RewriteName(), DelimitName(), RewriteValue() if targeting multiple database platforms
|
||||||
deleteSql += $"WHERE {condition}";
|
deleteSql += $"WHERE {condition}";
|
||||||
}
|
}
|
||||||
_migrationBuilder.Sql(deleteSql);
|
_migrationBuilder.Sql(deleteSql);
|
||||||
@ -488,9 +489,10 @@ namespace Oqtane.Migrations.EntityBuilders
|
|||||||
|
|
||||||
public void UpdateColumn(string columnName, string value, string type, string condition)
|
public void UpdateColumn(string columnName, string value, string type, string condition)
|
||||||
{
|
{
|
||||||
var updateSql = $"UPDATE {RewriteSqlEntityTableName(EntityTableName)} SET {RewriteName(columnName, true)} = {RewriteValue(value, type)} ";
|
var updateSql = $"UPDATE {AddSchema(DelimitName(RewriteName(EntityTableName)))} SET {DelimitName(RewriteName(columnName))} = {RewriteValue(value, type)} ";
|
||||||
if (!string.IsNullOrEmpty(condition))
|
if (!string.IsNullOrEmpty(condition))
|
||||||
{
|
{
|
||||||
|
// note that condition values must be created using RewriteName(), DelimitName(), RewriteValue() if targeting multiple database platforms
|
||||||
updateSql += $"WHERE {condition}";
|
updateSql += $"WHERE {condition}";
|
||||||
}
|
}
|
||||||
_migrationBuilder.Sql(updateSql);
|
_migrationBuilder.Sql(updateSql);
|
||||||
|
@ -12,14 +12,19 @@ namespace Oqtane.Migrations
|
|||||||
|
|
||||||
protected IDatabase ActiveDatabase { get; }
|
protected IDatabase ActiveDatabase { get; }
|
||||||
|
|
||||||
protected string RewriteName(string name)
|
protected string DelimitName(string name)
|
||||||
{
|
{
|
||||||
return ActiveDatabase.RewriteName(name, false);
|
return ActiveDatabase.DelimitName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string RewriteName(string name, bool isQuery)
|
protected string RewriteName(string name)
|
||||||
{
|
{
|
||||||
return ActiveDatabase.RewriteName(name, isQuery);
|
return ActiveDatabase.RewriteName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string RewriteValue(string value, string type)
|
||||||
|
{
|
||||||
|
return ActiveDatabase.RewriteValue(value, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ namespace Oqtane.Migrations.Tenant
|
|||||||
notificationEntityBuilder.AddDateTimeColumn("SendOn", true);
|
notificationEntityBuilder.AddDateTimeColumn("SendOn", true);
|
||||||
|
|
||||||
//Update new Column
|
//Update new Column
|
||||||
notificationEntityBuilder.UpdateColumn("SendOn", $"{ActiveDatabase.RewriteName("CreatedOn")}", $"{ActiveDatabase.RewriteName("SendOn")} IS NULL");
|
notificationEntityBuilder.UpdateColumn("SendOn", $"{RewriteName("CreatedOn")}", $"{DelimitName(RewriteName("SendOn"))} IS NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
@ -18,8 +18,8 @@ namespace Oqtane.Migrations.Tenant
|
|||||||
{
|
{
|
||||||
///Update Icon Field in Page
|
///Update Icon Field in Page
|
||||||
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
var updateSql = ActiveDatabase.ConcatenateSql("'oi oi-'", $"{ActiveDatabase.RewriteName("Icon")}");
|
var updateSql = ActiveDatabase.ConcatenateSql("'oi oi-'", $"{DelimitName(RewriteName("Icon"))}");
|
||||||
pageEntityBuilder.UpdateColumn("Icon", updateSql, $"{ActiveDatabase.RewriteName("Icon")} <> ''" );
|
pageEntityBuilder.UpdateColumn("Icon", updateSql, $"{DelimitName(RewriteName("Icon"))} <> ''" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,18 +20,18 @@ namespace Oqtane.Migrations.Tenant
|
|||||||
{
|
{
|
||||||
//Update DefaultContainerType In Site
|
//Update DefaultContainerType In Site
|
||||||
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
|
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'");
|
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'");
|
||||||
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'");
|
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'");
|
||||||
|
|
||||||
//Update DefaultContainerType in Page
|
//Update DefaultContainerType in Page
|
||||||
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'");
|
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'");
|
||||||
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'");
|
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'");
|
||||||
|
|
||||||
//Update ContainerType in PageModule
|
//Update ContainerType in PageModule
|
||||||
var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase);
|
var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'");
|
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'", $"{DelimitName(RewriteName("ContainerType"))} = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'");
|
||||||
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'");
|
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'", $"{DelimitName(RewriteName("ContainerType"))} = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client'");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,22 +29,22 @@ namespace Oqtane.Migrations.Tenant
|
|||||||
siteEntityBuilder.DropColumn("DefaultLayoutType");
|
siteEntityBuilder.DropColumn("DefaultLayoutType");
|
||||||
|
|
||||||
//Update DefaultContainerType In Site
|
//Update DefaultContainerType In Site
|
||||||
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'");
|
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'");
|
||||||
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'");
|
siteEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'");
|
||||||
|
|
||||||
//Drop Column from Page Table
|
//Drop Column from Page Table
|
||||||
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
pageEntityBuilder.DropColumn("LayoutType");
|
pageEntityBuilder.DropColumn("LayoutType");
|
||||||
|
|
||||||
//Update DefaultContainerType in Page
|
//Update DefaultContainerType in Page
|
||||||
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'");
|
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'");
|
||||||
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'");
|
pageEntityBuilder.UpdateColumn("DefaultContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("DefaultContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'");
|
||||||
|
|
||||||
|
|
||||||
//Update ContainerType in PageModule
|
//Update ContainerType in PageModule
|
||||||
var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase);
|
var pageModuleEntityBuilder = new PageModuleEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'");
|
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("ContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client'");
|
||||||
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", "ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'");
|
pageModuleEntityBuilder.UpdateColumn("ContainerType", "'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client'", $"{DelimitName(RewriteName("ContainerType"))} = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client'");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace Oqtane.Migrations.Tenant
|
|||||||
var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase);
|
var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
folderEntityBuilder.AddIntegerColumn("Capacity", true);
|
folderEntityBuilder.AddIntegerColumn("Capacity", true);
|
||||||
folderEntityBuilder.UpdateColumn("Capacity", "0");
|
folderEntityBuilder.UpdateColumn("Capacity", "0");
|
||||||
folderEntityBuilder.UpdateColumn("Capacity", Constants.UserFolderCapacity.ToString(), $"{ActiveDatabase.RewriteName("Name")} = 'My Folder'");
|
folderEntityBuilder.UpdateColumn("Capacity", Constants.UserFolderCapacity.ToString(), $"{DelimitName(RewriteName("Name"))} = 'My Folder'");
|
||||||
folderEntityBuilder.AddStringColumn("ImageSizes", 512, true, true);
|
folderEntityBuilder.AddStringColumn("ImageSizes", 512, true, true);
|
||||||
|
|
||||||
var fileEntityBuilder = new FileEntityBuilder(migrationBuilder, ActiveDatabase);
|
var fileEntityBuilder = new FileEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
@ -18,13 +18,13 @@ namespace Oqtane.Migrations.Tenant
|
|||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase);
|
var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
settingEntityBuilder.UpdateColumn("IsPublic", "1", "bool", $"{RewriteName("SettingName")} NOT LIKE 'SMTP%'");
|
settingEntityBuilder.UpdateColumn("IsPublic", "1", "bool", $"{DelimitName(RewriteName("SettingName"))} NOT LIKE 'SMTP%'");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase);
|
var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
settingEntityBuilder.UpdateColumn("IsPublic", "0", "bool", $"{RewriteName("SettingName")} NOT LIKE 'SMTP%'");
|
settingEntityBuilder.UpdateColumn("IsPublic", "0", "bool", $"{DelimitName(RewriteName("SettingName"))} NOT LIKE 'SMTP%'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace Oqtane.Migrations.Tenant
|
|||||||
var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase);
|
var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
settingEntityBuilder.AddBooleanColumn("IsPrivate", true);
|
settingEntityBuilder.AddBooleanColumn("IsPrivate", true);
|
||||||
settingEntityBuilder.UpdateColumn("IsPrivate", "0", "bool", "");
|
settingEntityBuilder.UpdateColumn("IsPrivate", "0", "bool", "");
|
||||||
settingEntityBuilder.UpdateColumn("IsPrivate", "1", "bool", $"{RewriteName("EntityName")} = 'Site' AND { RewriteName("SettingName")} LIKE 'SMTP%'");
|
settingEntityBuilder.UpdateColumn("IsPrivate", "1", "bool", $"{DelimitName(RewriteName("EntityName"))} = 'Site' AND { DelimitName(RewriteName("SettingName"))} LIKE 'SMTP%'");
|
||||||
settingEntityBuilder.DropColumn("IsPublic");
|
settingEntityBuilder.DropColumn("IsPublic");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
using Oqtane.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.Tenant
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TenantDBContext))]
|
||||||
|
[Migration("Tenant.06.01.04.01")]
|
||||||
|
public class RemoveUniqueEmailIndex : MultiDatabaseMigration
|
||||||
|
{
|
||||||
|
public RemoveUniqueEmailIndex(IDatabase database) : base(database)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// framework uses RequireUniqueEmail = False in .NET Identity configuration
|
||||||
|
var aspNetUsersEntityBuilder = new AspNetUsersEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
aspNetUsersEntityBuilder.DropIndex("EmailIndex");
|
||||||
|
aspNetUsersEntityBuilder.AddIndex("EmailIndex", "NormalizedEmail", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
Oqtane.Server/Migrations/Tenant/06010402_ResetTimeZone.cs
Normal file
32
Oqtane.Server/Migrations/Tenant/06010402_ResetTimeZone.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
using Oqtane.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.Tenant
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TenantDBContext))]
|
||||||
|
[Migration("Tenant.06.01.04.02")]
|
||||||
|
public class ResetTimeZone : MultiDatabaseMigration
|
||||||
|
{
|
||||||
|
public ResetTimeZone(IDatabase database) : base(database)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// resetting value as framework now uses IANA ID consistently for time zones
|
||||||
|
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
siteEntityBuilder.UpdateColumn("TimeZoneId", "''");
|
||||||
|
|
||||||
|
var userEntityBuilder = new UserEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
userEntityBuilder.UpdateColumn("TimeZoneId", "''");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>6.1.3</Version>
|
<Version>6.1.4</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -11,7 +11,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/v6.1.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
@ -34,21 +34,22 @@
|
|||||||
<EmbeddedResource Include="Scripts\MigrateTenant.sql" />
|
<EmbeddedResource Include="Scripts\MigrateTenant.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.2" />
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.7" />
|
||||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.11" />
|
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.11" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.8" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.10" />
|
||||||
<PackageReference Include="HtmlAgilityPack" Version="1.12.1" />
|
<PackageReference Include="HtmlAgilityPack" Version="1.12.2" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
|
||||||
|
<PackageReference Include="MailKit" Version="4.13.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Oqtane.Client\Oqtane.Client.csproj" />
|
<ProjectReference Include="..\Oqtane.Client\Oqtane.Client.csproj" />
|
||||||
|
@ -16,5 +16,6 @@ namespace Oqtane.Repository
|
|||||||
void DeleteSetting(string entityName, int settingId);
|
void DeleteSetting(string entityName, int settingId);
|
||||||
void DeleteSettings(string entityName, int entityId);
|
void DeleteSettings(string entityName, int entityId);
|
||||||
string GetSettingValue(IEnumerable<Setting> settings, string settingName, string defaultValue);
|
string GetSettingValue(IEnumerable<Setting> settings, string settingName, string defaultValue);
|
||||||
|
string GetSettingValue(string entityName, int entityId, string settingName, string defaultValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Modules.Admin.Users;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
@ -71,6 +73,19 @@ namespace Oqtane.Repository
|
|||||||
public void DeleteRole(int roleId)
|
public void DeleteRole(int roleId)
|
||||||
{
|
{
|
||||||
using var db = _dbContextFactory.CreateDbContext();
|
using var db = _dbContextFactory.CreateDbContext();
|
||||||
|
|
||||||
|
// remove userroles for role
|
||||||
|
foreach (var userrole in db.UserRole.Where(item => item.RoleId == roleId))
|
||||||
|
{
|
||||||
|
db.UserRole.Remove(userrole);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove permissions for role
|
||||||
|
foreach (var permission in db.Permission.Where(item => item.RoleId == roleId))
|
||||||
|
{
|
||||||
|
db.Permission.Remove(permission);
|
||||||
|
}
|
||||||
|
|
||||||
Role role = db.Role.Find(roleId);
|
Role role = db.Role.Find(roleId);
|
||||||
db.Role.Remove(role);
|
db.Role.Remove(role);
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
|
@ -180,6 +180,19 @@ namespace Oqtane.Repository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetSettingValue(string entityName, int entityId, string settingName, string defaultValue)
|
||||||
|
{
|
||||||
|
var setting = GetSetting(entityName, entityId, settingName);
|
||||||
|
if (setting != null)
|
||||||
|
{
|
||||||
|
return setting.SettingValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool IsMaster(string EntityName)
|
private bool IsMaster(string EntityName)
|
||||||
{
|
{
|
||||||
return (EntityName == EntityNames.ModuleDefinition || EntityName == EntityNames.Host);
|
return (EntityName == EntityNames.ModuleDefinition || EntityName == EntityNames.Host);
|
||||||
|
@ -2,6 +2,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Modules.Admin.Users;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
@ -131,6 +132,13 @@ namespace Oqtane.Repository
|
|||||||
public void DeleteUser(int userId)
|
public void DeleteUser(int userId)
|
||||||
{
|
{
|
||||||
using var db = _dbContextFactory.CreateDbContext();
|
using var db = _dbContextFactory.CreateDbContext();
|
||||||
|
|
||||||
|
// remove permissions for user
|
||||||
|
foreach (var permission in db.Permission.Where(item => item.UserId == userId))
|
||||||
|
{
|
||||||
|
db.Permission.Remove(permission);
|
||||||
|
}
|
||||||
|
|
||||||
var user = db.User.Find(userId);
|
var user = db.User.Find(userId);
|
||||||
db.User.Remove(user);
|
db.User.Remove(user);
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.7" />
|
||||||
<PackageReference Include="System.Net.Http.Json" Version="9.0.5" />
|
<PackageReference Include="System.Net.Http.Json" Version="9.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -19,10 +19,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -17,9 +17,9 @@ namespace [Owner].Theme.[Theme]
|
|||||||
Resources = new List<Resource>()
|
Resources = new List<Resource>()
|
||||||
{
|
{
|
||||||
// obtained from https://cdnjs.com/libraries
|
// obtained from https://cdnjs.com/libraries
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css", Integrity = "sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg==", CrossOrigin = "anonymous" },
|
new StyleSheet(Constants.BootstrapStylesheetUrl, Constants.BootstrapStylesheetIntegrity, "anonymous"),
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Theme.css" },
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Theme.css" },
|
||||||
new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.bundle.min.js", Integrity = "sha512-7Pi/otdlbbCR+LnW+F7PwFcSDJOuUJB3OxtEHbg4vSMvzvJjde4Po1v4BR9Gdc9aXNUNFVUY+SK51wWT8WF0Gg==", CrossOrigin = "anonymous" }
|
new Script(Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous")
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -75,6 +75,10 @@ app {
|
|||||||
color: gray;
|
color: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-moduleactions .dropdown-menu {
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
.app-moduleactions .dropdown-submenu {
|
.app-moduleactions .dropdown-submenu {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@ -274,11 +278,11 @@ app {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* cookie consent */
|
/* cookie consent */
|
||||||
.gdpr-consent-bar .btn-show{
|
.gdpr-consent-bar .btn-show {
|
||||||
bottom: -3px;
|
bottom: -3px;
|
||||||
left: 5px;
|
left: 5px;
|
||||||
}
|
}
|
||||||
.gdpr-consent-bar .btn-hide{
|
.gdpr-consent-bar .btn-hide {
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 5px;
|
right: 5px;
|
||||||
}
|
}
|
BIN
Oqtane.Server/wwwroot/images/disabled.png
Normal file
BIN
Oqtane.Server/wwwroot/images/disabled.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 875 B |
@ -311,7 +311,7 @@ Oqtane.Interop = {
|
|||||||
}
|
}
|
||||||
return files;
|
return files;
|
||||||
},
|
},
|
||||||
uploadFiles: async function (posturl, folder, id, antiforgerytoken, jwt, chunksize) {
|
uploadFiles: async function (posturl, folder, id, antiforgerytoken, jwt, chunksize, anonymizeuploadfilenames) {
|
||||||
var success = true;
|
var success = true;
|
||||||
var fileinput = document.getElementById('FileInput_' + id);
|
var fileinput = document.getElementById('FileInput_' + id);
|
||||||
var progressinfo = document.getElementById('ProgressInfo_' + id);
|
var progressinfo = document.getElementById('ProgressInfo_' + id);
|
||||||
@ -344,16 +344,22 @@ Oqtane.Interop = {
|
|||||||
const totalParts = Math.ceil(file.size / chunkSize);
|
const totalParts = Math.ceil(file.size / chunkSize);
|
||||||
let partCount = 0;
|
let partCount = 0;
|
||||||
|
|
||||||
|
let filename = file.name;
|
||||||
|
if (anonymizeuploadfilenames) {
|
||||||
|
filename = crypto.randomUUID() + '.' + filename.split('.').pop();
|
||||||
|
}
|
||||||
|
|
||||||
const uploadPart = () => {
|
const uploadPart = () => {
|
||||||
const start = partCount * chunkSize;
|
const start = partCount * chunkSize;
|
||||||
const end = Math.min(start + chunkSize, file.size);
|
const end = Math.min(start + chunkSize, file.size);
|
||||||
const chunk = file.slice(start, end);
|
const chunk = file.slice(start, end);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
let formdata = new FormData();
|
let formdata = new FormData();
|
||||||
formdata.append('__RequestVerificationToken', antiforgerytoken);
|
formdata.append('__RequestVerificationToken', antiforgerytoken);
|
||||||
formdata.append('folder', folder);
|
formdata.append('folder', folder);
|
||||||
formdata.append('formfile', chunk, file.name);
|
formdata.append('formfile', chunk, filename);
|
||||||
|
|
||||||
var credentials = 'same-origin';
|
var credentials = 'same-origin';
|
||||||
var headers = new Headers();
|
var headers = new Headers();
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>6.1.3</Version>
|
<Version>6.1.4</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -11,7 +11,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/v6.1.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.1.4</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
@ -19,11 +19,12 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.7" />
|
||||||
|
<PackageReference Include="NodaTime" Version="3.2.2" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Text.Json" Version="9.0.5" />
|
<PackageReference Include="System.Text.Json" Version="9.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user