Merge pull request #5119 from zyhfish/task/fix-4936
update the cookie consent control.
This commit is contained in:
commit
6a2ae2153a
|
@ -114,6 +114,16 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="cookieconsent" HelpText="Specify if cookie consent is enabled on this site. Please make sure your using theme supports Cookie Consent when enable this option." ResourceKey="CookieConsent">Cookie Consent: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="cookieconsent" class="form-select" @bind="@_cookieconsent">
|
||||
<option value="">@SharedLocalizer["Disabled"]</option>
|
||||
<option value="optin">@Localizer["OptIn"]</option>
|
||||
<option value="optout">@Localizer["OptOut"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
|
||||
|
@ -419,6 +429,7 @@
|
|||
private string _themetype = "";
|
||||
private string _containertype = "";
|
||||
private string _admincontainertype = "";
|
||||
private string _cookieconsent = "";
|
||||
|
||||
private Dictionary<string, string> _textEditors = new Dictionary<string, string>();
|
||||
private string _textEditor = "";
|
||||
|
@ -509,6 +520,7 @@
|
|||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||
_cookieconsent = SettingService.GetSetting(settings, "CookieConsent", string.Empty);
|
||||
|
||||
// functionality
|
||||
var textEditors = ServiceProvider.GetServices<ITextEditor>();
|
||||
|
@ -720,6 +732,9 @@
|
|||
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
||||
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
||||
|
||||
//cookie consent
|
||||
settings = SettingService.SetSetting(settings, "CookieConsent", _cookieconsent);
|
||||
|
||||
// functionality
|
||||
settings = SettingService.SetSetting(settings, "TextEditor", _textEditor);
|
||||
|
|
|
@ -426,6 +426,17 @@
|
|||
<data name="System" xml:space="preserve">
|
||||
<value>System</value>
|
||||
</data>
|
||||
<data name="CookieConsent.HelpText" xml:space="preserve">
|
||||
<value>Specify if cookie consent is enabled on this site. Please make sure your using theme supports Cookie Consent when enable this option.</value>
|
||||
</data>
|
||||
<data name="CookieConsent.Text" xml:space="preserve">
|
||||
<value>Cookie Consent:</value>
|
||||
</data>
|
||||
<data name="OptIn" xml:space="preserve">
|
||||
<value>Opt-In</value>
|
||||
</data>
|
||||
<data name="OptOut" xml:space="preserve">
|
||||
<value>Opt-Out</value>
|
||||
<data name="Theme.Heading" xml:space="preserve">
|
||||
<value>Theme</value>
|
||||
</data>
|
||||
|
|
|
@ -117,16 +117,13 @@
|
|||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ConsentBody" xml:space="preserve">
|
||||
<value>
|
||||
<div class="gdpr-consent-bar bg-light text-dark p-3 fixed-bottom">
|
||||
<div class="container-fluid d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
By clicking "Accept", you agree us to use cookies to ensure you get the best experience on our website.
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit">Accept</button>
|
||||
</div>
|
||||
</div>
|
||||
</value>
|
||||
<data name="Confirm" xml:space="preserve">
|
||||
<value>Confirm</value>
|
||||
</data>
|
||||
<data name="ConsentDescription" xml:space="preserve">
|
||||
<value>I agree to using cookies to provide the best user experience for this site.</value>
|
||||
</data>
|
||||
<data name="Privacy" xml:space="preserve">
|
||||
<value>Privacy</value>
|
||||
</data>
|
||||
</root>
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
|
|
@ -16,10 +16,20 @@ namespace Oqtane.Services
|
|||
|
||||
private string ApiUrl => CreateApiUrl("CookieConsent");
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> CanTrackAsync()
|
||||
public async Task<bool> IsActionedAsync()
|
||||
{
|
||||
return await GetJsonAsync<bool>($"{ApiUrl}/CanTrack");
|
||||
return await GetJsonAsync<bool>($"{ApiUrl}/IsActioned");
|
||||
}
|
||||
|
||||
public async Task<bool> CanTrackAsync(bool optOut)
|
||||
{
|
||||
return await GetJsonAsync<bool>($"{ApiUrl}/CanTrack?optout=" + optOut);
|
||||
}
|
||||
|
||||
public async Task<string> CreateActionedCookieAsync()
|
||||
{
|
||||
var cookie = await GetStringAsync($"{ApiUrl}/CreateActionedCookie");
|
||||
return cookie ?? string.Empty;
|
||||
}
|
||||
|
||||
public async Task<string> CreateConsentCookieAsync()
|
||||
|
@ -27,5 +37,11 @@ namespace Oqtane.Services
|
|||
var cookie = await GetStringAsync($"{ApiUrl}/CreateConsentCookie");
|
||||
return cookie ?? string.Empty;
|
||||
}
|
||||
|
||||
public async Task<string> WithdrawConsentCookieAsync()
|
||||
{
|
||||
var cookie = await GetStringAsync($"{ApiUrl}/WithdrawConsentCookie");
|
||||
return cookie ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,16 +9,34 @@ namespace Oqtane.Services
|
|||
/// </summary>
|
||||
public interface ICookieConsentService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get cookie consent bar actioned status
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<bool> IsActionedAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Get cookie consent status
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<bool> CanTrackAsync();
|
||||
Task<bool> CanTrackAsync(bool optOut);
|
||||
|
||||
/// <summary>
|
||||
/// Grant cookie consent
|
||||
/// create actioned cookie
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<string> CreateActionedCookieAsync();
|
||||
|
||||
/// <summary>
|
||||
/// create consent cookie
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<string> CreateConsentCookieAsync();
|
||||
|
||||
/// <summary>
|
||||
/// widhdraw consent cookie
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<string> WithdrawConsentCookieAsync();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,42 +1,155 @@
|
|||
@namespace Oqtane.Themes.Controls
|
||||
@inherits ThemeControlBase
|
||||
@inject ISettingService SettingService
|
||||
@inject ICookieConsentService CookieConsentService
|
||||
@inject IStringLocalizer<CookieConsent> Localizer
|
||||
|
||||
@if (showBanner)
|
||||
@if (_enabled && !Hidden)
|
||||
{
|
||||
<form method="post" @formname="CookieConsentForm" @onsubmit="async () => await AcceptPolicy()" data-enhance>
|
||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
else
|
||||
{
|
||||
@((MarkupString)Convert.ToString(Localizer["ConsentBody"]))
|
||||
}
|
||||
</form>
|
||||
|
||||
<div class="gdpr-consent-bar bg-light text-dark @(_showBanner ? "p-3" : "p-0") pe-5 fixed-bottom">
|
||||
<form method="post" @formname="CookieConsentForm" @onsubmit="async () => await AcceptPolicy()" data-enhance>
|
||||
@if (_showBanner)
|
||||
{
|
||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||
<div class="container-fluid d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
@((MarkupString)Convert.ToString(Localizer["ConsentDescription"]))
|
||||
@if (PageState.RenderMode == RenderModes.Static)
|
||||
{
|
||||
<input type="checkbox" name="cantrack" checked="@_canTrack" value="1" class="form-check-input ms-2" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="checkbox" name="cantrack" @bind="@_canTrack" value="1" class="form-check-input ms-2" />
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-primary" type="submit">@((MarkupString)Convert.ToString(Localizer["Confirm"]))</button>
|
||||
@if (ShowPrivacyLink)
|
||||
{
|
||||
<a class="btn btn-secondary ms-2" href="/privacy" target="_blank">@((MarkupString)Convert.ToString(Localizer["Privacy"]))</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</form>
|
||||
<form method="post" @formname="CookieConsentToggleForm" @onsubmit="async () => await ToggleBanner()" data-enhance>
|
||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||
@if(_showBanner)
|
||||
{
|
||||
<input type="hidden" name="showbanner" value="false" />
|
||||
<button type="submit" class="btn btn-light text-dark btn-sm position-absolute btn-hide">
|
||||
<i class="oi oi-chevron-bottom"></i>
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="hidden" name="showbanner" value="true" />
|
||||
<button type="submit" class="btn btn-light text-dark btn-sm position-absolute btn-show">
|
||||
<i class="oi oi-chevron-top"></i>
|
||||
</button>
|
||||
}
|
||||
|
||||
</form>
|
||||
</div>
|
||||
}
|
||||
@code {
|
||||
private bool showBanner;
|
||||
private bool _showBanner;
|
||||
private bool _enabled;
|
||||
private bool _optout;
|
||||
private bool _actioned;
|
||||
private bool _canTrack;
|
||||
private bool _consentPostback;
|
||||
private bool _togglePostback;
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; } = null;
|
||||
public bool Hidden { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool ShowPrivacyLink { get; set; } = true;
|
||||
|
||||
[SupplyParameterFromForm(FormName = "CookieConsentToggleForm")]
|
||||
public string ShowBanner {
|
||||
get => "";
|
||||
set
|
||||
{
|
||||
_showBanner = bool.Parse(value);
|
||||
_togglePostback = true;
|
||||
}
|
||||
}
|
||||
|
||||
[SupplyParameterFromForm(FormName = "CookieConsentForm")]
|
||||
public string CanTrack
|
||||
{
|
||||
get => "";
|
||||
set
|
||||
{
|
||||
_canTrack = !string.IsNullOrEmpty(value);
|
||||
_consentPostback = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
showBanner = !(await CookieConsentService.CanTrackAsync());
|
||||
var cookieConsentSetting = SettingService.GetSetting(PageState.Site.Settings, "CookieConsent", string.Empty);
|
||||
_enabled = !string.IsNullOrEmpty(cookieConsentSetting);
|
||||
_optout = cookieConsentSetting == "optout";
|
||||
_actioned = await CookieConsentService.IsActionedAsync();
|
||||
|
||||
if (!_consentPostback)
|
||||
{
|
||||
_canTrack = await CookieConsentService.CanTrackAsync(_optout);
|
||||
}
|
||||
|
||||
if(!_togglePostback)
|
||||
{
|
||||
_showBanner = !_actioned;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AcceptPolicy()
|
||||
{
|
||||
var cookieString = await CookieConsentService.CreateConsentCookieAsync();
|
||||
var cookieString = string.Empty;
|
||||
if(_optout)
|
||||
{
|
||||
cookieString = _canTrack ? await CookieConsentService.WithdrawConsentCookieAsync() : await CookieConsentService.CreateConsentCookieAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
cookieString = _canTrack ? await CookieConsentService.CreateConsentCookieAsync() : await CookieConsentService.WithdrawConsentCookieAsync();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(cookieString))
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.SetCookieString(cookieString);
|
||||
|
||||
showBanner = false;
|
||||
_actioned = true;
|
||||
_showBanner = false;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ToggleBanner()
|
||||
{
|
||||
if (!_actioned)
|
||||
{
|
||||
var cookieString = await CookieConsentService.CreateActionedCookieAsync();
|
||||
if (!string.IsNullOrEmpty(cookieString))
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.SetCookieString(cookieString);
|
||||
|
||||
_actioned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(PageState.RenderMode == RenderModes.Interactive)
|
||||
{
|
||||
_showBanner = !_showBanner;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Pane Name="Top Full Width" />
|
||||
<Pane Name="Top Full Width" />
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
@ -108,13 +108,13 @@
|
|||
<Pane Name="Footer" />
|
||||
}
|
||||
<CookieConsent />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@code {
|
||||
public override string Name => "Default Theme";
|
||||
|
||||
public override string Panes => PaneNames.Default + ",Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width,Footer";
|
||||
public override string Panes => PaneNames.Default + ",Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width,Footer";
|
||||
|
||||
private bool _login = true;
|
||||
private bool _register = true;
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
<select id="scope" class="form-select" value="@_scope" @onchange="(e => ScopeChanged(e))">
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||
{
|
||||
<option value="site">@Localizer["Site"]</option>
|
||||
<option value="site">@Localizer["Site"]</option>
|
||||
}
|
||||
<option value="page">@Localizer["Page"]</option>
|
||||
<option value="page">@Localizer["Page"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -92,7 +92,7 @@
|
|||
settings = SettingService.MergeSettings(PageState.Site.Settings, settings);
|
||||
_login = SettingService.GetSetting(settings, GetType().Namespace + ":Login", "-");
|
||||
_register = SettingService.GetSetting(settings, GetType().Namespace + ":Register", "-");
|
||||
_footer = SettingService.GetSetting(settings, GetType().Namespace + ":Footer", "-");
|
||||
_footer = SettingService.GetSetting(settings, GetType().Namespace + ":Footer", "-");
|
||||
}
|
||||
await Task.Yield();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace Oqtane.UI
|
|||
public bool IsInternalNavigation { get; set; }
|
||||
public Guid RenderId { get; set; }
|
||||
public bool Refresh { get; set; }
|
||||
public bool AllowCookies { get; set; }
|
||||
|
||||
public List<Page> Pages
|
||||
{
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
@inject IUrlMappingRepository UrlMappingRepository
|
||||
@inject IVisitorRepository VisitorRepository
|
||||
@inject IJwtManager JwtManager
|
||||
@inject ICookieConsentService CookieConsentService
|
||||
@inject ISettingService SettingService
|
||||
|
||||
@if (_initialized)
|
||||
{
|
||||
|
@ -107,6 +109,7 @@
|
|||
private string _styleSheets = "";
|
||||
private string _scripts = "";
|
||||
private string _message = "";
|
||||
private bool _allowCookies;
|
||||
private PageState _pageState;
|
||||
|
||||
// CascadingParameter is required to access HttpContext
|
||||
|
@ -140,6 +143,9 @@
|
|||
_prerender = site.Prerender;
|
||||
_fingerprint = site.Fingerprint;
|
||||
|
||||
var cookieConsentSettings = SettingService.GetSetting(site.Settings, "CookieConsent", string.Empty);
|
||||
_allowCookies = string.IsNullOrEmpty(cookieConsentSettings) || await CookieConsentService.CanTrackAsync(cookieConsentSettings == "optout");
|
||||
|
||||
var modules = new List<Module>();
|
||||
|
||||
Route route = new Route(url, alias.Path);
|
||||
|
@ -170,7 +176,7 @@
|
|||
modules = await SiteService.GetModulesAsync(site.SiteId, page.PageId);
|
||||
}
|
||||
|
||||
if (site.VisitorTracking)
|
||||
if (site.VisitorTracking && _allowCookies)
|
||||
{
|
||||
TrackVisitor(site.SiteId);
|
||||
}
|
||||
|
@ -245,7 +251,8 @@
|
|||
ReturnUrl = "",
|
||||
IsInternalNavigation = false,
|
||||
RenderId = Guid.NewGuid(),
|
||||
Refresh = true
|
||||
Refresh = true,
|
||||
AllowCookies = _allowCookies
|
||||
};
|
||||
}
|
||||
else
|
||||
|
|
|
@ -19,10 +19,22 @@ namespace Oqtane.Controllers
|
|||
_cookieConsentService = cookieConsentService;
|
||||
}
|
||||
|
||||
[HttpGet("CanTrack")]
|
||||
public async Task<bool> CanTrack()
|
||||
[HttpGet("IsActioned")]
|
||||
public async Task<bool> IsActioned()
|
||||
{
|
||||
return await _cookieConsentService.CanTrackAsync();
|
||||
return await _cookieConsentService.IsActionedAsync();
|
||||
}
|
||||
|
||||
[HttpGet("CanTrack")]
|
||||
public async Task<bool> CanTrack(string optout)
|
||||
{
|
||||
return await _cookieConsentService.CanTrackAsync(bool.Parse(optout));
|
||||
}
|
||||
|
||||
[HttpGet("CreateActionedCookie")]
|
||||
public async Task<string> CreateActionedCookie()
|
||||
{
|
||||
return await _cookieConsentService.CreateActionedCookieAsync();
|
||||
}
|
||||
|
||||
[HttpGet("CreateConsentCookie")]
|
||||
|
@ -30,5 +42,11 @@ namespace Oqtane.Controllers
|
|||
{
|
||||
return await _cookieConsentService.CreateConsentCookieAsync();
|
||||
}
|
||||
|
||||
[HttpGet("WithdrawConsentCookie")]
|
||||
public async Task<string> WithdrawConsentCookie()
|
||||
{
|
||||
return await _cookieConsentService.WithdrawConsentCookieAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,5 @@ namespace Oqtane.Extensions
|
|||
|
||||
public static IApplicationBuilder UseExceptionMiddleWare(this IApplicationBuilder builder)
|
||||
=> builder.UseMiddleware<ExceptionMiddleware>();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,6 +169,33 @@ namespace Oqtane.SiteTemplates
|
|||
}
|
||||
});
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Privacy",
|
||||
Parent = "",
|
||||
Path = "privacy",
|
||||
Icon = Icons.Eye,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Privacy Policy", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission> {
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = "<p>By using our website, you agree to this privacy policy. We value your privacy and are committed to protecting your personal information. This policy outlines how we collect, use, and safeguard your data when you visit our website or use our services.</p>"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Not Found",
|
||||
|
|
|
@ -75,6 +75,9 @@ namespace Oqtane.Infrastructure
|
|||
case "6.1.0":
|
||||
Upgrade_6_1_0(tenant, scope);
|
||||
break;
|
||||
case "6.1.1":
|
||||
Upgrade_6_1_1(tenant, scope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -457,6 +460,41 @@ namespace Oqtane.Infrastructure
|
|||
RemoveAssemblies(tenant, assemblies, "6.1.0");
|
||||
}
|
||||
|
||||
private void Upgrade_6_1_1(Tenant tenant, IServiceScope scope)
|
||||
{
|
||||
var pageTemplates = new List<PageTemplate>
|
||||
{
|
||||
new PageTemplate
|
||||
{
|
||||
Name = "Privacy",
|
||||
Parent = "",
|
||||
Path = "privacy",
|
||||
Icon = Icons.Eye,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Privacy Policy", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission> {
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = "<p>By using our website, you agree to this privacy policy. We value your privacy and are committed to protecting your personal information. This policy outlines how we collect, use, and safeguard your data when you visit our website or use our services.</p>"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AddPagesToSites(scope, tenant, pageTemplates);
|
||||
}
|
||||
|
||||
private void AddPagesToSites(IServiceScope scope, Tenant tenant, List<PageTemplate> pageTemplates)
|
||||
{
|
||||
var tenants = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
|
@ -12,27 +15,106 @@ namespace Oqtane.Services
|
|||
public class ServerCookieConsentService : ICookieConsentService
|
||||
{
|
||||
private readonly IHttpContextAccessor _accessor;
|
||||
private readonly CookiePolicyOptions _cookiePolicyOptions;
|
||||
|
||||
public ServerCookieConsentService(IHttpContextAccessor accessor)
|
||||
public ServerCookieConsentService(IHttpContextAccessor accessor, IOptions<CookiePolicyOptions> cookiePolicyOptions)
|
||||
{
|
||||
_accessor = accessor;
|
||||
_cookiePolicyOptions = cookiePolicyOptions.Value;
|
||||
}
|
||||
|
||||
public Task<bool> CanTrackAsync()
|
||||
public Task<bool> IsActionedAsync()
|
||||
{
|
||||
var consentFeature = _accessor.HttpContext?.Features.Get<ITrackingConsentFeature>();
|
||||
var canTrack = consentFeature?.CanTrack ?? true;
|
||||
var actioned = false;
|
||||
if (_accessor.HttpContext != null)
|
||||
{
|
||||
var cookieValue = GetCookieValue("actioned");
|
||||
actioned = cookieValue == Constants.CookieConsentActionCookieValue;
|
||||
}
|
||||
return Task.FromResult(actioned);
|
||||
}
|
||||
|
||||
public Task<bool> CanTrackAsync(bool optOut)
|
||||
{
|
||||
var canTrack = true;
|
||||
if (_accessor.HttpContext != null)
|
||||
{
|
||||
var cookieValue = GetCookieValue("consent");
|
||||
var saved = cookieValue == Constants.CookieConsentCookieValue;
|
||||
if (optOut)
|
||||
{
|
||||
canTrack = string.IsNullOrEmpty(cookieValue) || !saved;
|
||||
}
|
||||
else
|
||||
{
|
||||
canTrack = cookieValue == Constants.CookieConsentCookieValue;
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(canTrack);
|
||||
}
|
||||
|
||||
public Task<string> CreateActionedCookieAsync()
|
||||
{
|
||||
var cookieString = CreateCookieString(false, string.Empty);
|
||||
return Task.FromResult(cookieString);
|
||||
}
|
||||
|
||||
public Task<string> CreateConsentCookieAsync()
|
||||
{
|
||||
var consentFeature = _accessor.HttpContext?.Features.Get<ITrackingConsentFeature>();
|
||||
consentFeature?.GrantConsent();
|
||||
var cookie = consentFeature?.CreateConsentCookie() ?? string.Empty;
|
||||
var cookieString = CreateCookieString(true, Constants.CookieConsentCookieValue);
|
||||
return Task.FromResult(cookieString);
|
||||
}
|
||||
|
||||
return Task.FromResult(cookie);
|
||||
public Task<string> WithdrawConsentCookieAsync()
|
||||
{
|
||||
var cookieString = CreateCookieString(true, string.Empty);
|
||||
return Task.FromResult(cookieString);
|
||||
}
|
||||
|
||||
private string GetCookieValue(string type)
|
||||
{
|
||||
var cookieValue = string.Empty;
|
||||
if (_accessor.HttpContext != null)
|
||||
{
|
||||
var value = _accessor.HttpContext.Request.Cookies[Constants.CookieConsentCookieName];
|
||||
var index = type == "actioned" ? 1 : 0;
|
||||
cookieValue = !string.IsNullOrEmpty(value) && value.Contains("|") ? value.Split('|')[index] : string.Empty;
|
||||
}
|
||||
|
||||
return cookieValue;
|
||||
}
|
||||
|
||||
private string CreateCookieString(bool saved, string savedValue)
|
||||
{
|
||||
var cookieString = string.Empty;
|
||||
if (_accessor.HttpContext != null)
|
||||
{
|
||||
var savedCookie = saved ? savedValue : GetCookieValue("consent");
|
||||
var actionedCookie = Constants.CookieConsentActionCookieValue;
|
||||
var cookieValue = $"{savedCookie}|{actionedCookie}";
|
||||
var options = _cookiePolicyOptions.ConsentCookie.Build(_accessor.HttpContext);
|
||||
|
||||
if (!_accessor.HttpContext.Response.HasStarted)
|
||||
{
|
||||
_accessor.HttpContext.Response.Cookies.Append(
|
||||
Constants.CookieConsentCookieName,
|
||||
cookieValue,
|
||||
new CookieOptions()
|
||||
{
|
||||
Expires = options.Expires,
|
||||
IsEssential = true,
|
||||
SameSite = options.SameSite,
|
||||
Secure = options.Secure
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
//get the cookie string from response header
|
||||
cookieString = options.CreateCookieHeader(Constants.CookieConsentCookieName, Uri.EscapeDataString(cookieValue)).ToString();
|
||||
}
|
||||
|
||||
return cookieString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,13 +169,6 @@ namespace Oqtane
|
|||
options.CustomSchemaIds(type => type.ToString()); // Handle SchemaId already used for different type
|
||||
});
|
||||
services.TryAddSwagger(_useSwagger);
|
||||
|
||||
//add cookie consent policy
|
||||
services.Configure<CookiePolicyOptions>(options =>
|
||||
{
|
||||
options.CheckConsentNeeded = context => true;
|
||||
options.ConsentCookieValue = Constants.CookieConsentCookieValue;
|
||||
});
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
@ -232,7 +225,6 @@ namespace Oqtane
|
|||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseAntiforgery();
|
||||
app.UseCookiePolicy();
|
||||
|
||||
if (_useSwagger)
|
||||
{
|
||||
|
|
|
@ -121,6 +121,16 @@
|
|||
color: white;
|
||||
}
|
||||
|
||||
/* cookie consent */
|
||||
.gdpr-consent-bar .btn-show{
|
||||
bottom: 0;
|
||||
right: 5px;
|
||||
}
|
||||
.gdpr-consent-bar .btn-hide{
|
||||
top: 0;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.main .top-row {
|
||||
display: none;
|
||||
|
|
|
@ -100,6 +100,16 @@ div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu
|
|||
z-index: 1000;
|
||||
}
|
||||
|
||||
/* cookie consent */
|
||||
.gdpr-consent-bar .btn-show{
|
||||
bottom: 0;
|
||||
right: 5px;
|
||||
}
|
||||
.gdpr-consent-bar .btn-hide{
|
||||
top: 0;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
|
||||
.app-menu {
|
||||
|
|
|
@ -4,8 +4,8 @@ namespace Oqtane.Shared
|
|||
{
|
||||
public class Constants
|
||||
{
|
||||
public static readonly string Version = "6.1.0";
|
||||
public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0,5.1.1,5.1.2,5.2.0,5.2.1,5.2.2,5.2.3,5.2.4,6.0.0,6.0.1,6.1.0";
|
||||
public static readonly string Version = "6.1.1";
|
||||
public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0,5.1.1,5.1.2,5.2.0,5.2.1,5.2.2,5.2.3,5.2.4,6.0.0,6.0.1,6.1.0,6.1.1";
|
||||
public const string PackageId = "Oqtane.Framework";
|
||||
public const string ClientId = "Oqtane.Client";
|
||||
public const string UpdaterPackageId = "Oqtane.Updater";
|
||||
|
@ -91,7 +91,9 @@ namespace Oqtane.Shared
|
|||
public const string BootstrapStylesheetUrl = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css";
|
||||
public const string BootstrapStylesheetIntegrity = "sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg==";
|
||||
|
||||
public const string CookieConsentCookieValue = "true";
|
||||
public const string CookieConsentCookieName = "Oqtane.CookieConsent";
|
||||
public const string CookieConsentCookieValue = "yes";
|
||||
public const string CookieConsentActionCookieValue = "yes";
|
||||
// Obsolete constants
|
||||
|
||||
const string RoleObsoleteMessage = "Use the corresponding member from Oqtane.Shared.RoleNames";
|
||||
|
|
Loading…
Reference in New Issue
Block a user