From 9ed42d00bda678d047b2ca7110ed545f2dc5444e Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Mon, 21 Jul 2014 15:10:57 +0200 Subject: [PATCH] Added privacy settings for social networks --- com.woltlab.wcf/templates/shareButtons.tpl | 7 +- .../templates/shareButtonsPrivacySettings.tpl | 25 ++ wcfsetup/install/files/js/WCF.Message.js | 239 +++++++++++++++--- .../files/lib/data/user/User.class.php | 18 ++ .../files/lib/data/user/UserAction.class.php | 57 +++++ wcfsetup/install/files/style/message.less | 19 +- wcfsetup/install/lang/de.xml | 2 + wcfsetup/install/lang/en.xml | 2 + wcfsetup/setup/db/install.sql | 1 + 9 files changed, 316 insertions(+), 54 deletions(-) create mode 100644 com.woltlab.wcf/templates/shareButtonsPrivacySettings.tpl diff --git a/com.woltlab.wcf/templates/shareButtons.tpl b/com.woltlab.wcf/templates/shareButtons.tpl index 1369f32420..218de94477 100644 --- a/com.woltlab.wcf/templates/shareButtons.tpl +++ b/com.woltlab.wcf/templates/shareButtons.tpl @@ -39,10 +39,11 @@ 'wcf.message.share.facebook': '{lang}wcf.message.share.facebook{/lang}', 'wcf.message.share.google': '{lang}wcf.message.share.google{/lang}', 'wcf.message.share.reddit': '{lang}wcf.message.share.reddit{/lang}', - 'wcf.message.share.twitter': '{lang}wcf.message.share.twitter{/lang}' + 'wcf.message.share.twitter': '{lang}wcf.message.share.twitter{/lang}', + 'wcf.message.share.privacy': '{lang}wcf.message.share.privacy{/lang}' }); - - new WCF.Message.Share.Page({if SHARE_BUTTONS_SHOW_COUNT}true{else}false{/if}); + var $privacySettings = { {implode from=$__wcf->getUser()->getSocialNetworkPrivacySettings() key=provider item=value}'{$provider}': {if $value}true{else}false{/if}{/implode} }; + new WCF.Message.Share.Page({if SHARE_BUTTONS_SHOW_COUNT}true{else}false{/if}, $privacySettings); }); //]]> diff --git a/com.woltlab.wcf/templates/shareButtonsPrivacySettings.tpl b/com.woltlab.wcf/templates/shareButtonsPrivacySettings.tpl new file mode 100644 index 0000000000..97e138a1e7 --- /dev/null +++ b/com.woltlab.wcf/templates/shareButtonsPrivacySettings.tpl @@ -0,0 +1,25 @@ +
+ {lang}wcf.message.share.privacy{/lang} + {lang}wcf.message.share.privacy.description{/lang} + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
diff --git a/wcfsetup/install/files/js/WCF.Message.js b/wcfsetup/install/files/js/WCF.Message.js index 5128ef800b..1b3e56c274 100644 --- a/wcfsetup/install/files/js/WCF.Message.js +++ b/wcfsetup/install/files/js/WCF.Message.js @@ -2976,13 +2976,20 @@ WCF.Message.Share.Content = Class.extend({ * Provides buttons to share a page through multiple social community sites. * * @param boolean fetchObjectCount + * @param object privacySettings */ WCF.Message.Share.Page = Class.extend({ /** - * list of share buttons - * @var object + * dialog overlay + * @var jQuery + */ + _dialog: null, + + /** + * true if share count should be fetched + * @var boolean */ - _ui: { }, + _fetchObjectCount: false, /** * page description @@ -2996,72 +3003,228 @@ WCF.Message.Share.Page = Class.extend({ */ _pageURL: '', + /** + * list of privacy settings per social media site + */ + _privacySettings: { }, + + /** + * list of provider links and share callback + * @var object + */ + _provider: { }, + + /** + * action proxy + * @var WCF.Action.Proxy + */ + _proxy: null, + /** * Initializes the WCF.Message.Share.Page class. * * @param boolean fetchObjectCount + * @param object privacySettings */ - init: function(fetchObjectCount) { + init: function(fetchObjectCount, privacySettings) { + this._dialog = null; + this._fetchObjectCount = (fetchObjectCount === true) ? true : false; this._pageDescription = encodeURIComponent($('meta[property="og:title"]').prop('content')); this._pageURL = encodeURIComponent($('meta[property="og:url"]').prop('content')); + this._privacySettings = $.extend({ + facebook: false, + google: false, + twitter: false, + reddit: false + }, privacySettings || { }); + this._proxy = null; + this._initProvider(); + }, + + /** + * Initializes all social media providers. + */ + _initProvider: function() { var $container = $('.messageShareButtons'); - this._ui = { - facebook: $container.find('.jsShareFacebook'), - google: $container.find('.jsShareGoogle'), - reddit: $container.find('.jsShareReddit'), - twitter: $container.find('.jsShareTwitter') + var self = this; + this._provider = { + facebook: { + fetch: function() { self._fetchFacebook(); }, + link: $container.find('.jsShareFacebook'), + share: function() { self._share('facebook', 'https://www.facebook.com/sharer.php?u={pageURL}&t={text}', true); } + }, + google: { + fetch: undefined, + link: $container.find('.jsShareGoogle'), + share: function() { self._share('google', 'https://plus.google.com/share?url={pageURL}', true); } + }, + reddit: { + fetch: function() { self._fetchReddit(); }, + link:$container.find('.jsShareReddit'), + share: function() { self._share('reddit', 'https://ssl.reddit.com/submit?url={pageURL}', true); } + }, + twitter: { + fetch: function() { self._fetchTwitter(); }, + link: $container.find('.jsShareTwitter'), + share: function() { self._share('twitter', 'https://twitter.com/share?url={pageURL}&text={text}', false); } + } }; - this._ui.facebook.children('a').click($.proxy(this._shareFacebook, this)); - this._ui.google.children('a').click($.proxy(this._shareGoogle, this)); - this._ui.reddit.children('a').click($.proxy(this._shareReddit, this)); - this._ui.twitter.children('a').click($.proxy(this._shareTwitter, this)); + $.each(this._provider, function(provider, data) { + if (self._privacySettings[provider]) { + if (self._fetchObjectCount && data.fetch) { + data.fetch(); + } + } + else { + data.link.addClass('disabled'); + } + + data.link.data('provider', provider).click($.proxy(self._click, self)); + }); - if (fetchObjectCount === true) { - this._fetchFacebook(); - this._fetchTwitter(); - this._fetchReddit(); + if (WCF.User.userID) { + var $openSettings = $('
  • '); + $openSettings.appendTo($container.children('ul')).children('a').click($.proxy(this._openPrivacySettings, this)); } }, /** - * Shares current page to selected social community site. + * Handles clicks on a social media provider link. * - * @param string objectName - * @param string url - * @param boolean appendURL + * @param object event */ - _share: function(objectName, url, appendURL) { - window.open(url.replace(/{pageURL}/, this._pageURL).replace(/{text}/, this._pageDescription + (appendURL ? " " + this._pageURL : "")), 'height=600,width=600'); + _click: function(event) { + var $link = $(event.currentTarget); + var $provider = $link.data('provider'); + + if ($link.hasClass('disabled')) { + if (WCF.User.userID) { + this._openPrivacySettings(); + } + else { + // guest => enable button + $link.removeClass('disabled'); + } + } + else { + this._provider[$provider].share(); + } + }, + + /** + * Opens the privacy settings dialog. + */ + _openPrivacySettings: function() { + if (this._proxy === null) { + this._proxy = new WCF.Action.Proxy({ + success: $.proxy(this._success, this) + }); + } + + this._proxy.setOption('data', { + actionName: 'getSocialNetworkPrivacySettings', + className: 'wcf\\data\\user\\UserAction' + }); + this._proxy.sendRequest(); + }, + + /** + * Handles successful AJAX requests. + * + * @param object data + * @param string textStatus + * @param jQuery jqXHR + */ + _success: function(data, textStatus, jqXHR) { + switch (data.actionName) { + case 'getSocialNetworkPrivacySettings': + this._renderDialog(data); + break; + + case 'saveSocialNetworkPrivacySettings': + this._updatePrivacySettings(data); + break; + } }, /** - * Shares current page with Facebook. + * Renders the settings dialog. + * + * @param object data */ - _shareFacebook: function() { - this._share('facebook', 'https://www.facebook.com/sharer.php?u={pageURL}&t={text}', true); + _renderDialog: function(data) { + if (this._dialog === null) { + this._dialog = $('
    ').hide().appendTo(document.body); + this._dialog.html(data.returnValues.template); + this._dialog.wcfDialog({ + title: WCF.Language.get('wcf.message.share.privacy') + }); + } + else { + this._dialog.html(data.returnValues.template); + this._dialog.wcfDialog('open'); + } + + this._dialog.find('input[type=submit]').click($.proxy(this._save, this)); }, /** - * Shares current page with Google Plus. + * Saves settings. */ - _shareGoogle: function() { - this._share('google', 'https://plus.google.com/share?url={pageURL}', true); + _save: function() { + this._proxy.setOption('data', { + actionName: 'saveSocialNetworkPrivacySettings', + className: 'wcf\\data\\user\\UserAction', + parameters: { + facebook: (this._dialog.find('input[name=facebook]').is(':checked')), + google: (this._dialog.find('input[name=google]').is(':checked')), + reddit: (this._dialog.find('input[name=reddit]').is(':checked')), + twitter: (this._dialog.find('input[name=twitter]').is(':checked')) + } + }); + this._proxy.sendRequest(); + + this._dialog.wcfDialog('close'); }, /** - * Shares current page with Reddit. + * Updates the internal privacy settings. + * + * @param object data */ - _shareReddit: function() { - this._share('reddit', 'https://ssl.reddit.com/submit?url={pageURL}', true); + _updatePrivacySettings: function(data) { + this._privacySettings = $.extend(this._privacySettings, data.returnValues.settings); + + var self = this; + $.each(data.returnValues.settings, function(provider, status) { + self._privacySettings[provider] = (status) ? true : false; + + if (status) { + self._provider[provider].link.removeClass('disabled'); + + if (self._fetchObjectCount && self._provider[provider].fetch) { + self._provider[provider].fetch(); + } + } + else { + self._provider[provider].link.addClass('disabled'); + } + }); + + new WCF.System.Notification().show(); }, /** - * Shares current page with Twitter. + * Shares current page to selected social community site. + * + * @param string objectName + * @param string url + * @param boolean appendURL */ - _shareTwitter: function() { - this._share('twitter', 'https://twitter.com/share?url={pageURL}&text={text}', false); + _share: function(objectName, url, appendURL) { + window.open(url.replace(/{pageURL}/, this._pageURL).replace(/{text}/, this._pageDescription + (appendURL ? " " + this._pageURL : "")), 'height=600,width=600'); }, /** @@ -3094,7 +3257,7 @@ WCF.Message.Share.Page = Class.extend({ _fetchFacebook: function() { this._fetchCount('https://graph.facebook.com/?id={pageURL}', $.proxy(function(data) { if (data.shares) { - this._ui.facebook.children('span.badge').show().text(data.shares); + this._provider.facebook.link.children('span.badge').show().text(data.shares); } }, this)); }, @@ -3107,7 +3270,7 @@ WCF.Message.Share.Page = Class.extend({ this._fetchCount('http://urls.api.twitter.com/1/urls/count.json?url={pageURL}', $.proxy(function(data) { if (data.count) { - this._ui.twitter.children('span.badge').show().text(data.count); + this._provider.twitter.link.children('span.badge').show().text(data.count); } }, this)); }, @@ -3120,7 +3283,7 @@ WCF.Message.Share.Page = Class.extend({ this._fetchCount('http://www.reddit.com/api/info.json?url={pageURL}', $.proxy(function(data) { if (data.data.children.length) { - this._ui.reddit.children('span.badge').show().text(data.data.children[0].data.score); + this._provider.reddit.link.children('span.badge').show().text(data.data.children[0].data.score); } }, this), 'jsonp'); } diff --git a/wcfsetup/install/files/lib/data/user/User.class.php b/wcfsetup/install/files/lib/data/user/User.class.php index 6d3a69be8e..6a0fe802a2 100644 --- a/wcfsetup/install/files/lib/data/user/User.class.php +++ b/wcfsetup/install/files/lib/data/user/User.class.php @@ -463,4 +463,22 @@ final class User extends DatabaseObject implements IRouteController, IUserConten 'forceFrontend' => true )); } + + public function getSocialNetworkPrivacySettings() { + $settings = false; + if ($this->userID && WCF::getUser()->socialNetworkPrivacySettings) { + $settings = @unserialize(WCF::getUser()->socialNetworkPrivacySettings); + } + + if ($settings === false) { + $settings = array( + 'facebook' => false, + 'google' => false, + 'reddit' => false, + 'twitter' => false + ); + } + + return $settings; + } } diff --git a/wcfsetup/install/files/lib/data/user/UserAction.class.php b/wcfsetup/install/files/lib/data/user/UserAction.class.php index c0cc84c35b..b46b66804e 100644 --- a/wcfsetup/install/files/lib/data/user/UserAction.class.php +++ b/wcfsetup/install/files/lib/data/user/UserAction.class.php @@ -16,6 +16,8 @@ use wcf\system\mail\Mail; use wcf\system\request\RequestHandler; use wcf\system\WCF; use wcf\util\UserRegistrationUtil; +use wcf\util\JSON; +use wcf\system\exception\SystemException; /** * Executes user-related actions. @@ -744,4 +746,59 @@ class UserAction extends AbstractDatabaseObjectAction implements IClipboardActio )); } } + + /** + * Validates parameters to retrieve the social network privacy settings. + */ + public function validateGetSocialNetworkPrivacySettings() { /* does nothing */ } + + /** + * Returns the social network privacy settings. + * + * @return array + */ + public function getSocialNetworkPrivacySettings() { + $settings = @unserialize(WCF::getUser()->socialNetworkPrivacySettings); + if (!is_array($settings)) { + $settings = array( + 'facebook' => false, + 'google' => false, + 'reddit' => false, + 'twitter' => false + ); + } + + WCF::getTPL()->assign(array( + 'settings' => $settings + )); + + return array( + 'template' => WCF::getTPL()->fetch('shareButtonsPrivacySettings') + ); + } + + public function validateSaveSocialNetworkPrivacySettings() { + $this->readBoolean('facebook', true); + $this->readBoolean('google', true); + $this->readBoolean('reddit', true); + $this->readBoolean('twitter', true); + } + + public function saveSocialNetworkPrivacySettings() { + $settings = array( + 'facebook' => $this->parameters['facebook'], + 'google' => $this->parameters['google'], + 'reddit' => $this->parameters['reddit'], + 'twitter' => $this->parameters['twitter'] + ); + + $userEditor = new UserEditor(WCF::getUser()); + $userEditor->update(array( + 'socialNetworkPrivacySettings' => serialize($settings) + )); + + return array( + 'settings' => $settings + ); + } } diff --git a/wcfsetup/install/files/style/message.less b/wcfsetup/install/files/style/message.less index 7ff9317bc7..da8066cfeb 100644 --- a/wcfsetup/install/files/style/message.less +++ b/wcfsetup/install/files/style/message.less @@ -891,34 +891,27 @@ li:nth-child(2n+1) .message { } } - .jsShareFacebook { + .jsShareFacebook:not(.disabled) { > a > .icon { color: rgb(59, 89, 152); } } - .jsShareTwitter { + .jsShareTwitter:not(.disabled) { > a > .icon { color: rgb(64, 153, 255); } } - .jsShareGoogle { + .jsShareGoogle:not(.disabled) { > a > .icon { color: rgb(211, 72, 54); } } - .jsShareReddit { - > a > img { - width: 24px; - height: 24px; - margin: 0 4px 4px; - box-shadow: 0 1px 0 rgba(255, 255, 255, .8); - border-radius: 3px; - - /* smooth fixes */ - background-color: rgba(255, 255, 255, .8); + .jsShareReddit:not(.disabled) { + > a > .icon { + color: rgb(95, 153, 207); } } } diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index e878c771d8..daf77c55a6 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -2166,6 +2166,8 @@ Fehler sind beispielsweise: + + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 01c8cbcbb6..71c87749e3 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -2134,6 +2134,8 @@ Errors are: + + diff --git a/wcfsetup/setup/db/install.sql b/wcfsetup/setup/db/install.sql index 9075e2585a..2b285a5f17 100644 --- a/wcfsetup/setup/db/install.sql +++ b/wcfsetup/setup/db/install.sql @@ -1091,6 +1091,7 @@ CREATE TABLE wcf1_user ( notificationMailToken VARCHAR(20) NOT NULL DEFAULT '', authData VARCHAR(255) NOT NULL DEFAULT '', likesReceived MEDIUMINT(7) NOT NULL DEFAULT 0, + socialNetworkPrivacySettings TEXT, KEY username (username), KEY registrationDate (registrationDate), -- 2.20.1