diff --git a/Extensions/Manage/Dnn.PersonaBar.Sites/Components/SitesController.cs b/Extensions/Manage/Dnn.PersonaBar.Sites/Components/SitesController.cs index 211d84ad3..9195c0808 100644 --- a/Extensions/Manage/Dnn.PersonaBar.Sites/Components/SitesController.cs +++ b/Extensions/Manage/Dnn.PersonaBar.Sites/Components/SitesController.cs @@ -824,6 +824,42 @@ private void SerializePortalSettings(XmlWriter writer, PortalInfo portal, bool i writer.WriteElementString("cookiemorelink", setting); } + settingsDictionary.TryGetValue("DataConsentActive", out setting); + if (!string.IsNullOrEmpty(setting)) + { + writer.WriteElementString("dataconsentactive", setting); + } + + settingsDictionary.TryGetValue("DataConsentTermsLastChange", out setting); + if (!string.IsNullOrEmpty(setting)) + { + writer.WriteElementString("dataconsenttermslastchange", setting); + } + + settingsDictionary.TryGetValue("DataConsentConsentRedirect", out setting); + if (!string.IsNullOrEmpty(setting)) + { + writer.WriteElementString("dataconsentconsentredirect", setting); + } + + settingsDictionary.TryGetValue("DataConsentUserDeleteAction", out setting); + if (!string.IsNullOrEmpty(setting)) + { + writer.WriteElementString("dataconsentuserdeleteaction", setting); + } + + settingsDictionary.TryGetValue("DataConsentDelay", out setting); + if (!string.IsNullOrEmpty(setting)) + { + writer.WriteElementString("dataconsentdelay", setting); + } + + settingsDictionary.TryGetValue("DataConsentDelayMeasurement", out setting); + if (!string.IsNullOrEmpty(setting)) + { + writer.WriteElementString("dataconsentdelaymeasurement", setting); + } + //End Portal Settings writer.WriteEndElement(); } diff --git a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Dnn.PersonaBar.SiteSettings.csproj b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Dnn.PersonaBar.SiteSettings.csproj index 47d427e2f..6f68906c9 100644 --- a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Dnn.PersonaBar.SiteSettings.csproj +++ b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Dnn.PersonaBar.SiteSettings.csproj @@ -76,6 +76,7 @@ + False @@ -84,6 +85,10 @@ + + + + False ..\..\..\bin\System.Web.Http.dll @@ -93,6 +98,7 @@ ..\..\..\bin\System.Web.Http.WebHost.dll + @@ -109,6 +115,7 @@ + diff --git a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/Dto/ResetTermsAgreementRequest.cs b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/Dto/ResetTermsAgreementRequest.cs new file mode 100644 index 000000000..8a0011f08 --- /dev/null +++ b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/Dto/ResetTermsAgreementRequest.cs @@ -0,0 +1,28 @@ +#region Copyright +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2002-2018 +// by DotNetNuke Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +#endregion + +namespace Dnn.PersonaBar.SiteSettings.Services.Dto +{ + public class ResetTermsAgreementRequest + { + public int? PortalId { get; set; } + } +} \ No newline at end of file diff --git a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/Dto/UpdatePrivacySettings.cs b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/Dto/UpdatePrivacySettings.cs index 155977ad9..ac3f2df66 100644 --- a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/Dto/UpdatePrivacySettings.cs +++ b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/Dto/UpdatePrivacySettings.cs @@ -41,5 +41,15 @@ public class UpdatePrivacySettingsRequest public bool DnnImprovementProgram { get; set; } public bool DisplayCopyright { get; set; } + + public bool DataConsentActive { get; set; } + + public int DataConsentConsentRedirect { get; set; } + + public int DataConsentUserDeleteAction { get; set; } + + public int DataConsentDelay { get; set; } + + public string DataConsentDelayMeasurement { get; set; } } } \ No newline at end of file diff --git a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/SiteSettingsController.cs b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/SiteSettingsController.cs index 61b5c3d48..083183fe0 100644 --- a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/SiteSettingsController.cs +++ b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/Services/SiteSettingsController.cs @@ -1576,7 +1576,14 @@ public HttpResponseMessage GetPrivacySettings(int? portalId) portalSettings.CookieMoreLink, CheckUpgrade = HostController.Instance.GetBoolean("CheckUpgrade", true), DnnImprovementProgram = HostController.Instance.GetBoolean("DnnImprovementProgram", true), - DisplayCopyright = HostController.Instance.GetBoolean("Copyright", true) + DisplayCopyright = HostController.Instance.GetBoolean("Copyright", true), + portalSettings.DataConsentActive, + DataConsentResetTerms = false, + DataConsentConsentRedirect = TabSanitizer(portalSettings.DataConsentConsentRedirect, pid)?.TabID, + DataConsentConsentRedirectName = TabSanitizer(portalSettings.DataConsentConsentRedirect, pid)?.TabName, + DataConsentUserDeleteAction = (int)portalSettings.DataConsentUserDeleteAction, + PortalSettings.DataConsentDelay, + PortalSettings.DataConsentDelayMeasurement } }); } @@ -1611,6 +1618,11 @@ public HttpResponseMessage UpdatePrivacySettings(UpdatePrivacySettingsRequest re HostController.Instance.Update("CheckUpgrade", request.CheckUpgrade ? "Y" : "N", false); HostController.Instance.Update("DnnImprovementProgram", request.DnnImprovementProgram ? "Y" : "N", false); HostController.Instance.Update("Copyright", request.DisplayCopyright ? "Y" : "N", false); + PortalController.UpdatePortalSetting(pid, "DataConsentActive", request.DataConsentActive.ToString(), false); + PortalController.UpdatePortalSetting(pid, "DataConsentConsentRedirect", ValidateTabId(request.DataConsentConsentRedirect, pid).ToString(), false); + PortalController.UpdatePortalSetting(pid, "DataConsentUserDeleteAction", request.DataConsentUserDeleteAction.ToString(), false); + PortalController.UpdatePortalSetting(pid, "DataConsentDelay", request.DataConsentDelay.ToString(), false); + PortalController.UpdatePortalSetting(pid, "DataConsentDelayMeasurement", request.DataConsentDelayMeasurement, false); DataCache.ClearCache(); return Request.CreateResponse(HttpStatusCode.OK, new { Success = true }); @@ -1622,6 +1634,35 @@ public HttpResponseMessage UpdatePrivacySettings(UpdatePrivacySettingsRequest re } } + /// POST: api/SiteSettings/ResetTermsAgreement + /// + /// Resets terms and conditions agreements + /// + /// + /// + [HttpPost] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = Constants.AdminsRoleName)] + public HttpResponseMessage ResetTermsAgreement(ResetTermsAgreementRequest request) + { + try + { + var pid = request.PortalId ?? PortalId; + if (!UserInfo.IsSuperUser && PortalId != pid) + { + return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, AuthFailureMessage); + } + UserController.ResetTermsAgreement(pid); + PortalController.UpdatePortalSetting(pid, "DataConsentTermsLastChange", DateTime.Now.ToString("u"), true); + return Request.CreateResponse(HttpStatusCode.OK, new { Success = true }); + } + catch (Exception exc) + { + Logger.Error(exc); + return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, exc); + } + } + #endregion #region Search Settings API diff --git a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/SiteSettings.Web/src/actions/siteBehavior.js b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/SiteSettings.Web/src/actions/siteBehavior.js index 6905feb53..fb5f248a5 100644 --- a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/SiteSettings.Web/src/actions/siteBehavior.js +++ b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/SiteSettings.Web/src/actions/siteBehavior.js @@ -499,6 +499,17 @@ const siteBehaviorActions = { }); }; }, + resetTermsAgreement(payload, callback, failureCallback) { + ApplicationService.resetTermsAgreement(payload, data => { + if (callback) { + callback(data); + } + }, data => { + if (failureCallback) { + failureCallback(data); + } + }); + }, privacySettingsClientModified(parameter) { return (dispatch) => { dispatch({ diff --git a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/SiteSettings.Web/src/components/privacySettings/index.jsx b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/SiteSettings.Web/src/components/privacySettings/index.jsx index 834a47071..d9b8f9434 100644 --- a/Extensions/Settings/Dnn.PersonaBar.SiteSettings/SiteSettings.Web/src/components/privacySettings/index.jsx +++ b/Extensions/Settings/Dnn.PersonaBar.SiteSettings/SiteSettings.Web/src/components/privacySettings/index.jsx @@ -2,278 +2,460 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; import { connect } from "react-redux"; import { siteBehavior as SiteBehaviorActions } from "../../actions"; -import { InputGroup, Switch, GridSystem, Tooltip, Label, Button, SingleLineInputWithError } from "@dnnsoftware/dnn-react-common"; +import { + InputGroup, + Switch, + GridSystem, + Tooltip, + Label, + Button, + SingleLineInputWithError, + PagePicker, + Dropdown +} from "@dnnsoftware/dnn-react-common"; import "./style.less"; import util from "../../utils"; import resx from "../../resources"; import styles from "./style.less"; class PrivacySettingsPanelBody extends Component { - constructor() { - super(); - this.state = { - privacySettings: undefined - }; - } + constructor() { + super(); + this.state = { + privacySettings: undefined + }; + } - loadData() { - const { props } = this; - props.dispatch( - SiteBehaviorActions.getPrivacySettings(props.portalId, data => { - this.setState({ - privacySettings: Object.assign({}, data.Settings) - }); - }) - ); - } + loadData() { + const { props } = this; + props.dispatch( + SiteBehaviorActions.getPrivacySettings(props.portalId, data => { + this.setState({ + privacySettings: Object.assign({}, data.Settings) + }); + }) + ); + } - componentDidMount() { - this.loadData(); - } + componentDidMount() { + this.loadData(); + } - componentDidUpdate(prevProps) { - const { props } = this; - if (props.privacySettings) { - let portalIdChanged = false; - let cultureCodeChanged = false; - if (props.portalId === undefined || prevProps.portalId === props.portalId) { - portalIdChanged = false; - } - else { - portalIdChanged = true; - } - if (props.cultureCode === undefined || prevProps.cultureCode === props.cultureCode) { - cultureCodeChanged = false; - } - else { - cultureCodeChanged = true; - } + componentDidUpdate(prevProps) { + const { props } = this; + if (props.privacySettings) { + let portalIdChanged = false; + let cultureCodeChanged = false; + if ( + props.portalId === undefined || + prevProps.portalId === props.portalId + ) { + portalIdChanged = false; + } else { + portalIdChanged = true; + } + if ( + props.cultureCode === undefined || + prevProps.cultureCode === props.cultureCode + ) { + cultureCodeChanged = false; + } else { + cultureCodeChanged = true; + } - if (portalIdChanged || cultureCodeChanged) { - this.loadData(); - } - } + if (portalIdChanged || cultureCodeChanged) { + this.loadData(); + } } + } - onSettingChange(key, event) { - let { state, props } = this; - let privacySettings = Object.assign({}, state.privacySettings); + getUserDeleteOptions() { + return [ + { label: resx.get("Off"), value: 0 }, + { label: resx.get("DataConsentUserDeleteManual"), value: 1 }, + { label: resx.get("DataConsentUserDelayedHardDelete"), value: 2 }, + { label: resx.get("DataConsentUserHardDelete"), value: 3 } + ]; + } - if (key === "ThrottlingInterval" || key === "RecipientLimit") { - privacySettings[key] = event.value; - } else { - privacySettings[key] = - typeof event === "object" ? event.target.value : event; - } + getTimeLapseMeasurements() { + return [ + { value: "h", label: resx.get("Hours") }, + { value: "d", label: resx.get("Days") }, + { value: "w", label: resx.get("Weeks") } + ]; + } - this.setState({ - privacySettings: privacySettings - }); - - props.dispatch( - SiteBehaviorActions.privacySettingsClientModified(privacySettings) + onDataConsentResetTerms() { + util.utilities.confirm( + resx.get("DataConsentResetTerms.Confirm"), + resx.get("Yes"), + resx.get("No"), + function onDataConsentResetTermsConfirm() { + SiteBehaviorActions.resetTermsAgreement( + { + PortalId: this.state.privacySettings.PortalId + }, + () => { + util.utilities.notify(resx.get("DataConsentResetTerms.Completed")); + } ); + }.bind(this) + ); + } + + onSettingChange(key, event) { + let { state, props } = this; + let privacySettings = Object.assign({}, state.privacySettings); + + if ( + key === "DataConsentUserDeleteAction" || + key === "DataConsentDelayMeasurement" + ) { + privacySettings[key] = event.value; + } else { + privacySettings[key] = + typeof event === "object" ? event.target.value : event; } - onUpdate(event) { - event.preventDefault(); - const { props, state } = this; + this.setState({ + privacySettings: privacySettings + }); + + props.dispatch( + SiteBehaviorActions.privacySettingsClientModified(privacySettings) + ); + } + onUpdate(event) { + event.preventDefault(); + const { props, state } = this; + + props.dispatch( + SiteBehaviorActions.updatePrivacySettings( + state.privacySettings, + () => { + util.utilities.notify(resx.get("SettingsUpdateSuccess")); + this.setState({ + privacySettings: Object.assign({}, this.state.privacySettings, { + DataConsentResetTerms: false + }) + }); + }, + () => { + util.utilities.notifyError(resx.get("SettingsError")); + } + ) + ); + } + + onCancel() { + const { props } = this; + util.utilities.confirm( + resx.get("SettingsRestoreWarning"), + resx.get("Yes"), + resx.get("No"), + () => { props.dispatch( - SiteBehaviorActions.updatePrivacySettings( - state.privacySettings, - () => { - util.utilities.notify(resx.get("SettingsUpdateSuccess")); - }, - () => { - util.utilities.notifyError(resx.get("SettingsError")); - } - ) + SiteBehaviorActions.getPrivacySettings(props.portalId, data => { + this.setState({ + privacySettings: Object.assign({}, data.Settings) + }); + }) ); - } + } + ); + } - onCancel() { - const { props } = this; - util.utilities.confirm( - resx.get("SettingsRestoreWarning"), - resx.get("Yes"), - resx.get("No"), - () => { - props.dispatch( - SiteBehaviorActions.getPrivacySettings(props.portalId, data => { - this.setState({ - privacySettings: Object.assign({}, data.Settings) - }); - }) - ); + /* eslint-disable react/no-danger */ + render() { + const { props, state } = this; + const TabParameters = { + portalId: props.portalId !== undefined ? props.portalId : -2, + cultureCode: props.cultureCode || "", + isMultiLanguage: false, + excludeAdminTabs: false, + roles: "", + sortOrder: 0 + }; + let TabParameters_1 = Object.assign(Object.assign({}, TabParameters), { + disabledNotSelectable: false + }); + const noneSpecifiedText = "<" + resx.get("NoneSpecified") + ">"; + const columnOneLeft = state.privacySettings ? ( +
+ +