EBernhardson has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/384180 )
Change subject: Add opt out to relevance survey ...................................................................... Add opt out to relevance survey * Opt-out for anonymous users is tracked in local storage, so is only handled on a best-effort basis. * Opt-out for logged in users is tracked in the mediawiki user options so should be a strong guarantee. Bug: T176428 Change-Id: Ic08d0362ea26beb2e1e6d996e4b48c46a14d9d15 --- M extension.json M i18n/en.json M i18n/qqq.json M includes/ApiRelevanceSurvey.php M modules/ext.wikimediaEvents.humanSearchRelevance.css M modules/ext.wikimediaEvents.humanSearchRelevance.js 6 files changed, 83 insertions(+), 10 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/WikimediaEvents refs/changes/80/384180/1 diff --git a/extension.json b/extension.json index 37bd3bf..290382b 100644 --- a/extension.json +++ b/extension.json @@ -19,7 +19,8 @@ "relevancesurvey": "MediaWiki\\WikimediaEvents\\ApiRelevanceSurvey" }, "DefaultUserOptions": { - "wme-relevance-filter": "" + "wme-relevance-filter": "", + "wme-relevance-optout": false }, "Hooks": { "BeforeInitialize": [ @@ -166,7 +167,7 @@ "schema.HumanSearchRelevance": { "class": "ResourceLoaderSchemaModule", "schema": "HumanSearchRelevance", - "revision": 17320055 + "revision": 17322925 }, "ext.wikimediaEvents": { "scripts": [ @@ -217,7 +218,8 @@ "wikimediaevents-humanrel-no", "wikimediaevents-humanrel-unsure", "wikimediaevents-humanrel-why", - "wikimediaevents-humanrel-privacy-statement" + "wikimediaevents-humanrel-privacy-statement", + "wikimediaevents-humanrel-opt-out" ], "styles": [ "ext.wikimediaEvents.humanSearchRelevance.css" diff --git a/i18n/en.json b/i18n/en.json index 1916a3d..eddd96b 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -19,5 +19,6 @@ "wikimediaevents-humanrel-no": "No", "wikimediaevents-humanrel-unsure": "I don't know", "wikimediaevents-humanrel-why": "Why we are asking this?", - "wikimediaevents-humanrel-privacy-statement": "Privacy Statement" + "wikimediaevents-humanrel-privacy-statement": "Privacy Statement", + "wikimediaevents-humanrel-opt-out": "Opt out of survey" } diff --git a/i18n/qqq.json b/i18n/qqq.json index 05fd94e..b3d5488 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -22,5 +22,6 @@ "wikimediaevents-humanrel-no": "Negative answer to articles relevance to a search query.\n\nAppears with the question: {{msg-mw|wikimediaevents-humanrel-question-c}}\n\n{{Identical|No}}", "wikimediaevents-humanrel-unsure": "Indecisive answer to articles relevance to a search query.\n\nSee also: {{msg-mw|wikimediaevents-humanrel-question-c}}, {{msg-mw|wikimediaevents-humanrel-yes}}, {{msg-mw|wikimediaevents-humanrel-no}}", "wikimediaevents-humanrel-why": "Link text to wiki page describing the purpose of the survey.", - "wikimediaevents-humanrel-privacy-statement": "Text for link to the survey privacy statement." + "wikimediaevents-humanrel-privacy-statement": "Text for link to the survey privacy statement.", + "wikimediaevents-humanrel-opt-out": "Text for link to opt out (never see again) the search relevance survey." } diff --git a/includes/ApiRelevanceSurvey.php b/includes/ApiRelevanceSurvey.php index 48b7424..c547732 100644 --- a/includes/ApiRelevanceSurvey.php +++ b/includes/ApiRelevanceSurvey.php @@ -4,12 +4,16 @@ use ApiBase; use InvalidArgumentException; +use MediaWiki\Logger\LoggerFactory; +use MWException; use Title; use User; class ApiRelevanceSurvey extends ApiBase { // User option that stores the per-user bloom filter const USER_OPTION_FILTER = 'wme-relevance-filter'; + // User option to opt out of surveys + const USER_OPTION_OPTOUT = 'wme-relevance-optout'; // A bloom filter with 180 bytes and 6 hashes gives a false positive rate // of 0.01% at 58 items, 1% at 150 items, and 10% at 275 items. @@ -18,6 +22,29 @@ public function execute() { $params = $this->extractRequestParams(); + + $user = $this->getUser(); + if ( $params['optout'] ) { + if ( $user->isAnon() ) { + $this->dieWithError( 'apierror-musbeloggedin-generic' ); + } + // There is a small possibility of CAS errors if multiple requests + // are trying to change user options. Make the window as small as + // possible since the user would really prefer we not forget about + // their opt out preference. + $user = User::newFromId( $user->getId() ); + $user->load( User::READ_LATEST ); + $user->setOption( self::USER_OPTION_OPTOUT, '1' ); + $user->saveSettings(); + $this->applyResult( false ); + return; + } + + if ( $user->getOption( self::USER_OPTION_OPTOUT ) ) { + $this->applyResult( false ); + return; + } + $title = Title::newFromText( $params['title'] ); if ( !$title ) { $this->dieWithError( [ 'apierror-invalidtitle', $params['title'] ] ); @@ -101,6 +128,9 @@ ApiBase::PARAM_TYPE => 'string', ApiBase::PARAM_REQUIRED => true, ], + 'optout' => [ + ApiBase::PARAM_TYPE => 'boolean', + ], ]; } } diff --git a/modules/ext.wikimediaEvents.humanSearchRelevance.css b/modules/ext.wikimediaEvents.humanSearchRelevance.css index 1e9b8fb..1f670b0 100644 --- a/modules/ext.wikimediaEvents.humanSearchRelevance.css +++ b/modules/ext.wikimediaEvents.humanSearchRelevance.css @@ -22,3 +22,10 @@ /* Force the first footer anchor onto it's own line */ display: block; } + +/* Center the buttons and footer */ +.mw-wme-humanrel-question > .oo-ui-buttonGroupWidget, +.mw-wme-humanrel-question > .footer { + text-align: center; + width: 100%; +} diff --git a/modules/ext.wikimediaEvents.humanSearchRelevance.js b/modules/ext.wikimediaEvents.humanSearchRelevance.js index 8bdb789..14f043d 100644 --- a/modules/ext.wikimediaEvents.humanSearchRelevance.js +++ b/modules/ext.wikimediaEvents.humanSearchRelevance.js @@ -1,6 +1,9 @@ ( function ( mw, $ ) { 'use strict'; + var sampleRate, + optOutKey = 'wme-humrel-optout'; + function sample( acceptPercentage ) { var rand = mw.user.generateRandomSessionId(), // take the first 52 bits of the rand value to match js @@ -30,11 +33,24 @@ // The config value is coded into the page output and cached in varnish. // That means any changes to sampling rates or pages chosen will take up to // a week to propogate into the wild unless explicitly purged. - var sampleRate = mw.config.get( 'wgWMESearchRelevancePages' ); + sampleRate = mw.config.get( 'wgWMESearchRelevancePages' ); // This page view not chosen for sampling if ( !sample( sampleRate ) ) { return; + } + + function applyOptOut() { + if ( mw.user.isAnon() ) { + // best we can do for anon users. + mw.storage.set( optOutKey, '1' ); + } else { + new mw.Api().post( { + action: 'relevancesurvey', + title: mw.config.get( 'wgTitle' ), + optout: true + } ); + } } function canAskQuestion() { @@ -42,11 +58,17 @@ timeout = mw.storage.get( timeoutKey ), now = Date.now(); + // User has previously opted out + if ( mw.storage.get( optOutKey ) ) { + return false; + } + // Don't show the survey to same browser for 2 days, to prevent annoying users if ( timeout && timeout > now ) { // User has seen the survey recently return false; } + // If we can't record that the survey shouldn't be duplicated, just // opt them out of the survey all together. if ( !mw.storage.set( timeoutKey, now + 2 * 86400000 ) ) { @@ -77,7 +99,12 @@ $( '<a>', { href: '//wikimediafoundation.org/wiki/Search_Relevance_Survey_Privacy_Statement', target: '_blank' - } ).text( mw.message( 'wikimediaevents-humanrel-privacy-statement' ) ) + } ).text( mw.message( 'wikimediaevents-humanrel-privacy-statement' ) ), + // TODO: Could be done with css instead i suppose? + document.createTextNode( ' | ' ), + $( '<a>' ) + .text( mw.message( 'wikimediaevents-humanrel-opt-out' ) ) + .on( 'click', function () { onClick( 'optout' ); } ) ); return $( '<p>' ).attr( { @@ -106,7 +133,12 @@ } ); } ); }, - content = buildContent( query, logEvent ); + content = buildContent( query, function ( clicked ) { + if ( clicked === 'optout' ) { + applyOptOut(); + } + logEvent( clicked ); + } ); // we need a longer timeout than notification provides manually, // so create our out key. While at it extend the timeout from @@ -131,7 +163,8 @@ return originalClose(); }; - // Prevent clicks in footer from closing notification. + // Prevent clicks in footer from closing notification. Opt-out will + // close the notification directly. content.find( '.footer' ).on( 'click', function ( event ) { event.stopPropagation(); // These clicks open some external page in a new tab, restart the @@ -175,5 +208,4 @@ } ); // When debugging show the survey immediately }, mw.Debug ? 0 : 60000 ); - }( mediaWiki, jQuery ) ); -- To view, visit https://gerrit.wikimedia.org/r/384180 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic08d0362ea26beb2e1e6d996e4b48c46a14d9d15 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/WikimediaEvents Gerrit-Branch: master Gerrit-Owner: EBernhardson <ebernhard...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits