From 7bf742966fe14175d7680dd74d3ce18b4705ce4b Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Sat, 12 Aug 2023 20:18:21 +0200 Subject: [PATCH 01/22] fix: Fix dispatching server side jobs --- extension.json | 18 +++++++++--------- includes/PlausibleEventJob.php | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/extension.json b/extension.json index c15b72b..b10d089 100644 --- a/extension.json +++ b/extension.json @@ -160,17 +160,17 @@ }, "Hooks": { "BeforePageDisplay": "PageHooks", - "PageSaveCompleteHook": "PageHooks", - "ArticleDeleteAfterSuccessHook": "PageHooks", + "PageSaveComplete": "PageHooks", + "ArticleDeleteAfterSuccess": "PageHooks", "ParserFirstCallInit": "ParserHooks", "MediaWikiServices": "MediaWikiServices", - "LocalUserCreatedHook": "UserHooks", - "UserLogoutCompleteHook": "UserHooks", - "UserLoginCompleteHook": "UserHooks", - "UploadCompleteHook": "FileHooks", - "FileDeleteCompleteHook": "FileHooks", - "SpecialSearchNogomatchHook": "SearchHooks", - "SpecialSearchGoResultHook": "SearchHooks", + "LocalUserCreated": "UserHooks", + "UserLogoutComplete": "UserHooks", + "UserLoginComplete": "UserHooks", + "UploadComplete": "FileHooks", + "FileDeleteComplete": "FileHooks", + "SpecialSearchNogomatch": "SearchHooks", + "SpecialSearchGoResult": "SearchHooks", "ScribuntoExternalLibraries": "MediaWiki\\Extension\\Plausible\\Hooks\\ScribuntoHooks::onScribuntoExternalLibraries" }, "ResourceModules": { diff --git a/includes/PlausibleEventJob.php b/includes/PlausibleEventJob.php index 209d65a..17ee1cf 100644 --- a/includes/PlausibleEventJob.php +++ b/includes/PlausibleEventJob.php @@ -12,7 +12,7 @@ class PlausibleEventJob extends Job implements GenericParameterJob { public function __construct( array $params ) { - parent::__construct( null, $params ); + parent::__construct( 'PlausibleEvent', $params ); } /** From e81413ddf406df68baeadf418221419074817bcd Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Sat, 12 Aug 2023 20:42:37 +0200 Subject: [PATCH 02/22] fix: Fix server side events --- includes/Hooks/FileHooks.php | 6 +++--- includes/Hooks/MediaWikiServices.php | 2 +- includes/Hooks/PageHooks.php | 8 ++++---- includes/Hooks/ParserHooks.php | 2 +- includes/Hooks/SearchHooks.php | 4 ++-- includes/Hooks/UserHooks.php | 6 +++--- includes/PlausibleEventJob.php | 8 +++++--- 7 files changed, 19 insertions(+), 17 deletions(-) diff --git a/includes/Hooks/FileHooks.php b/includes/Hooks/FileHooks.php index 6a71f24..ac908ae 100644 --- a/includes/Hooks/FileHooks.php +++ b/includes/Hooks/FileHooks.php @@ -23,7 +23,7 @@ public function __construct( Config $config, JobQueueGroup $group ) { /** * @inheritDoc */ - public function onFileDeleteComplete( $file, $oldimage, $article, $user, $reason ) { + public function onFileDeleteComplete( $file, $oldimage, $article, $user, $reason ): void { if ( !$this->config['filedelete'] ) { return; } @@ -34,7 +34,7 @@ public function onFileDeleteComplete( $file, $oldimage, $article, $user, $reason /** * @inheritDoc */ - public function onUploadComplete( $uploadBase ) { + public function onUploadComplete( $uploadBase ): void { if ( !$this->config['fileupload'] ) { return; } @@ -45,7 +45,7 @@ public function onUploadComplete( $uploadBase ) { /** * @inheritDoc */ - public function onFileUndeleteComplete( $title, $fileVersions, $user, $reason ) { + public function onFileUndeleteComplete( $title, $fileVersions, $user, $reason ): void { if ( !$this->config['fileundelete'] ) { return; } diff --git a/includes/Hooks/MediaWikiServices.php b/includes/Hooks/MediaWikiServices.php index 6f6c806..94c335c 100644 --- a/includes/Hooks/MediaWikiServices.php +++ b/includes/Hooks/MediaWikiServices.php @@ -14,7 +14,7 @@ class MediaWikiServices implements MediaWikiServicesHook { /** * @inheritDoc */ - public function onMediaWikiServices( $services ) { + public function onMediaWikiServices( $services ): void { if ( !ExtensionRegistry::getInstance()->isLoaded( 'PageViewInfo' ) ) { return; } diff --git a/includes/Hooks/PageHooks.php b/includes/Hooks/PageHooks.php index 0924898..f038c31 100644 --- a/includes/Hooks/PageHooks.php +++ b/includes/Hooks/PageHooks.php @@ -76,7 +76,7 @@ public function onBeforePageDisplay( $out, $skin ): void { /** * @inheritDoc */ - public function onArticleDeleteAfterSuccess( $title, $outputPage ) { + public function onArticleDeleteAfterSuccess( $title, $outputPage ): void { if ( !$this->config['pagedelete'] ) { return; } @@ -87,7 +87,7 @@ public function onArticleDeleteAfterSuccess( $title, $outputPage ) { /** * @inheritDoc */ - public function onPageSaveComplete( $wikiPage, $user, $summary, $flags, $revisionRecord, $editResult ) { + public function onPageSaveComplete( $wikiPage, $user, $summary, $flags, $revisionRecord, $editResult ): void { if ( !$this->config['pageedit'] || $editResult->isNullEdit() ) { return; } @@ -98,7 +98,7 @@ public function onPageSaveComplete( $wikiPage, $user, $summary, $flags, $revisio /** * @inheritDoc */ - public function onArticleUndelete( $title, $create, $comment, $oldPageId, $restoredPages ) { + public function onArticleUndelete( $title, $create, $comment, $oldPageId, $restoredPages ): void { if ( !$this->config['pageundelete'] ) { return; } @@ -109,7 +109,7 @@ public function onArticleUndelete( $title, $create, $comment, $oldPageId, $resto /** * @inheritDoc */ - public function onPageMoveComplete( $old, $new, $user, $pageid, $redirid, $reason, $revision ) { + public function onPageMoveComplete( $old, $new, $user, $pageid, $redirid, $reason, $revision ): void { if ( !$this->config['pagemove'] ) { return; } diff --git a/includes/Hooks/ParserHooks.php b/includes/Hooks/ParserHooks.php index f8310eb..e261d4a 100644 --- a/includes/Hooks/ParserHooks.php +++ b/includes/Hooks/ParserHooks.php @@ -12,7 +12,7 @@ class ParserHooks implements ParserFirstCallInitHook { /** * @inheritDoc */ - public function onParserFirstCallInit( $parser ) { + public function onParserFirstCallInit( $parser ): void { $config = MediaWikiServices::getInstance()->getConfigFactory()->makeConfig( 'Plausible' ); if ( $config->get( 'PlausibleEnableOptOutTag' ) === false ) { return; diff --git a/includes/Hooks/SearchHooks.php b/includes/Hooks/SearchHooks.php index c3c6d80..656d96c 100644 --- a/includes/Hooks/SearchHooks.php +++ b/includes/Hooks/SearchHooks.php @@ -22,7 +22,7 @@ public function __construct( Config $config, JobQueueGroup $group ) { /** * @inheritDoc */ - public function onSpecialSearchNogomatch( &$title ) { + public function onSpecialSearchNogomatch( &$title ): void { if ( !$this->config['searchnotfound'] ) { return; } @@ -39,7 +39,7 @@ public function onSpecialSearchNogomatch( &$title ) { /** * @inheritDoc */ - public function onSpecialSearchGoResult( $term, $title, &$url ) { + public function onSpecialSearchGoResult( $term, $title, &$url ): void { if ( !$this->config['searchfound'] ) { return; } diff --git a/includes/Hooks/UserHooks.php b/includes/Hooks/UserHooks.php index 61b3e19..63febae 100644 --- a/includes/Hooks/UserHooks.php +++ b/includes/Hooks/UserHooks.php @@ -22,7 +22,7 @@ public function __construct( Config $config, JobQueueGroup $group ) { /** * @inheritDoc */ - public function onLocalUserCreated( $user, $autocreated ) { + public function onLocalUserCreated( $user, $autocreated ): void { if ( !$this->config['userregister'] ) { return; } @@ -39,7 +39,7 @@ public function onLocalUserCreated( $user, $autocreated ) { /** * @inheritDoc */ - public function onUserLoginComplete( $user, &$inject_html, $direct ) { + public function onUserLoginComplete( $user, &$inject_html, $direct ): void { if ( !$this->config['userlogin'] ) { return; } @@ -56,7 +56,7 @@ public function onUserLoginComplete( $user, &$inject_html, $direct ) { /** * @inheritDoc */ - public function onUserLogoutComplete( $user, &$inject_html, $oldName ) { + public function onUserLogoutComplete( $user, &$inject_html, $oldName ): void { if ( !$this->config['userlogout'] ) { return; } diff --git a/includes/PlausibleEventJob.php b/includes/PlausibleEventJob.php index 17ee1cf..9bbd26f 100644 --- a/includes/PlausibleEventJob.php +++ b/includes/PlausibleEventJob.php @@ -10,6 +10,7 @@ use WebRequest; class PlausibleEventJob extends Job implements GenericParameterJob { + protected $removeDuplicates = true; public function __construct( array $params ) { parent::__construct( 'PlausibleEvent', $params ); @@ -19,7 +20,7 @@ public function __construct( array $params ) { * @inheritDoc */ public function run(): bool { - if ( !empty( $this->params['url'] ) || !is_string( $this->params['agent'] ) ) { + if ( empty( $this->params['url'] ) || empty( $this->params['agent'] ) ) { return false; } @@ -28,10 +29,11 @@ public function run(): bool { $request = MediaWikiServices::getInstance()->getHttpRequestFactory()->create( sprintf( '%s/api/event', $config->get( 'PlausibleDomain' ) ), [ + 'method' => 'POST', 'userAgent' => $this->params['agent'], 'postData' => [ 'domain' => $config->get( 'PlausibleDomainKey' ), - 'name' => 'pageview', + 'name' => $this->params['event'], 'url' => $this->params['url'], 'props' => $this->params['props'] ?? [], ], @@ -59,7 +61,7 @@ public static function newFromRequest( WebRequest $request, string $event = 'pag return new self( [ 'event' => $event, 'ip' => $request->getIP(), - 'url' => $request->getRequestURL(), + 'url' => $request->getFullRequestURL(), 'agent' => $request->getHeader( 'User-Agent' ), 'props' => $props, ] ); From 0ffef7bf7b114bb7a5b491a071dcf5cc42af7e44 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Sat, 12 Aug 2023 21:07:57 +0200 Subject: [PATCH 03/22] fix: Fix server side events --- includes/Hooks/PageHooks.php | 9 ++++++++- includes/PlausibleEventJob.php | 13 ++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/includes/Hooks/PageHooks.php b/includes/Hooks/PageHooks.php index f038c31..2cc02bb 100644 --- a/includes/Hooks/PageHooks.php +++ b/includes/Hooks/PageHooks.php @@ -92,7 +92,14 @@ public function onPageSaveComplete( $wikiPage, $user, $summary, $flags, $revisio return; } - $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), 'pageedit' ) ); + $this->jobs->push( PlausibleEventJob::newFromRequest( + $user->getRequest(), + 'pageedit', + [ + 'title' => $wikiPage->getTitle()->getText(), + 'user' => $user->isRegistered() ? $user->getName() : null, + ] + ) ); } /** diff --git a/includes/PlausibleEventJob.php b/includes/PlausibleEventJob.php index 9bbd26f..b53b8f6 100644 --- a/includes/PlausibleEventJob.php +++ b/includes/PlausibleEventJob.php @@ -6,6 +6,7 @@ use GenericParameterJob; use Job; use MediaWiki\MediaWikiServices; +use MediaWiki\Title\Title; use NullJob; use WebRequest; @@ -31,12 +32,12 @@ public function run(): bool { [ 'method' => 'POST', 'userAgent' => $this->params['agent'], - 'postData' => [ + 'postData' => json_encode( [ 'domain' => $config->get( 'PlausibleDomainKey' ), 'name' => $this->params['event'], 'url' => $this->params['url'], 'props' => $this->params['props'] ?? [], - ], + ], JSON_THROW_ON_ERROR ), ] ); @@ -58,10 +59,16 @@ public function run(): bool { */ public static function newFromRequest( WebRequest $request, string $event = 'pageview', array $props = [] ): Job { try { + $url = $request->getFullRequestURL(); + if ( isset( $props['title'] ) ) { + $url = ( Title::newFromText( $props['title'] ) )->getFullURL(); + unset( $props['title'] ); + } + return new self( [ 'event' => $event, 'ip' => $request->getIP(), - 'url' => $request->getFullRequestURL(), + 'url' => $url, 'agent' => $request->getHeader( 'User-Agent' ), 'props' => $props, ] ); From 787c4768cda32b9b578a9d096e884a04faff4718 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Sat, 12 Aug 2023 23:31:56 +0200 Subject: [PATCH 04/22] refactor: Change title to term for non found searches --- includes/Hooks/SearchHooks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Hooks/SearchHooks.php b/includes/Hooks/SearchHooks.php index 656d96c..41b8fb0 100644 --- a/includes/Hooks/SearchHooks.php +++ b/includes/Hooks/SearchHooks.php @@ -31,7 +31,7 @@ public function onSpecialSearchNogomatch( &$title ): void { RequestContext::getMain()->getRequest(), 'searchnotfound', [ - 'title' => $title->getText(), + 'term' => $title->getText(), ] ) ); } From d67b90718256c012c888098114b770babb4f9d4c Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Tue, 15 Aug 2023 12:45:55 +0200 Subject: [PATCH 05/22] refactor: Honor PlausibleTrackLoggedIn for server events --- includes/PlausibleEventJob.php | 39 ++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/includes/PlausibleEventJob.php b/includes/PlausibleEventJob.php index b53b8f6..e4c5e55 100644 --- a/includes/PlausibleEventJob.php +++ b/includes/PlausibleEventJob.php @@ -1,10 +1,14 @@ getMainConfig(); - $request = MediaWikiServices::getInstance()->getHttpRequestFactory()->create( - sprintf( '%s/api/event', $config->get( 'PlausibleDomain' ) ), - [ - 'method' => 'POST', - 'userAgent' => $this->params['agent'], - 'postData' => json_encode( [ - 'domain' => $config->get( 'PlausibleDomainKey' ), - 'name' => $this->params['event'], - 'url' => $this->params['url'], - 'props' => $this->params['props'] ?? [], - ], JSON_THROW_ON_ERROR ), - ] - ); + try { + if ( !$config->get( 'PlausibleTrackLoggedIn' ) && ( $this->params['isRegistered'] ?? false ) === true ) { + return true; + } + + $request = MediaWikiServices::getInstance()->getHttpRequestFactory()->create( + sprintf( '%s/api/event', $config->get( 'PlausibleDomain' ) ), + [ + 'method' => 'POST', + 'userAgent' => $this->params['agent'], + 'postData' => json_encode( [ + 'domain' => $config->get( 'PlausibleDomainKey' ), + 'name' => $this->params['event'], + 'url' => $this->params['url'], + 'props' => $this->params['props'] ?? [], + ], JSON_THROW_ON_ERROR ), + ] + ); + } catch ( JsonException | ConfigException $e ) { + return false; + } $request->setHeader( 'Content-Type', 'application/json' ); $request->setHeader( 'X-Forwarded-For', $this->params['ip'] ); @@ -71,6 +83,7 @@ public static function newFromRequest( WebRequest $request, string $event = 'pag 'url' => $url, 'agent' => $request->getHeader( 'User-Agent' ), 'props' => $props, + 'isRegistered' => $request->getSession()->getUser()->isRegistered(), ] ); } catch ( Exception $e ) { return new NullJob( [ 'removeDuplicates' => true ] ); From 88ef9ce76a652ae259f920799a79551f4a5a6ab5 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Tue, 15 Aug 2023 12:49:10 +0200 Subject: [PATCH 06/22] refactor: Raise required php version to >=8.0 --- composer.json | 2 +- extension.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 65a44a0..c7d5b09 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ } ], "require": { - "php": ">=7.2", + "php": ">=8.0", "ext-json": "*", "composer/installers": ">=1.0.1" }, diff --git a/extension.json b/extension.json index f79a3c2..2656585 100644 --- a/extension.json +++ b/extension.json @@ -11,7 +11,7 @@ "requires": { "MediaWiki": ">= 1.39.0", "platform": { - "php": ">=7.3.19" + "php": ">=8.0" } }, "config": { From 44c74ab66999740dbdb3145de67e587b13ed8f5d Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Thu, 17 Aug 2023 10:09:36 +0200 Subject: [PATCH 07/22] breaking: Change property names Update: - `path` -> `title` - `query` -> `term` Addition: - `isAnon` true for anonymous users, and false for registered --- includes/PlausibleEventJob.php | 8 +++++--- .../track-menu-links.js | 6 ++++-- .../track-search-links.js | 6 ++++-- resources/ext.plausible.scripts.track-404/track-404.js | 6 ++++-- .../track-edit-btn.js | 6 ++++-- .../track-infobox-clicks.js | 9 ++++++--- .../track-navplate-clicks.js | 6 ++++-- .../ext.plausible.scripts.track-search/track-search.js | 6 ++++-- .../track-special-search.js | 6 ++++-- 9 files changed, 39 insertions(+), 20 deletions(-) diff --git a/includes/PlausibleEventJob.php b/includes/PlausibleEventJob.php index e4c5e55..db80c44 100644 --- a/includes/PlausibleEventJob.php +++ b/includes/PlausibleEventJob.php @@ -1,6 +1,6 @@ getMainConfig(); try { - if ( !$config->get( 'PlausibleTrackLoggedIn' ) && ( $this->params['isRegistered'] ?? false ) === true ) { + if ( !$config->get( 'PlausibleTrackLoggedIn' ) && ( $this->params['isAnon'] ?? true ) === false ) { return true; } + $this->params['props']['isAnon'] = $this->params['isAnon']; + $request = MediaWikiServices::getInstance()->getHttpRequestFactory()->create( sprintf( '%s/api/event', $config->get( 'PlausibleDomain' ) ), [ @@ -83,7 +85,7 @@ public static function newFromRequest( WebRequest $request, string $event = 'pag 'url' => $url, 'agent' => $request->getHeader( 'User-Agent' ), 'props' => $props, - 'isRegistered' => $request->getSession()->getUser()->isRegistered(), + 'isAnon' => $request->getSession()->getUser()->isAnon(), ] ); } catch ( Exception $e ) { return new NullJob( [ 'removeDuplicates' => true ] ); diff --git a/resources/ext.plausible.scripts.citizen.track-menu-links/track-menu-links.js b/resources/ext.plausible.scripts.citizen.track-menu-links/track-menu-links.js index a057e31..9cf0e69 100644 --- a/resources/ext.plausible.scripts.citizen.track-menu-links/track-menu-links.js +++ b/resources/ext.plausible.scripts.citizen.track-menu-links/track-menu-links.js @@ -1,6 +1,7 @@ // Menu Link click Tracking ( function () { - var eventName = 'CitizenMenuLinkClick'; + var eventName = 'CitizenMenuLinkClick', + isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\'; if ( typeof window.plausible === 'undefined' || window.plausible.length === 0 ) { return; @@ -15,7 +16,8 @@ window.plausible( eventName, { props: { entry: event.target.innerText, - path: event.target.href + title: event.target.href, + isAnon, }, callback: function () { window.location = event.target.href; diff --git a/resources/ext.plausible.scripts.citizen.track-search-links/track-search-links.js b/resources/ext.plausible.scripts.citizen.track-search-links/track-search-links.js index 8884aa0..94e3e63 100644 --- a/resources/ext.plausible.scripts.citizen.track-search-links/track-search-links.js +++ b/resources/ext.plausible.scripts.citizen.track-search-links/track-search-links.js @@ -3,6 +3,7 @@ var eventName = 'CitizenSearchLinkClick', suggestions = document.getElementById( 'searchform' ), search = document.getElementById( 'searchInput' ), + isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\', callback = function ( event ) { var currentEl, href = null, @@ -38,8 +39,9 @@ window.plausible( eventName, { props: { - query: searchValue, - path: url.pathname + term: searchValue, + title: url.pathname, + isAnon, }, callback: function () { window.location = href; diff --git a/resources/ext.plausible.scripts.track-404/track-404.js b/resources/ext.plausible.scripts.track-404/track-404.js index 9d6c7ac..019954a 100644 --- a/resources/ext.plausible.scripts.track-404/track-404.js +++ b/resources/ext.plausible.scripts.track-404/track-404.js @@ -1,6 +1,7 @@ // 404 page Tracking ( function () { - var eventName = '404'; + var eventName = '404', + isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\'; if ( typeof window.plausible === 'undefined' || window.plausible.length === 0 || typeof mw.config === 'undefined' ) { return; @@ -9,7 +10,8 @@ if ( mw.config.get( 'is404', false ) === true ) { window.plausible( eventName, { props: { - path: document.location.pathname + title: document.location.pathname, + isAnon, } } ); } diff --git a/resources/ext.plausible.scripts.track-edit-btn/track-edit-btn.js b/resources/ext.plausible.scripts.track-edit-btn/track-edit-btn.js index 7617123..f1a9cba 100644 --- a/resources/ext.plausible.scripts.track-edit-btn/track-edit-btn.js +++ b/resources/ext.plausible.scripts.track-edit-btn/track-edit-btn.js @@ -5,10 +5,12 @@ } var registerEvent = function() { - var eventName = 'EditButtonClick'; + var eventName = 'EditButtonClick', + isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\'; + window.plausible( eventName, { props: { - path: document.location.pathname + isAnon, } } ); }; diff --git a/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js b/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js index 214e807..d7220a1 100644 --- a/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js +++ b/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js @@ -1,7 +1,8 @@ // Infobox Link Click Tracking ( function () { var eventName = 'Infobox: Click', - infoboxes = document.querySelectorAll( '.mw-capiunto-infobox' ); + infoboxes = document.querySelectorAll( '.mw-capiunto-infobox' ), + isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\'; if ( typeof window.plausible === 'undefined' || window.plausible.length === 0 || infoboxes === null ) { return; @@ -19,7 +20,8 @@ eventName, { props: { - link: 'Infobox Image' + link: 'Infobox Image', + isAnon, } } ); @@ -30,7 +32,8 @@ eventName, { props: { - link: link.textContent + link: link.textContent, + isAnon, }, callback: function () { window.location = link.getAttribute('href'); diff --git a/resources/ext.plausible.scripts.track-navplate-clicks/track-navplate-clicks.js b/resources/ext.plausible.scripts.track-navplate-clicks/track-navplate-clicks.js index e78e322..c37f8c1 100644 --- a/resources/ext.plausible.scripts.track-navplate-clicks/track-navplate-clicks.js +++ b/resources/ext.plausible.scripts.track-navplate-clicks/track-navplate-clicks.js @@ -1,7 +1,8 @@ // Navplate Link Click Tracking ( function () { var eventName = 'Navplate: Click', - navplates = document.querySelectorAll( '.navplate' ); + navplates = document.querySelectorAll( '.navplate' ), + isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\'; if ( typeof window.plausible === 'undefined' || window.plausible.length === 0 || navplates === null ) { return; @@ -20,7 +21,8 @@ eventName, { props: { - link: link.textContent + link: link.textContent, + isAnon, }, callback: function () { window.location = link.getAttribute('href'); diff --git a/resources/ext.plausible.scripts.track-search/track-search.js b/resources/ext.plausible.scripts.track-search/track-search.js index 1682c4b..3698aa0 100644 --- a/resources/ext.plausible.scripts.track-search/track-search.js +++ b/resources/ext.plausible.scripts.track-search/track-search.js @@ -2,6 +2,7 @@ ( function () { var eventName = 'SearchInput', search = document.getElementById( 'searchInput' ), + isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\', sendAfter = 1500, // ms minLength = 3, timeoutId; @@ -18,8 +19,9 @@ window.plausible( eventName, { props: { - query: event.target.value, - path: document.location.pathname + term: event.target.value, + title: document.location.pathname, + isAnon, } } ); diff --git a/resources/ext.plausible.scripts.track-special-search/track-special-search.js b/resources/ext.plausible.scripts.track-special-search/track-special-search.js index 0b777c6..69955de 100644 --- a/resources/ext.plausible.scripts.track-special-search/track-special-search.js +++ b/resources/ext.plausible.scripts.track-special-search/track-special-search.js @@ -2,6 +2,7 @@ ( function () { var eventName = 'SpecialSearchInput', search = document.querySelector( 'body.mw-special-Search input[type="search"]' ), + isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\', sendAfter = 1500, // ms minLength = 3, timeoutId; @@ -18,8 +19,9 @@ window.plausible( eventName, { props: { - query: event.target.value, - path: document.location.pathname + term: event.target.value, + title: document.location.pathname, + isAnon, } } ); From 4bbf85ce6f00f9806be75f27b6847e67e4f701d3 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Thu, 17 Aug 2023 10:11:35 +0200 Subject: [PATCH 08/22] refactor: Don't track login/register/logout per default --- extension.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extension.json b/extension.json index 2656585..872167b 100644 --- a/extension.json +++ b/extension.json @@ -96,9 +96,9 @@ "pagedelete": true, "pageundelete": true, "pagemove": true, - "userregister": true, - "userlogin": true, - "userlogout": true, + "userregister": false, + "userlogin": false, + "userlogout": false, "fileupload": true, "filedelete": true, "fileundelete": true, From f1f3b0402da26d2281171558f3109900280c9e3e Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Thu, 17 Aug 2023 10:26:40 +0200 Subject: [PATCH 09/22] refactor: Change `link` -> `title` --- .../track-infobox-clicks.js | 4 ++-- .../track-navplate-clicks.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js b/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js index d7220a1..35d7261 100644 --- a/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js +++ b/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js @@ -20,7 +20,7 @@ eventName, { props: { - link: 'Infobox Image', + title: 'Infobox Image', isAnon, } } @@ -32,7 +32,7 @@ eventName, { props: { - link: link.textContent, + title: link.innerText, isAnon, }, callback: function () { diff --git a/resources/ext.plausible.scripts.track-navplate-clicks/track-navplate-clicks.js b/resources/ext.plausible.scripts.track-navplate-clicks/track-navplate-clicks.js index c37f8c1..6847479 100644 --- a/resources/ext.plausible.scripts.track-navplate-clicks/track-navplate-clicks.js +++ b/resources/ext.plausible.scripts.track-navplate-clicks/track-navplate-clicks.js @@ -21,7 +21,7 @@ eventName, { props: { - link: link.textContent, + title: link.innerText, isAnon, }, callback: function () { From 49872fa5c3c3242c50368d67a7c4bb9e7f1db038 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Thu, 17 Aug 2023 11:29:00 +0200 Subject: [PATCH 10/22] breaking: Standardize event / goal names Use the form of: `: ` --- README.md | 72 ++++++++++--------- includes/Hooks/FileHooks.php | 6 +- includes/Hooks/PageHooks.php | 8 +-- includes/Hooks/SearchHooks.php | 4 +- includes/Hooks/UserHooks.php | 6 +- .../track-menu-links.js | 2 +- .../track-search-links.js | 2 +- .../track-edit-btn.js | 2 +- .../track-infobox-clicks.js | 15 ++-- .../track-search.js | 2 +- .../track-special-search.js | 2 +- 11 files changed, 65 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index e922ba2..7669ff8 100644 --- a/README.md +++ b/README.md @@ -17,33 +17,33 @@ $wgPlausibleApikey = ''; // Only necessary when using Extension:PageViewInfo * Done – Navigate to Special:Version on your wiki to verify that the extension is successfully installed. ## Configuration -| Key | Description | Example | Default | -|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------|---------| -| $wgPlausibleDomain | Plausible Domain. **Required** | https://plausible.io | null | -| $wgPlausibleDomainKey | Domain Key set on the plausible website. **Required** | plausible.io | null | -| $wgPlausibleHonorDNT | Honor the Do Not Track header and disable tracking. | false | true | -| $wgPlausibleTrackOutboundLinks | Enable Tracking of outbound link clicks. | true | false | -| $wgPlausibleTrackFileDownloads | Enable Tracking of link clicks that lead to files, sending a `File Download` event. See [the official docs](https://plausible.io/docs/file-downloads-tracking). | true | false | -| $wgPlausibleTrackFileDownloadExtensions | List of additional file extensions to track. See [the official docs](https://plausible.io/docs/file-downloads-tracking#which-file-types-are-tracked). | ['js', 'py'] | [] | -| $wgPlausibleTrackLoggedIn | Enable Tracking for logged in users. | true | false | -| $wgPlausibleEnableCustomEvents | Enable to add the global `window.plausible` function needed for custom event tracking. | true | false | -| $wgPlausibleIgnoredTitles | List of page titles that should not be tracked. [Examples](https://github.com/plausible/docs/blob/master/docs/excluding-pages.md#common-use-cases-and-examples). | ['/Page1', '/Special:*', ] | [] | -| $wgPlausibleEnableOptOutTag | Enables or disables the `` tag that allows users to opt-out from being tracked. | false | true | -| $wgPlausibleApiKey | Auth Bearer key for integration with [Extension:PageViewInfo](https://www.mediawiki.org/wiki/Extension:PageViewInfo) | | | +| Key | Description | Example | Default | +|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|---------| +| $wgPlausibleDomain | Plausible Domain. **Required** | https://plausible.io | null | +| $wgPlausibleDomainKey | Domain Key set on the plausible website. **Required** | plausible.io | null | +| $wgPlausibleHonorDNT | Honor the Do Not Track header and disable tracking. | false | true | +| $wgPlausibleTrackOutboundLinks | Enable Tracking of outbound link clicks. | true | false | +| $wgPlausibleTrackFileDownloads | Enable Tracking of link clicks that lead to files, sending a `File Download` event. See [the official docs](https://plausible.io/docs/file-downloads-tracking). | true | false | +| $wgPlausibleTrackFileDownloadExtensions | List of additional file extensions to track. See [the official docs](https://plausible.io/docs/file-downloads-tracking#which-file-types-are-tracked). | ['js', 'py'] | [] | +| $wgPlausibleTrackLoggedIn | Enable Tracking for logged in users. | true | false | +| $wgPlausibleEnableCustomEvents | Enable to add the global `window.plausible` function needed for custom event tracking. | true | false | +| $wgPlausibleIgnoredTitles | List of page titles that should not be tracked. [Examples](https://github.com/plausible/docs/blob/master/docs/excluding-pages.md#common-use-cases-and-examples). | ['/Page1', '/Special:*', ] | [] | +| $wgPlausibleEnableOptOutTag | Enables or disables the `` tag that allows users to opt-out from being tracked. | false | true | +| $wgPlausibleApiKey | Auth Bearer key for integration with [Extension:PageViewInfo](https://www.mediawiki.org/wiki/Extension:PageViewInfo) | | | ### Included tracking scripts The following tracking modules can be activated by setting the provided configuration key in `LocalSettings.php` to true. -| Key | Description | EventName | -|-------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------| -| $wgPlausibleTrack404 | Sends a `404` event for unknown titles. | `404` | -| $wgPlausibleTrackSearchInput | Send inputs to `#searchInput` to plausible as a custom event named `SearchInput`. | `SearchInput` | -| $wgPlausibleTrackEditButtonClicks | Track clicks to `#ca-edit a` as a custom event named `EditButtonClick`. | `EditButtonClick` | -| $wgPlausibleTrackNavplateClicks | Track clicks to links inside `.navplate` elements. | `Navplate: Click` | -| $wgPlausibleTrackInfoboxClicks | Track clicks to links inside `.mw-capiunto-infobox` elements. | `Infobox: Click` | -| $wgPlausibleTrackCitizenSearchLinks | Only for [Skin:Citizen](https://github.com/StarCitizenTools/mediawiki-skins-Citizen). Track clicks to search result links found in `#typeahead-suggestions`. Event is named `CitizenSearchLinkClick`. | `CitizenSearchLinkClick` | -| $wgPlausibleTrackCitizenMenuLinks | Only for [Skin:Citizen](https://github.com/StarCitizenTools/mediawiki-skins-Citizen). Track clicks to links in the sidebar menu. Event is named `CitizenMenuLinkClick`. | `CitizenMenuLinkClick` | +| Key | Description | EventName | +|-------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------| +| $wgPlausibleTrack404 | Sends a `404` event for unknown titles. | `404` | +| $wgPlausibleTrackSearchInput | Send inputs to `#searchInput` to plausible as a custom event named `Search: Input`. | `Search: Input` | +| $wgPlausibleTrackEditButtonClicks | Track clicks to `#ca-edit a` as a custom event named `Edit Button: Click`. | `Edit Button: Click` | +| $wgPlausibleTrackNavplateClicks | Track clicks to links inside `.navplate` elements. | `Navplate: Click` | +| $wgPlausibleTrackInfoboxClicks | Track clicks to links inside `.mw-capiunto-infobox` and `.infobox` elements. | `Infobox: Click` | +| $wgPlausibleTrackCitizenSearchLinks | Only for [Skin:Citizen](https://github.com/StarCitizenTools/mediawiki-skins-Citizen). Track clicks to search result links found in `#typeahead-suggestions`. Event is named `Citizen: Search Link Click`. | `Citizen: Search Link Click` | +| $wgPlausibleTrackCitizenMenuLinks | Only for [Skin:Citizen](https://github.com/StarCitizenTools/mediawiki-skins-Citizen). Track clicks to links in the sidebar menu. Event is named `Citizen: Menu Link Click`. | `Citizen: Menu Link Click` | ### Server Side Tracking Some events can be sent serverside without having to rely on the included plausible client script. @@ -51,18 +51,20 @@ Some events can be sent serverside without having to rely on the included plausi The following custom events can be activated: ```php $wgPlausibleServerSideTracking = [ - 'pageview' => false, - 'page404' => false, - 'pageedit' => true, - 'pagedelete' => true, - 'pageundelete' => true, - 'pagemove' => true, - 'userregister' => true, - 'userlogin' => true, - 'userlogout' => true, - 'fileupload' => true, - 'filedelete' => true, - 'fileundelete' => true, + 'pageview' => false, // EventName: pageview + 'page404' => false, // EventName: 404 + 'pageedit' => true, // EventName: Page: Edit; Info: Page has been successfully edited + 'pagedelete' => true, // EventName: Page: Delete; Info: Page has been deleted + 'pageundelete' => true, // EventName: Page: Undelete; Info: Page has been undeleted + 'pagemove' => true, // EventName: Page: Move; Info: Page was moved + 'userregister' => false, // EventName: User: Register; Info: A new user registered + 'userlogin' => false, // EventName: User: Login; Info: A user logged in + 'userlogout' => false, // EventName: User: Logout; Info: A user logged out + 'fileupload' => true, // EventName: File: Upload; Info: A file was uploaded + 'filedelete' => true, // EventName: File: Delete; Info: A file was deleted + 'fileundelete' => true, // EventName: File: Undelete; Info: A file was undeleted + 'searchnotfound' => true, // EventName: Search: Not found; Info: A searched term was not found / has no title on the wiki + 'searchfound' => true, // EventName: Search: Found; Info: A searched term was found / has a corresponding title on the wiki ]; ``` @@ -80,7 +82,7 @@ if (typeof window.plausible === 'undefined') { } document.querySelector('#ca-edit a').addEventListener('click', function (event) { - plausible('Editbtn Clicked'); + plausible('Edit Button: Click'); }); ``` diff --git a/includes/Hooks/FileHooks.php b/includes/Hooks/FileHooks.php index ac908ae..ec28fe9 100644 --- a/includes/Hooks/FileHooks.php +++ b/includes/Hooks/FileHooks.php @@ -28,7 +28,7 @@ public function onFileDeleteComplete( $file, $oldimage, $article, $user, $reason return; } - $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), 'filedelete' ) ); + $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), 'File: Delete' ) ); } /** @@ -39,7 +39,7 @@ public function onUploadComplete( $uploadBase ): void { return; } - $this->jobs->push( PlausibleEventJob::newFromRequest( RequestContext::getMain()->getRequest(), 'fileupload' ) ); + $this->jobs->push( PlausibleEventJob::newFromRequest( RequestContext::getMain()->getRequest(), 'File: Upload' ) ); } /** @@ -50,6 +50,6 @@ public function onFileUndeleteComplete( $title, $fileVersions, $user, $reason ): return; } - $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), 'fileundelete' ) ); + $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), 'File: Undelete' ) ); } } diff --git a/includes/Hooks/PageHooks.php b/includes/Hooks/PageHooks.php index 2cc02bb..5010acd 100644 --- a/includes/Hooks/PageHooks.php +++ b/includes/Hooks/PageHooks.php @@ -81,7 +81,7 @@ public function onArticleDeleteAfterSuccess( $title, $outputPage ): void { return; } - $this->jobs->push( PlausibleEventJob::newFromRequest( $outputPage->getRequest(), 'pagedelete' ) ); + $this->jobs->push( PlausibleEventJob::newFromRequest( $outputPage->getRequest(), 'Page: Delete' ) ); } /** @@ -94,7 +94,7 @@ public function onPageSaveComplete( $wikiPage, $user, $summary, $flags, $revisio $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), - 'pageedit', + 'Page: Edit', [ 'title' => $wikiPage->getTitle()->getText(), 'user' => $user->isRegistered() ? $user->getName() : null, @@ -110,7 +110,7 @@ public function onArticleUndelete( $title, $create, $comment, $oldPageId, $resto return; } - $this->jobs->push( PlausibleEventJob::newFromRequest( RequestContext::getMain()->getRequest(), 'pageedit' ) ); + $this->jobs->push( PlausibleEventJob::newFromRequest( RequestContext::getMain()->getRequest(), 'Page: Undelete' ) ); } /** @@ -121,6 +121,6 @@ public function onPageMoveComplete( $old, $new, $user, $pageid, $redirid, $reaso return; } - $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), 'pagemove' ) ); + $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), 'Page: Move' ) ); } } diff --git a/includes/Hooks/SearchHooks.php b/includes/Hooks/SearchHooks.php index 41b8fb0..3641db9 100644 --- a/includes/Hooks/SearchHooks.php +++ b/includes/Hooks/SearchHooks.php @@ -29,7 +29,7 @@ public function onSpecialSearchNogomatch( &$title ): void { $this->jobs->push( PlausibleEventJob::newFromRequest( RequestContext::getMain()->getRequest(), - 'searchnotfound', + 'Search: Not Found', [ 'term' => $title->getText(), ] @@ -46,7 +46,7 @@ public function onSpecialSearchGoResult( $term, $title, &$url ): void { $this->jobs->push( PlausibleEventJob::newFromRequest( RequestContext::getMain()->getRequest(), - 'searchfound', + 'Search: Found', [ 'term' => $term, 'title' => $title->getText(), diff --git a/includes/Hooks/UserHooks.php b/includes/Hooks/UserHooks.php index 63febae..63909ac 100644 --- a/includes/Hooks/UserHooks.php +++ b/includes/Hooks/UserHooks.php @@ -29,7 +29,7 @@ public function onLocalUserCreated( $user, $autocreated ): void { $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), - 'userregister', + 'User: Register', [ 'user' => $user->isRegistered() ? $user->getName() : null, ] @@ -46,7 +46,7 @@ public function onUserLoginComplete( $user, &$inject_html, $direct ): void { $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), - 'userlogin', + 'User: Login', [ 'user' => $user->isRegistered() ? $user->getName() : null, ] @@ -63,7 +63,7 @@ public function onUserLogoutComplete( $user, &$inject_html, $oldName ): void { $this->jobs->push( PlausibleEventJob::newFromRequest( $user->getRequest(), - 'userlogout', + 'User: Logout', [ 'user' => $user->isRegistered() ? $user->getName() : null, ] diff --git a/resources/ext.plausible.scripts.citizen.track-menu-links/track-menu-links.js b/resources/ext.plausible.scripts.citizen.track-menu-links/track-menu-links.js index 9cf0e69..e6e0867 100644 --- a/resources/ext.plausible.scripts.citizen.track-menu-links/track-menu-links.js +++ b/resources/ext.plausible.scripts.citizen.track-menu-links/track-menu-links.js @@ -1,6 +1,6 @@ // Menu Link click Tracking ( function () { - var eventName = 'CitizenMenuLinkClick', + var eventName = 'Citizen: Menu Link Click', isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\'; if ( typeof window.plausible === 'undefined' || window.plausible.length === 0 ) { diff --git a/resources/ext.plausible.scripts.citizen.track-search-links/track-search-links.js b/resources/ext.plausible.scripts.citizen.track-search-links/track-search-links.js index 94e3e63..00dcdc4 100644 --- a/resources/ext.plausible.scripts.citizen.track-search-links/track-search-links.js +++ b/resources/ext.plausible.scripts.citizen.track-search-links/track-search-links.js @@ -1,6 +1,6 @@ // Search Link click Tracking ( function () { - var eventName = 'CitizenSearchLinkClick', + var eventName = 'Citizen: Search Link Click', suggestions = document.getElementById( 'searchform' ), search = document.getElementById( 'searchInput' ), isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\', diff --git a/resources/ext.plausible.scripts.track-edit-btn/track-edit-btn.js b/resources/ext.plausible.scripts.track-edit-btn/track-edit-btn.js index f1a9cba..8c8310a 100644 --- a/resources/ext.plausible.scripts.track-edit-btn/track-edit-btn.js +++ b/resources/ext.plausible.scripts.track-edit-btn/track-edit-btn.js @@ -5,7 +5,7 @@ } var registerEvent = function() { - var eventName = 'EditButtonClick', + var eventName = 'Edit Button: Click', isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\'; window.plausible( eventName, { diff --git a/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js b/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js index 35d7261..93d5fd8 100644 --- a/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js +++ b/resources/ext.plausible.scripts.track-infobox-clicks/track-infobox-clicks.js @@ -1,16 +1,20 @@ // Infobox Link Click Tracking ( function () { var eventName = 'Infobox: Click', - infoboxes = document.querySelectorAll( '.mw-capiunto-infobox' ), + infoboxes = [ + ...Array.from(document.querySelectorAll( '.mw-capiunto-infobox' )), + ...Array.from(document.querySelectorAll( '.infobox' )), + ], isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\'; - if ( typeof window.plausible === 'undefined' || window.plausible.length === 0 || infoboxes === null ) { + + if ( typeof window.plausible === 'undefined' || window.plausible.length === 0 || infoboxes.length === null ) { return; } infoboxes.forEach(infobox => { infobox.querySelectorAll('a:not(.new)').forEach(link => { - link.addEventListener('click', function (event) { + const callback = function (event) { if (link.getAttribute('href') === null) { return; } @@ -41,7 +45,10 @@ } ); } - }); + }; + + link.removeEventListener('click', callback); + link.addEventListener('click', callback); }); }); }() ); diff --git a/resources/ext.plausible.scripts.track-search/track-search.js b/resources/ext.plausible.scripts.track-search/track-search.js index 3698aa0..0cfc6da 100644 --- a/resources/ext.plausible.scripts.track-search/track-search.js +++ b/resources/ext.plausible.scripts.track-search/track-search.js @@ -1,6 +1,6 @@ // Search Input Tracking ( function () { - var eventName = 'SearchInput', + var eventName = 'Search: Input', search = document.getElementById( 'searchInput' ), isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\', sendAfter = 1500, // ms diff --git a/resources/ext.plausible.scripts.track-special-search/track-special-search.js b/resources/ext.plausible.scripts.track-special-search/track-special-search.js index 69955de..8d7d180 100644 --- a/resources/ext.plausible.scripts.track-special-search/track-special-search.js +++ b/resources/ext.plausible.scripts.track-special-search/track-special-search.js @@ -1,6 +1,6 @@ // Special Search Input Tracking ( function () { - var eventName = 'SpecialSearchInput', + var eventName = 'Special Search: Input', search = document.querySelector( 'body.mw-special-Search input[type="search"]' ), isAnon = mw.user?.tokens?.values?.watchToken === null || mw.user?.tokens?.values?.watchToken === '+\\', sendAfter = 1500, // ms From 0af1a598fed9631858736efba37337f89f75581b Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Thu, 17 Aug 2023 11:40:21 +0200 Subject: [PATCH 11/22] docs: Update readme --- README.md | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 7669ff8..b90648d 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ $wgPlausibleApikey = ''; // Only necessary when using Extension:PageViewInfo ### Included tracking scripts The following tracking modules can be activated by setting the provided configuration key in `LocalSettings.php` to true. -| Key | Description | EventName | +| Key | Description | Event Name | |-------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------| | $wgPlausibleTrack404 | Sends a `404` event for unknown titles. | `404` | | $wgPlausibleTrackSearchInput | Send inputs to `#searchInput` to plausible as a custom event named `Search: Input`. | `Search: Input` | @@ -51,23 +51,40 @@ Some events can be sent serverside without having to rely on the included plausi The following custom events can be activated: ```php $wgPlausibleServerSideTracking = [ - 'pageview' => false, // EventName: pageview - 'page404' => false, // EventName: 404 - 'pageedit' => true, // EventName: Page: Edit; Info: Page has been successfully edited - 'pagedelete' => true, // EventName: Page: Delete; Info: Page has been deleted - 'pageundelete' => true, // EventName: Page: Undelete; Info: Page has been undeleted - 'pagemove' => true, // EventName: Page: Move; Info: Page was moved - 'userregister' => false, // EventName: User: Register; Info: A new user registered - 'userlogin' => false, // EventName: User: Login; Info: A user logged in - 'userlogout' => false, // EventName: User: Logout; Info: A user logged out - 'fileupload' => true, // EventName: File: Upload; Info: A file was uploaded - 'filedelete' => true, // EventName: File: Delete; Info: A file was deleted - 'fileundelete' => true, // EventName: File: Undelete; Info: A file was undeleted - 'searchnotfound' => true, // EventName: Search: Not found; Info: A searched term was not found / has no title on the wiki - 'searchfound' => true, // EventName: Search: Found; Info: A searched term was found / has a corresponding title on the wiki + // Event Name: pageview + 'pageview' => false, + // Event Name: 404 + 'page404' => false, + // Event Name: Page: Edit + 'pageedit' => true, // Page has been successfully edited + // Event Name: Page: Delete + 'pagedelete' => true, // Page has been deleted + // Event Name: Page: Undelete + 'pageundelete' => true, // Page has been undeleted + // Event Name: Page: Move + 'pagemove' => true, // Page was moved + // Event Name: User: Register + 'userregister' => false, // A new user registered + // Event Name: User: Login + 'userlogin' => false, // A user logged in + // Event Name: User: Logout + 'userlogout' => false, // A user logged out + // Event Name: File: Upload + 'fileupload' => true, // A file was uploaded + // Event Name: File: Delete + 'filedelete' => true, // A file was deleted + // Event Name: File: Undelete + 'fileundelete' => true, // A file was undeleted + // Event Name: Search: Not found + 'searchnotfound' => true, // A searched term was not found / has no title on the wiki + // Event Name: Search: Found + 'searchfound' => true, // A searched term was found / has a corresponding title on the wiki ]; ``` +### Event / Goal Names +This extension chooses the following convention for naming events / goals: `Subject: Event/Action`. + ## Tracking Custom Events https://github.com/plausible/docs/blob/master/docs/custom-event-goals.md From e983ddf6766a1940f86b6236a29a881e7c259884 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Thu, 17 Aug 2023 13:14:21 +0200 Subject: [PATCH 12/22] feat: Add tagged events And default load window.plausible via `pageview-props`. This removes $wgPlausibleEnableTaggedEvents. --- README.md | 47 +++++++++++++++++++++++++++----------- extension.json | 6 ++--- includes/Plausible.php | 51 ++++++------------------------------------ 3 files changed, 44 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index b90648d..6111ee7 100644 --- a/README.md +++ b/README.md @@ -17,19 +17,19 @@ $wgPlausibleApikey = ''; // Only necessary when using Extension:PageViewInfo * Done – Navigate to Special:Version on your wiki to verify that the extension is successfully installed. ## Configuration -| Key | Description | Example | Default | -|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|---------| -| $wgPlausibleDomain | Plausible Domain. **Required** | https://plausible.io | null | -| $wgPlausibleDomainKey | Domain Key set on the plausible website. **Required** | plausible.io | null | -| $wgPlausibleHonorDNT | Honor the Do Not Track header and disable tracking. | false | true | -| $wgPlausibleTrackOutboundLinks | Enable Tracking of outbound link clicks. | true | false | -| $wgPlausibleTrackFileDownloads | Enable Tracking of link clicks that lead to files, sending a `File Download` event. See [the official docs](https://plausible.io/docs/file-downloads-tracking). | true | false | -| $wgPlausibleTrackFileDownloadExtensions | List of additional file extensions to track. See [the official docs](https://plausible.io/docs/file-downloads-tracking#which-file-types-are-tracked). | ['js', 'py'] | [] | -| $wgPlausibleTrackLoggedIn | Enable Tracking for logged in users. | true | false | -| $wgPlausibleEnableCustomEvents | Enable to add the global `window.plausible` function needed for custom event tracking. | true | false | -| $wgPlausibleIgnoredTitles | List of page titles that should not be tracked. [Examples](https://github.com/plausible/docs/blob/master/docs/excluding-pages.md#common-use-cases-and-examples). | ['/Page1', '/Special:*', ] | [] | -| $wgPlausibleEnableOptOutTag | Enables or disables the `` tag that allows users to opt-out from being tracked. | false | true | -| $wgPlausibleApiKey | Auth Bearer key for integration with [Extension:PageViewInfo](https://www.mediawiki.org/wiki/Extension:PageViewInfo) | | | +| Key | Description | Example | Default | +|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|---------| +| $wgPlausibleDomain | Plausible Domain. **Required** | https://plausible.io | null | +| $wgPlausibleDomainKey | Domain Key set on the plausible website. **Required** | plausible.io | null | +| $wgPlausibleApiKey | Auth Bearer key for integration with [Extension:PageViewInfo](https://www.mediawiki.org/wiki/Extension:PageViewInfo) | | | +| $wgPlausibleHonorDNT | Honor the Do Not Track header and disable tracking. | false | true | +| $wgPlausibleTrackOutboundLinks | Enable Tracking of outbound link clicks. | true | false | +| $wgPlausibleTrackFileDownloads | Enable Tracking of link clicks that lead to files, sending a `File Download` event. See [the official docs](https://plausible.io/docs/file-downloads-tracking). | true | false | +| $wgPlausibleTrackFileDownloadExtensions | List of additional file extensions to track. See [the official docs](https://plausible.io/docs/file-downloads-tracking#which-file-types-are-tracked). | ['js', 'py'] | [] | +| $wgPlausibleTrackLoggedIn | Enable Tracking for logged in users. | true | false | +| $wgPlausibleEnableTaggedEvents | Enable click tracking via css classes. See [the official docs](https://plausible.io/docs/custom-event-goals#2-add-a-css-class-name-to-the-element-you-want-to-track-on-your-site). | true | false | +| $wgPlausibleIgnoredTitles | List of page titles that should not be tracked. [Examples](https://github.com/plausible/docs/blob/master/docs/excluding-pages.md#common-use-cases-and-examples). | ['/Page1', '/Special:*', ] | [] | +| $wgPlausibleEnableOptOutTag | Enables or disables the `` tag that allows users to opt-out from being tracked. | false | true | ### Included tracking scripts @@ -103,6 +103,27 @@ document.querySelector('#ca-edit a').addEventListener('click', function (event) }); ``` +### Via css classes +With setting `$wgPlausibleEnableTaggedEvents = true;` click to elements can be tracked by setting css classes. +From [the official docs](https://plausible.io/docs/custom-event-goals): +> You can also add class names directly in HTML +> If you can edit the raw HTML code of the element you want to track, you can also add the classes directly in HTML. For example: +> +> `````` +> `````` +> `````` +> `````` +> +> Or if your element already has a class attribute, just separate the new ones with a space: +> +> `````` +> `````` +> +> `````` +> `````` + +> When you send custom events to Plausible, they won't show up in your dashboard automatically. You'll have to configure the goal for the conversion numbers to show up. + ## Ignoring Pages https://github.com/plausible/docs/blob/master/docs/excluding-pages.md#common-use-cases-and-examples diff --git a/extension.json b/extension.json index 872167b..2bc948c 100644 --- a/extension.json +++ b/extension.json @@ -43,8 +43,8 @@ "description": "Enable Tracking for logged in users", "value": false }, - "PlausibleEnableCustomEvents": { - "description": "Set to true to add the window.plausible function. Needed for custom event goals etc.", + "PlausibleEnableTaggedEvents": { + "description": "Enable tracking clicks to tagged elements via css classes", "value": false }, "PlausibleIgnoredTitles": { @@ -68,7 +68,7 @@ "value": false }, "PlausibleTrackInfoboxClicks": { - "description": "Tracks clicks to links inside .mw-capiunto-infobox elements", + "description": "Tracks clicks to links inside .mw-capiunto-infobox and .infobox elements", "value": false }, "PlausibleTrackCitizenSearchLinks": { diff --git a/includes/Plausible.php b/includes/Plausible.php index e27b60e..24df27d 100644 --- a/includes/Plausible.php +++ b/includes/Plausible.php @@ -47,13 +47,6 @@ class Plausible { */ private $domainKey; - /** - * True if window.plausible was added - * - * @var bool - */ - private $windowFnAdded = false; - /** * @var Config */ @@ -75,16 +68,7 @@ public function addScript(): void { } $script = $this->buildScript(); - // Script needs to be placed in - if ( strpos( $script, 'plausible.js' ) === false ) { - $this->out->addHeadItem( 'plausible', $script ); - } else { - $this->out->addScript( $script ); - } - - if ( $this->getConfigValue( 'PlausibleEnableCustomEvents', false ) === true ) { - $this->addWindowDotPlausible(); - } + $this->out->addHeadItem( 'plausible', $script ); } /** @@ -106,8 +90,6 @@ public function addModules(): void { 'PlausibleTrackCitizenMenuLinks' => 'ext.plausible.scripts.citizen.track-menu-links', ]; - $anythingAdded = false; - foreach ( $availableModules as $config => $module ) { if ( $this->getConfigValue( $config, false ) === false ) { continue; @@ -119,31 +101,7 @@ public function addModules(): void { } $this->out->addModules( $module ); - $anythingAdded = true; - } - - if ( $anythingAdded ) { - $this->addWindowDotPlausible(); - } - } - - /** - * Adds the global window.plausible function - */ - private function addWindowDotPlausible(): void { - if ( $this->windowFnAdded === true ) { - return; } - - $nonce = $this->out->getCSP()->getNonce(); - - $this->out->addScript( - sprintf( - '', - $nonce !== false ? $nonce : '' - ) - ); - $this->windowFnAdded = true; } /** @@ -168,7 +126,8 @@ private function buildScript(): string { * @return string */ private function buildScriptPath(): string { - $name = 'plausible'; + $name = 'script'; + $name = sprintf( '%s.pageview-props', $name ); if ( $this->getConfigValue( 'PlausibleTrackOutboundLinks', false ) === true ) { $name = sprintf( '%s.outbound-links', $name ); @@ -182,6 +141,10 @@ private function buildScriptPath(): string { $name = sprintf( '%s.file-downloads', $name ); } + if ( $this->getConfigValue( 'PlausibleEnableTaggedEvents', false ) === true ) { + $name = sprintf( '%s.tagged-events', $name ); + } + return sprintf( '%s/js/%s.js', rtrim( $this->plausibleDomain, '/' ), From 6c13e2e736bfcbddaae7552be39013171461265d Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Thu, 17 Aug 2023 15:16:35 +0200 Subject: [PATCH 13/22] ci: WIP Add tests and test workflow --- .github/workflows/ci.yml | 74 +++++++ .github/workflows/installWiki.sh | 36 ++++ tests/phpunit/Hooks/FileHooksTest.php | 173 ++++++++++++++++ tests/phpunit/Hooks/PageHooksTest.php | 261 ++++++++++++++++++++++++ tests/phpunit/Hooks/SearchHooksTest.php | 126 ++++++++++++ tests/phpunit/PlausibleTest.php | 127 ++++++++++++ 6 files changed, 797 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/installWiki.sh create mode 100644 tests/phpunit/Hooks/FileHooksTest.php create mode 100644 tests/phpunit/Hooks/PageHooksTest.php create mode 100644 tests/phpunit/Hooks/SearchHooksTest.php create mode 100644 tests/phpunit/PlausibleTest.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..961d530 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,74 @@ +name: CI + +on: + push: + branches: [ master, develop ] + pull_request: + branches: [ "*" ] + +jobs: + test: + name: "PHPUnit: MW ${{ matrix.mw }}, PHP ${{ matrix.php }}" + continue-on-error: ${{ matrix.experimental }} + + strategy: + matrix: + include: + - mw: 'REL1_39' + php: 8.1 + experimental: false + - mw: 'REL1_40' + php: 8.1 + experimental: true + - mw: 'master' + php: 8.1 + experimental: true + + runs-on: ubuntu-latest + + defaults: + run: + working-directory: mediawiki + + steps: + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: mbstring, intl + tools: composer + + - name: Cache MediaWiki + id: cache-mediawiki + uses: actions/cache@v3 + with: + path: | + mediawiki + !mediawiki/extensions/ + !mediawiki/vendor/ + key: mw_${{ matrix.mw }}-php${{ matrix.php }}-v20 + + - name: Cache Composer cache + uses: actions/cache@v3 + with: + path: ~/.composer/cache + key: composer-php${{ matrix.php }} + + - uses: actions/checkout@v3 + with: + path: EarlyCopy + + - name: Install MediaWiki + if: steps.cache-mediawiki.outputs.cache-hit != 'true' + working-directory: ~ + run: bash EarlyCopy/.github/workflows/installWiki.sh ${{ matrix.mw }} + + - uses: actions/checkout@v3 + with: + path: mediawiki/extensions/Plausible + + - name: Composer update + run: composer update + + - name: Run PHPUnit + run: composer phpunit:entrypoint -- --group Plausible \ No newline at end of file diff --git a/.github/workflows/installWiki.sh b/.github/workflows/installWiki.sh new file mode 100644 index 0000000..6a5f065 --- /dev/null +++ b/.github/workflows/installWiki.sh @@ -0,0 +1,36 @@ +#! /bin/bash + +MW_BRANCH=$1 +EXTENSION_NAME=$2 + +wget https://github.com/wikimedia/mediawiki/archive/$MW_BRANCH.tar.gz -nv + +tar -zxf $MW_BRANCH.tar.gz +mv mediawiki-$MW_BRANCH mediawiki + +cd mediawiki + +composer install +php maintenance/install.php --dbtype sqlite --dbuser root --dbname mw --dbpath $(pwd) --pass AdminPassword WikiName AdminUser + +# echo 'error_reporting(E_ALL| E_STRICT);' >> LocalSettings.php +# echo 'ini_set("display_errors", 1);' >> LocalSettings.php +echo '$wgShowExceptionDetails = true;' >> LocalSettings.php +echo '$wgShowDBErrorBacktrace = true;' >> LocalSettings.php +echo '$wgDevelopmentWarnings = true;' >> LocalSettings.php + +echo 'wfLoadExtension( "Plausible" );' >> LocalSettings.php + +cat <> composer.local.json +{ + "require": { + + }, + "extra": { + "merge-plugin": { + "merge-dev": true, + "include": [] + } + } +} +EOT \ No newline at end of file diff --git a/tests/phpunit/Hooks/FileHooksTest.php b/tests/phpunit/Hooks/FileHooksTest.php new file mode 100644 index 0000000..221fb0a --- /dev/null +++ b/tests/phpunit/Hooks/FileHooksTest.php @@ -0,0 +1,173 @@ +overrideConfigValues( [ + 'PlausibleTrackOutboundLinks' => false, + 'PlausibleTrackFileDownloads' => false, + 'PlausibleTrackLoggedIn' => false, + 'PlausibleEnableTaggedEvents' => false, + ] ); + + $this->mockQueue = $this->getMockBuilder( JobQueueGroup::class ) + ->disableOriginalConstructor() + ->onlyMethods( [ 'push' ] ) + ->getMock(); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\FileHooks::onUploadComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testUploadComplete() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new FileHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onUploadComplete( new UploadFromFile() ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\FileHooks::onFileDeleteComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testDeleteComplete() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new FileHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $file = new LocalFile( + Title::newFromText( 'Foo.jpg', NS_FILE ), + $this->getServiceContainer()->getRepoGroup()->getLocalRepo() + ); + + $hooks->onFileDeleteComplete( $file, null, null, User::createNew( 'Foo' ), '' ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\FileHooks::onFileUndeleteComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testUndeleteComplete() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new FileHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onFileUndeleteComplete( Title::newFromText( 'Foo.jpg', NS_FILE ), [], User::createNew( 'Foo2' ), '' ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\FileHooks::onUploadComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testUploadCompleteDisabled() { + $this->overrideConfigValues( [ + 'PlausibleServerSideTracking' => [ + 'fileupload' => false, + ], + ] ); + + $this->mockQueue->expects( $this->never() )->method( 'push' ); + + $hooks = new FileHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onUploadComplete( new UploadFromFile() ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\FileHooks::onFileDeleteComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testDeleteCompleteDisabled() { + $this->overrideConfigValues( [ + 'PlausibleServerSideTracking' => [ + 'filedelete' => false, + ], + ] ); + + $this->mockQueue->expects( $this->never() )->method( 'push' ); + + $hooks = new FileHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $file = new LocalFile( + Title::newFromText( 'Foo.jpg', NS_FILE ), + $this->getServiceContainer()->getRepoGroup()->getLocalRepo() + ); + + $hooks->onFileDeleteComplete( $file, null, null, User::createNew( 'Foo' ), '' ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\FileHooks::onFileUndeleteComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testUndeleteCompleteDisabled() { + $this->overrideConfigValues( [ + 'PlausibleServerSideTracking' => [ + 'fileundelete' => false, + ], + ] ); + + $this->mockQueue->expects( $this->never() )->method( 'push' ); + + $hooks = new FileHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onFileUndeleteComplete( Title::newFromText( 'Foo.jpg', NS_FILE ), [], User::createNew( 'Foo2' ), '' ); + } +} diff --git a/tests/phpunit/Hooks/PageHooksTest.php b/tests/phpunit/Hooks/PageHooksTest.php new file mode 100644 index 0000000..babe760 --- /dev/null +++ b/tests/phpunit/Hooks/PageHooksTest.php @@ -0,0 +1,261 @@ +overrideConfigValues( [ + 'PlausibleTrackOutboundLinks' => false, + 'PlausibleTrackFileDownloads' => false, + 'PlausibleTrackLoggedIn' => false, + 'PlausibleEnableTaggedEvents' => false, + ] ); + + $this->mockQueue = $this->getMockBuilder( JobQueueGroup::class ) + ->disableOriginalConstructor() + ->onlyMethods( [ 'push' ] ) + ->getMock(); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onArticleDeleteAfterSuccess + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testArticleDeleteAfterSuccess() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onArticleDeleteAfterSuccess( Title::newFromText( 'Foo' ), new OutputPage( RequestContext::getMain() ) ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onPageSaveComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testPageSaveComplete() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onPageSaveComplete( + $this->getServiceContainer()->getWikiPageFactory()->newFromTitle( Title::newFromText( 'Foo' ) ), + User::createNew( 'PageSaveComplete' ), + '', + 0, + $this->getMockBuilder( RevisionRecord::class )->disableOriginalConstructor()->getMock(), + new EditResult( true, false, null, null, null, false, false, [] ) + ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onArticleUndelete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testArticleUndelete() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onArticleUndelete( + Title::newFromText( 'ArticleUndelete' ), + true, + null, + 0, + [], + ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onPageMoveComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testPageMoveComplete() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onPageMoveComplete( + Title::newFromText( 'Foo' ), + Title::newFromText( 'Bar' ), + User::createNew( 'PageMoveComplete' ), + 0, + 0, + '', + $this->getMockBuilder( RevisionRecord::class )->disableOriginalConstructor()->getMock() + ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onArticleDeleteAfterSuccess + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testArticleDeleteAfterSuccessDisabled() { + $this->overrideConfigValues( [ + 'PlausibleServerSideTracking' => [ + 'pageedit' => false, + 'pagedelete' => false, + 'pageundelete' => false, + 'pagemove' => false, + ], + ] ); + + $this->mockQueue->expects( $this->never() )->method( 'push' ); + + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onArticleDeleteAfterSuccess( Title::newFromText( 'Foo' ), new OutputPage( RequestContext::getMain() ) ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onPageSaveComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testPageSaveCompleteDisabled() { + $this->overrideConfigValues( [ + 'PlausibleServerSideTracking' => [ + 'pageedit' => false, + 'pagedelete' => false, + 'pageundelete' => false, + 'pagemove' => false, + ], + ] ); + + $this->mockQueue->expects( $this->never() )->method( 'push' ); + + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onPageSaveComplete( + $this->getServiceContainer()->getWikiPageFactory()->newFromTitle( Title::newFromText( 'Foo' ) ), + User::createNew( 'PageSaveCompleteDisabled' ), + '', + 0, + $this->getMockBuilder( RevisionRecord::class )->disableOriginalConstructor()->getMock(), + new EditResult( true, false, null, null, null, false, false, [] ) + ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onArticleUndelete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testArticleUndeleteDisabled() { + $this->overrideConfigValues( [ + 'PlausibleServerSideTracking' => [ + 'pageedit' => false, + 'pagedelete' => false, + 'pageundelete' => false, + 'pagemove' => false, + ], + ] ); + + $this->mockQueue->expects( $this->never() )->method( 'push' ); + + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onArticleUndelete( + Title::newFromText( 'Foo' ), + true, + null, + 0, + [], + ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onPageMoveComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testPageMoveCompleteDisabled() { + $this->overrideConfigValues( [ + 'PlausibleServerSideTracking' => [ + 'pageedit' => false, + 'pagedelete' => false, + 'pageundelete' => false, + 'pagemove' => false, + ], + ] ); + + $this->mockQueue->expects( $this->never() )->method( 'push' ); + + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onPageMoveComplete( + Title::newFromText( 'Foo' ), + Title::newFromText( 'Bar' ), + User::createNew( 'PageMoveCompleteDisabled' ), + 0, + 0, + '', + $this->getMockBuilder( RevisionRecord::class )->disableOriginalConstructor()->getMock() + ); + } +} diff --git a/tests/phpunit/Hooks/SearchHooksTest.php b/tests/phpunit/Hooks/SearchHooksTest.php new file mode 100644 index 0000000..b055bcb --- /dev/null +++ b/tests/phpunit/Hooks/SearchHooksTest.php @@ -0,0 +1,126 @@ +overrideConfigValues( [ + 'PlausibleTrackOutboundLinks' => false, + 'PlausibleTrackFileDownloads' => false, + 'PlausibleTrackLoggedIn' => false, + 'PlausibleEnableTaggedEvents' => false, + ] ); + + $this->mockQueue = $this->getMockBuilder( JobQueueGroup::class ) + ->disableOriginalConstructor() + ->onlyMethods( [ 'push' ] ) + ->getMock(); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\SearchHooks::onSpecialSearchGoResult + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testSearchHooksFound() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new SearchHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $empty = null; + + $hooks->onSpecialSearchGoResult( 'Foo', Title::newFromText( 'Foo' ), $empty ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\SearchHooks::onSpecialSearchGoResult + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testSearchHooksFoundDisabled() { + $this->overrideConfigValues( [ + 'PlausibleServerSideTracking' => [ + 'searchfound' => false, + ], + ] ); + + $this->mockQueue->expects( $this->never() )->method( 'push' ); + + $hooks = new SearchHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $empty = null; + + $hooks->onSpecialSearchGoResult( 'Foo', Title::newFromText( 'Foo' ), $empty ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\SearchHooks::onSpecialSearchNogomatch + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testSearchHooksNotFound() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new SearchHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $title = Title::newFromText( 'Foo' ); + + $hooks->onSpecialSearchNogomatch( $title ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\SearchHooks::onSpecialSearchNogomatch + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testSearchHooksNotFoundDisabled() { + $this->overrideConfigValues( [ + 'PlausibleServerSideTracking' => [ + 'searchnotfound' => false, + ], + ] ); + + $this->mockQueue->expects( $this->never() )->method( 'push' ); + + $hooks = new SearchHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $title = Title::newFromText( 'Foo' ); + + $hooks->onSpecialSearchNogomatch( $title ); + } +} diff --git a/tests/phpunit/PlausibleTest.php b/tests/phpunit/PlausibleTest.php new file mode 100644 index 0000000..e5b8983 --- /dev/null +++ b/tests/phpunit/PlausibleTest.php @@ -0,0 +1,127 @@ +overrideConfigValues( [ + 'PlausibleTrackOutboundLinks' => false, + 'PlausibleTrackFileDownloads' => false, + 'PlausibleTrackLoggedIn' => false, + 'PlausibleEnableTaggedEvents' => false, + ] ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Plausible + * @return void + */ + public function testConstructor() { + $plausible = new Plausible( new OutputPage( RequestContext::getMain() ) ); + $this->assertInstanceOf( Plausible::class, $plausible ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Plausible::addScript + * @covers \MediaWiki\Extension\Plausible\Plausible::addModules + * @covers \MediaWiki\Extension\Plausible\Plausible::canAdd + * @return void + */ + public function testScriptGeneration() { + $this->overrideConfigValues( [ + 'PlausibleDomain' => 'localhost', + 'PlausibleDomainKey' => 'localwiki', + ] ); + + $page = new OutputPage( RequestContext::getMain() ); + $plausible = new Plausible( $page ); + $plausible->addModules(); + $plausible->addScript(); + + $this->assertArrayHasKey( 'plausible', $page->getHeadItemsArray() ); + $this->assertStringContainsString( 'script.pageview-props.js', $page->getHeadItemsArray()['plausible'] ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Plausible::addScript + * @covers \MediaWiki\Extension\Plausible\Plausible::addModules + * @covers \MediaWiki\Extension\Plausible\Plausible::canAdd + * @return void + */ + public function testNoScriptGeneration() { + $this->overrideConfigValues( [ + 'PlausibleDomain' => null, + 'PlausibleDomainKey' => null, + ] ); + + $this->expectWarning(); + + $page = new OutputPage( RequestContext::getMain() ); + $plausible = new Plausible( $page ); + $plausible->addModules(); + $plausible->addScript(); + + $this->assertArrayNotHasKey( 'plausible', $page->getHeadItemsArray() ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Plausible::addScript + * @covers \MediaWiki\Extension\Plausible\Plausible::addModules + * @covers \MediaWiki\Extension\Plausible\Plausible::canAdd + * @return void + */ + public function testCustomScriptGeneration() { + $this->overrideConfigValues( [ + 'PlausibleDomain' => 'localhost', + 'PlausibleDomainKey' => 'localwiki', + 'PlausibleTrackFileDownloads' => true, + ] ); + + $page = new OutputPage( RequestContext::getMain() ); + $plausible = new Plausible( $page ); + $plausible->addModules(); + $plausible->addScript(); + + $this->assertArrayHasKey( 'plausible', $page->getHeadItemsArray() ); + $script = $page->getHeadItemsArray()['plausible']; + + $this->assertStringContainsString( 'script.pageview-props', $script ); + $this->assertStringContainsString( 'file-downloads', $script ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Plausible::addScript + * @covers \MediaWiki\Extension\Plausible\Plausible::addModules + * @covers \MediaWiki\Extension\Plausible\Plausible::canAdd + * @return void + */ + public function testIgnoredTitles() { + $this->overrideConfigValues( [ + 'PlausibleDomain' => 'localhost', + 'PlausibleDomainKey' => 'localwiki', + 'PlausibleIgnoredTitles' => [ 'Main Page', 'Foo' ], + ] ); + + $page = new OutputPage( RequestContext::getMain() ); + $plausible = new Plausible( $page ); + $plausible->addModules(); + $plausible->addScript(); + + $this->assertArrayHasKey( 'plausible', $page->getHeadItemsArray() ); + $script = $page->getHeadItemsArray()['plausible']; + + $this->assertStringContainsString( 'exclusions', $script ); + $this->assertStringContainsString( 'data-exclude="Main Page, Foo"', $script ); + } +} From 2f50cbbf76148f6e22000145fda187570222cb44 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Fri, 18 Aug 2023 09:48:29 +0200 Subject: [PATCH 14/22] feat: Add job tests --- tests/phpunit/PlausibleEventJobTest.php | 224 ++++++++++++++++++++++++ tests/phpunit/PlausibleTest.php | 38 ++++ 2 files changed, 262 insertions(+) create mode 100644 tests/phpunit/PlausibleEventJobTest.php diff --git a/tests/phpunit/PlausibleEventJobTest.php b/tests/phpunit/PlausibleEventJobTest.php new file mode 100644 index 0000000..f03ee8c --- /dev/null +++ b/tests/phpunit/PlausibleEventJobTest.php @@ -0,0 +1,224 @@ +assertInstanceOf( PlausibleEventJob::class, $job ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * @return void + * @throws MWException + */ + public function testCreateFromRequest() { + $session = SessionManager::singleton()->getEmptySession(); + $session->setUser( User::createNew( 'FromRequestUser' ) ); + + $title = Title::newFromText( 'Foo' ); + + $request = new FauxRequest( [], false, $session, 'https' ); + $request->setRequestURL( $title->getLinkURL() ); + + $job = PlausibleEventJob::newFromRequest( $request ); + + $this->assertInstanceOf( PlausibleEventJob::class, $job ); + $this->assertStringEndsWith( '/Foo', $job->params['url'] ); + $this->assertFalse( $job->params['isAnon'] ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * @return void + */ + public function testCreateFromRequestNullJob() { + $job = PlausibleEventJob::newFromRequest( new FauxRequest() ); + + $this->assertInstanceOf( NullJob::class, $job ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * @return void + * @throws MWException + */ + public function testNotRunMissingAgent() { + $session = SessionManager::singleton()->getEmptySession(); + $session->setUser( User::createNew( 'NotRunMissingAgent' ) ); + + $title = Title::newFromText( 'Foo' ); + + $request = new FauxRequest( [], false, $session, 'https' ); + $request->setRequestURL( $title->getLinkURL() ); + + $job = PlausibleEventJob::newFromRequest( $request ); + + $this->assertInstanceOf( PlausibleEventJob::class, $job ); + $this->assertStringEndsWith( '/Foo', $job->params['url'] ); + $this->assertFalse( $job->params['isAnon'] ); + + $this->assertFalse( $job->run() ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::run + * @return void + * @throws MWException + * @throws Exception + */ + public function testRun() { + $this->overrideConfigValues( [ + 'PlausibleTrackLoggedIn' => true, + ] ); + + $session = SessionManager::singleton()->getEmptySession(); + $session->setUser( User::createNew( 'Run' ) ); + + $title = Title::newFromText( 'Foo' ); + + $request = new FauxRequest( [], false, $session, 'https' ); + $request->setRequestURL( $title->getLinkURL() ); + $request->setHeader( 'User-Agent', 'Foo-Agent' ); + + $fac = $this->getMockBuilder( HttpRequestFactory::class ) + ->disableOriginalConstructor() + ->onlyMethods( [ 'create' ] ) + ->getMock(); + + $this->getServiceContainer()->redefineService( 'HttpRequestFactory', function () use ( $fac ) { + return $fac; + } ); + + $req = $this->getMockBuilder( MWHttpRequest::class ) + ->disableOriginalConstructor() + ->onlyMethods( [ 'setHeader', 'execute' ] ) + ->getMock(); + + $req->expects( $this->once() )->method( 'execute' )->willReturn( Status::newGood() ); + $fac->expects( $this->once() )->method( 'create' )->willReturn( $req ); + + $job = PlausibleEventJob::newFromRequest( $request ); + + $this->assertInstanceOf( PlausibleEventJob::class, $job ); + $this->assertStringEndsWith( '/Foo', $job->params['url'] ); + $this->assertFalse( $job->params['isAnon'] ); + $this->assertTrue( $job->run() ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::run + * @return void + * @throws MWException + * @throws Exception + */ + public function testRunAnon() { + $this->overrideConfigValues( [ + 'PlausibleTrackLoggedIn' => false, + ] ); + + $session = SessionManager::singleton()->getEmptySession(); + $session->setUser( User::newFromSession() ); + + $title = Title::newFromText( 'Foo' ); + + $request = new FauxRequest( [], false, $session, 'https' ); + $request->setRequestURL( $title->getLinkURL() ); + $request->setHeader( 'User-Agent', 'Foo-Agent' ); + + $fac = $this->getMockBuilder( HttpRequestFactory::class ) + ->disableOriginalConstructor() + ->onlyMethods( [ 'create' ] ) + ->getMock(); + + $this->getServiceContainer()->redefineService( 'HttpRequestFactory', function () use ( $fac ) { + return $fac; + } ); + + $req = $this->getMockBuilder( MWHttpRequest::class ) + ->disableOriginalConstructor() + ->onlyMethods( [ 'setHeader', 'execute' ] ) + ->getMock(); + + $req->expects( $this->once() )->method( 'execute' )->willReturn( Status::newGood() ); + $fac->expects( $this->once() )->method( 'create' )->willReturn( $req ); + + $job = PlausibleEventJob::newFromRequest( $request ); + + $this->assertInstanceOf( PlausibleEventJob::class, $job ); + $this->assertStringEndsWith( '/Foo', $job->params['url'] ); + $this->assertTrue( $job->params['isAnon'] ); + $this->assertTrue( $job->run() ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::run + * @return void + * @throws MWException + * @throws Exception + */ + public function testNotRunLoggedInUser() { + $this->overrideConfigValues( [ + 'PlausibleTrackLoggedIn' => false, + ] ); + + $session = SessionManager::singleton()->getEmptySession(); + $session->setUser( User::createNew( 'NotRunLoggedInUser' ) ); + + $title = Title::newFromText( 'Foo' ); + + $request = new FauxRequest( [], false, $session, 'https' ); + $request->setRequestURL( $title->getLinkURL() ); + $request->setHeader( 'User-Agent', 'Foo-Agent' ); + + $fac = $this->getMockBuilder( HttpRequestFactory::class ) + ->disableOriginalConstructor() + ->onlyMethods( [ 'create' ] ) + ->getMock(); + + $this->getServiceContainer()->redefineService( 'HttpRequestFactory', function () use ( $fac ) { + return $fac; + } ); + + $req = $this->getMockBuilder( MWHttpRequest::class ) + ->disableOriginalConstructor() + ->onlyMethods( [ 'setHeader', 'execute' ] ) + ->getMock(); + + $req->expects( $this->never() )->method( 'execute' ); + $fac->expects( $this->never() )->method( 'create' ); + + $job = PlausibleEventJob::newFromRequest( $request ); + + $this->assertInstanceOf( PlausibleEventJob::class, $job ); + $this->assertStringEndsWith( '/Foo', $job->params['url'] ); + + $this->assertFalse( $job->params['isAnon'] ); + $this->assertTrue( $job->run() ); + } +} diff --git a/tests/phpunit/PlausibleTest.php b/tests/phpunit/PlausibleTest.php index e5b8983..63bf9d0 100644 --- a/tests/phpunit/PlausibleTest.php +++ b/tests/phpunit/PlausibleTest.php @@ -34,6 +34,9 @@ public function testConstructor() { /** * @covers \MediaWiki\Extension\Plausible\Plausible::addScript + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScript + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScriptAttribs + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScriptPath * @covers \MediaWiki\Extension\Plausible\Plausible::addModules * @covers \MediaWiki\Extension\Plausible\Plausible::canAdd * @return void @@ -55,6 +58,9 @@ public function testScriptGeneration() { /** * @covers \MediaWiki\Extension\Plausible\Plausible::addScript + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScript + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScriptAttribs + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScriptPath * @covers \MediaWiki\Extension\Plausible\Plausible::addModules * @covers \MediaWiki\Extension\Plausible\Plausible::canAdd * @return void @@ -77,6 +83,9 @@ public function testNoScriptGeneration() { /** * @covers \MediaWiki\Extension\Plausible\Plausible::addScript + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScript + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScriptAttribs + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScriptPath * @covers \MediaWiki\Extension\Plausible\Plausible::addModules * @covers \MediaWiki\Extension\Plausible\Plausible::canAdd * @return void @@ -102,6 +111,9 @@ public function testCustomScriptGeneration() { /** * @covers \MediaWiki\Extension\Plausible\Plausible::addScript + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScript + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScriptAttribs + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScriptPath * @covers \MediaWiki\Extension\Plausible\Plausible::addModules * @covers \MediaWiki\Extension\Plausible\Plausible::canAdd * @return void @@ -124,4 +136,30 @@ public function testIgnoredTitles() { $this->assertStringContainsString( 'exclusions', $script ); $this->assertStringContainsString( 'data-exclude="Main Page, Foo"', $script ); } + + /** + * @covers \MediaWiki\Extension\Plausible\Plausible::addScript + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScript + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScriptAttribs + * @covers \MediaWiki\Extension\Plausible\Plausible::buildScriptPath + * @covers \MediaWiki\Extension\Plausible\Plausible::addModules + * @covers \MediaWiki\Extension\Plausible\Plausible::canAdd + * @return void + */ + public function testAddModule() { + $this->overrideConfigValues( [ + 'PlausibleDomain' => 'localhost', + 'PlausibleDomainKey' => 'localwiki', + 'PlausibleTrack404' => true, + ] ); + + $page = new OutputPage( RequestContext::getMain() ); + $plausible = new Plausible( $page ); + $plausible->addModules(); + $plausible->addScript(); + + $this->assertArrayHasKey( 'plausible', $page->getHeadItemsArray() ); + + $this->assertContainsEquals( 'ext.plausible.scripts.track-404', $page->getModules() ); + } } From 8a034fa665326dd90b45de13fc341c63cffb6cc4 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Fri, 18 Aug 2023 13:43:23 +0200 Subject: [PATCH 15/22] feat: Add lint jobs --- .github/workflows/lint-check.yml | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/lint-check.yml diff --git a/.github/workflows/lint-check.yml b/.github/workflows/lint-check.yml new file mode 100644 index 0000000..c2be628 --- /dev/null +++ b/.github/workflows/lint-check.yml @@ -0,0 +1,38 @@ +name: Lint Tests +on: + push: + branches: [ master, develop, feature/** ] + pull_request: + branches: [ master ] +jobs: + lint-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Installing PHP + uses: shivammathur/setup-php@master + with: + php-version: '8.0' + - name: Get Composer Cache Directory 2 + id: composer-cache + run: | + echo "::set-output name=dir::$(composer config cache-files-dir)" + - uses: actions/cache@v3 + id: actions-cache + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- + - name: Cache PHP dependencies + uses: actions/cache@v3 + id: vendor-cache + with: + path: vendor + key: ${{ runner.OS }}-build-${{ hashFiles('**/composer.lock') }} + - name: Composer install + if: steps.vendor-cache.outputs.cache-hit != 'true' + run: composer install --no-ansi --no-interaction --no-scripts --no-suggest --prefer-dist + - name: Run Test + run: composer run test From db158e47819160517d66f9ff236db0c66ebfd428 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Fri, 18 Aug 2023 13:53:18 +0200 Subject: [PATCH 16/22] refactor: Make linter happy --- includes/Hooks/FileHooks.php | 8 +++++++- includes/Hooks/PageHooks.php | 16 ++++++++++++++-- includes/Hooks/SearchHooks.php | 4 ++++ includes/Hooks/UserHooks.php | 4 ++++ includes/OptOut.php | 3 ++- includes/Plausible.php | 3 +++ includes/PlausibleEventJob.php | 3 +++ includes/PlausibleLua.php | 12 ++++++++---- includes/PlausiblePageViewService.php | 3 +++ 9 files changed, 48 insertions(+), 8 deletions(-) diff --git a/includes/Hooks/FileHooks.php b/includes/Hooks/FileHooks.php index ec28fe9..4e83119 100644 --- a/includes/Hooks/FileHooks.php +++ b/includes/Hooks/FileHooks.php @@ -15,6 +15,10 @@ class FileHooks implements UploadCompleteHook, FileDeleteCompleteHook, FileUndel private array $config; private JobQueueGroup $jobs; + /** + * @param Config $config + * @param JobQueueGroup $group + */ public function __construct( Config $config, JobQueueGroup $group ) { $this->config = $config->get( 'PlausibleServerSideTracking' ); $this->jobs = $group; @@ -39,7 +43,9 @@ public function onUploadComplete( $uploadBase ): void { return; } - $this->jobs->push( PlausibleEventJob::newFromRequest( RequestContext::getMain()->getRequest(), 'File: Upload' ) ); + $this->jobs->push( + PlausibleEventJob::newFromRequest( RequestContext::getMain()->getRequest(), 'File: Upload' ) + ); } /** diff --git a/includes/Hooks/PageHooks.php b/includes/Hooks/PageHooks.php index 5010acd..7d15f36 100644 --- a/includes/Hooks/PageHooks.php +++ b/includes/Hooks/PageHooks.php @@ -37,11 +37,21 @@ /** * Hooks to run relating the page */ -class PageHooks implements BeforePageDisplayHook, PageSaveCompleteHook, ArticleDeleteAfterSuccessHook, ArticleUndeleteHook, PageMoveCompleteHook { +class PageHooks implements + BeforePageDisplayHook, + PageSaveCompleteHook, + ArticleDeleteAfterSuccessHook, + ArticleUndeleteHook, + PageMoveCompleteHook +{ private array $config; private JobQueueGroup $jobs; + /** + * @param Config $config + * @param JobQueueGroup $group + */ public function __construct( Config $config, JobQueueGroup $group ) { $this->config = $config->get( 'PlausibleServerSideTracking' ); $this->jobs = $group; @@ -110,7 +120,9 @@ public function onArticleUndelete( $title, $create, $comment, $oldPageId, $resto return; } - $this->jobs->push( PlausibleEventJob::newFromRequest( RequestContext::getMain()->getRequest(), 'Page: Undelete' ) ); + $this->jobs->push( + PlausibleEventJob::newFromRequest( RequestContext::getMain()->getRequest(), 'Page: Undelete' ) + ); } /** diff --git a/includes/Hooks/SearchHooks.php b/includes/Hooks/SearchHooks.php index 3641db9..87e5204 100644 --- a/includes/Hooks/SearchHooks.php +++ b/includes/Hooks/SearchHooks.php @@ -14,6 +14,10 @@ class SearchHooks implements SpecialSearchNogomatchHook, SpecialSearchGoResultHo private array $config; private JobQueueGroup $jobs; + /** + * @param Config $config + * @param JobQueueGroup $group + */ public function __construct( Config $config, JobQueueGroup $group ) { $this->config = $config->get( 'PlausibleServerSideTracking' ); $this->jobs = $group; diff --git a/includes/Hooks/UserHooks.php b/includes/Hooks/UserHooks.php index 63909ac..b55183a 100644 --- a/includes/Hooks/UserHooks.php +++ b/includes/Hooks/UserHooks.php @@ -14,6 +14,10 @@ class UserHooks implements LocalUserCreatedHook, UserLogoutCompleteHook, UserLog private array $config; private JobQueueGroup $jobs; + /** + * @param Config $config + * @param JobQueueGroup $group + */ public function __construct( Config $config, JobQueueGroup $group ) { $this->config = $config->get( 'PlausibleServerSideTracking' ); $this->jobs = $group; diff --git a/includes/OptOut.php b/includes/OptOut.php index 886d8f6..853a0bc 100644 --- a/includes/OptOut.php +++ b/includes/OptOut.php @@ -10,9 +10,10 @@ class OptOut { /** * * + * @param string|null $input + * @param array $args Arguments * @param Parser $parser The active Parser instance * @param PPFrame $frame Frame - * @param array $args Arguments * * @return string The button */ diff --git a/includes/Plausible.php b/includes/Plausible.php index 24df27d..55c1b97 100644 --- a/includes/Plausible.php +++ b/includes/Plausible.php @@ -52,6 +52,9 @@ class Plausible { */ private $config; + /** + * @param OutputPage $out + */ public function __construct( OutputPage $out ) { $this->out = $out; $this->config = MediaWikiServices::getInstance()->getConfigFactory()->makeConfig( 'Plausible' ); diff --git a/includes/PlausibleEventJob.php b/includes/PlausibleEventJob.php index db80c44..97801b3 100644 --- a/includes/PlausibleEventJob.php +++ b/includes/PlausibleEventJob.php @@ -17,6 +17,9 @@ class PlausibleEventJob extends Job implements GenericParameterJob { protected $removeDuplicates = true; + /** + * @param array $params + */ public function __construct( array $params ) { parent::__construct( 'PlausibleEvent', $params ); } diff --git a/includes/PlausibleLua.php b/includes/PlausibleLua.php index 191ca6a..415af1a 100644 --- a/includes/PlausibleLua.php +++ b/includes/PlausibleLua.php @@ -26,6 +26,9 @@ use MediaWiki\Title\Title; use Scribunto_LuaLibraryBase; +/** + * phpcs:disable MediaWiki.Commenting.FunctionComment.ExtraParamComment + */ class PlausibleLua extends Scribunto_LuaLibraryBase { /** @@ -45,7 +48,7 @@ public function register() { /** * The top pages in the last day (or specified days) for this site * - * @param $days int optional Number of days to calculate the top pages over + * @param int $days optional Number of days to calculate the top pages over * * @return array|array[] */ @@ -85,7 +88,7 @@ public function getTopPages(): array { /** * Number of views for whole site * - * @param $days int optional Number of days for returning the views + * @param int $days optional Number of days for returning the views * * @return array */ @@ -107,8 +110,9 @@ public function getSiteData(): array { /** * Number of views for the specified titles * - * @param $titles string|string[] The titles to work on - * @param $days int optional Number of days to calculate the views over + * MediaWiki.Commenting.FunctionComment.ExtraParamComment + * @param string|string[] $titles The titles to work on + * @param int $days optional Number of days to calculate the views over * * @return array */ diff --git a/includes/PlausiblePageViewService.php b/includes/PlausiblePageViewService.php index 6c288c2..bd8f90c 100644 --- a/includes/PlausiblePageViewService.php +++ b/includes/PlausiblePageViewService.php @@ -175,6 +175,9 @@ public function getTopPages( $metric = self::METRIC_VIEW ) { /** * This is getTopPages with a configurable day range + * @param int $days + * @param string $metric One of the METRIC_* constants. + * @return StatusValue */ public function getTopPagesDays( $days = 1, $metric = self::METRIC_VIEW ) { if ( !in_array( $metric, [ self::METRIC_VIEW, self::METRIC_UNIQUE ] ) ) { From 82e8c3a16b311cad633a9022fcbfdc3534c20bfe Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Fri, 18 Aug 2023 13:54:22 +0200 Subject: [PATCH 17/22] refactor: Make linter happy --- includes/Hooks/ScribuntoHooks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Hooks/ScribuntoHooks.php b/includes/Hooks/ScribuntoHooks.php index ee6e8c8..adb1190 100644 --- a/includes/Hooks/ScribuntoHooks.php +++ b/includes/Hooks/ScribuntoHooks.php @@ -30,7 +30,7 @@ class ScribuntoHooks { * Register Lua Library * * @param string $engine - * @param array $extraLibraries + * @param array &$extraLibraries * @return bool */ public static function onScribuntoExternalLibraries( string $engine, array &$extraLibraries ): bool { From 0e7809c563ea93bc28e87a0cb983b31ce675cce7 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Fri, 18 Aug 2023 14:29:34 +0200 Subject: [PATCH 18/22] refactor: Use $GITHUB_OUTPUT --- .github/workflows/lint-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-check.yml b/.github/workflows/lint-check.yml index c2be628..7a04f06 100644 --- a/.github/workflows/lint-check.yml +++ b/.github/workflows/lint-check.yml @@ -17,7 +17,7 @@ jobs: - name: Get Composer Cache Directory 2 id: composer-cache run: | - echo "::set-output name=dir::$(composer config cache-files-dir)" + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - uses: actions/cache@v3 id: actions-cache with: From 578b10161230be9c7ff2ef4e38789ba4f8ee0fe6 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Thu, 24 Aug 2023 12:35:11 +0200 Subject: [PATCH 19/22] ci: Add tests --- extension.json | 3 +- includes/Hooks/UserHooks.php | 3 +- includes/Plausible.php | 3 +- tests/phpunit/Hooks/FileHooksTest.php | 15 +++ tests/phpunit/Hooks/PageHooksTest.php | 90 ++++++++++++++- tests/phpunit/Hooks/ParserHooksTest.php | 66 +++++++++++ tests/phpunit/Hooks/SearchHooksTest.php | 15 +++ tests/phpunit/Hooks/UserHooksTest.php | 140 ++++++++++++++++++++++++ 8 files changed, 329 insertions(+), 6 deletions(-) create mode 100644 tests/phpunit/Hooks/ParserHooksTest.php create mode 100644 tests/phpunit/Hooks/UserHooksTest.php diff --git a/extension.json b/extension.json index 2bc948c..5bdd046 100644 --- a/extension.json +++ b/extension.json @@ -104,7 +104,8 @@ "fileundelete": true, "searchnotfound": true, "searchfound": true - } + }, + "merge_strategy": "array_plus" } }, "ConfigRegistry": { diff --git a/includes/Hooks/UserHooks.php b/includes/Hooks/UserHooks.php index b55183a..5051f0e 100644 --- a/includes/Hooks/UserHooks.php +++ b/includes/Hooks/UserHooks.php @@ -36,6 +36,7 @@ public function onLocalUserCreated( $user, $autocreated ): void { 'User: Register', [ 'user' => $user->isRegistered() ? $user->getName() : null, + 'autocreated' => $autocreated, ] ) ); } @@ -44,7 +45,7 @@ public function onLocalUserCreated( $user, $autocreated ): void { * @inheritDoc */ public function onUserLoginComplete( $user, &$inject_html, $direct ): void { - if ( !$this->config['userlogin'] ) { + if ( !$this->config['userlogin'] || !$direct ) { return; } diff --git a/includes/Plausible.php b/includes/Plausible.php index 55c1b97..88ca66c 100644 --- a/includes/Plausible.php +++ b/includes/Plausible.php @@ -23,7 +23,6 @@ use Config; use ConfigException; -use MediaWiki\MediaWikiServices; use OutputPage; class Plausible { @@ -57,7 +56,7 @@ class Plausible { */ public function __construct( OutputPage $out ) { $this->out = $out; - $this->config = MediaWikiServices::getInstance()->getConfigFactory()->makeConfig( 'Plausible' ); + $this->config = $out->getConfig(); $this->plausibleDomain = $this->getConfigValue( 'PlausibleDomain' ); $this->domainKey = $this->getConfigValue( 'PlausibleDomainKey' ); } diff --git a/tests/phpunit/Hooks/FileHooksTest.php b/tests/phpunit/Hooks/FileHooksTest.php index 221fb0a..b3bcd45 100644 --- a/tests/phpunit/Hooks/FileHooksTest.php +++ b/tests/phpunit/Hooks/FileHooksTest.php @@ -35,6 +35,21 @@ protected function setUp(): void { ->getMock(); } + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\FileHooks + * + * @return void + * @throws Exception + */ + public function testConstructor() { + $hooks = new FileHooks( + $this->getServiceContainer()->getMainConfig(), + $this->getServiceContainer()->getJobQueueGroup() + ); + + $this->assertInstanceOf( FileHooks::class, $hooks ); + } + /** * @covers \MediaWiki\Extension\Plausible\Hooks\FileHooks::onUploadComplete * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest diff --git a/tests/phpunit/Hooks/PageHooksTest.php b/tests/phpunit/Hooks/PageHooksTest.php index babe760..7ead90c 100644 --- a/tests/phpunit/Hooks/PageHooksTest.php +++ b/tests/phpunit/Hooks/PageHooksTest.php @@ -37,6 +37,84 @@ protected function setUp(): void { ->getMock(); } + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks + * + * @return void + * @throws Exception + */ + public function testConstructor() { + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->getServiceContainer()->getJobQueueGroup() + ); + + $this->assertInstanceOf( PageHooks::class, $hooks ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onBeforePageDisplay + * @return void + * @throws Exception + */ + public function testOnBeforePageDisplay() { + $this->overrideConfigValues( [ + 'PlausibleDomain' => 'foo', + 'PlausibleDomainKey' => 'foo', + 'PlausibleTrackLoggedIn' => true, + 'PlausibleHonorDNT' => false, + ] ); + + $out = new OutputPage( RequestContext::getMain() ); + + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onBeforePageDisplay( $out, null ); + + $this->assertArrayHasKey( 'plausible', $out->getHeadItemsArray() ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onBeforePageDisplay + * @return void + * @throws Exception + */ + public function testOnBeforePageDisplayAllModules() { + $this->overrideConfigValues( [ + 'PlausibleDomain' => 'foo', + 'PlausibleDomainKey' => 'foo', + 'PlausibleTrackLoggedIn' => true, + 'PlausibleHonorDNT' => false, + 'PlausibleTrack404' => true, + 'PlausibleTrackSearchInput' => true, + 'PlausibleTrackEditButtonClicks' => true, + 'PlausibleTrackNavplateClicks' => true, + 'PlausibleTrackInfoboxClicks' => true, + 'PlausibleTrackCitizenSearchLinks' => true, + 'PlausibleTrackCitizenMenuLinks' => true, + ] ); + + $out = new OutputPage( RequestContext::getMain() ); + + $hooks = new PageHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $hooks->onBeforePageDisplay( $out, null ); + + $this->assertContains( 'ext.plausible.scripts.track-404', $out->getModules() ); + $this->assertContains( 'ext.plausible.scripts.track-search', $out->getModules() ); + $this->assertContains( 'ext.plausible.scripts.track-edit-btn', $out->getModules() ); + $this->assertContains( 'ext.plausible.scripts.track-navplate-clicks', $out->getModules() ); + $this->assertContains( 'ext.plausible.scripts.track-infobox-clicks', $out->getModules() ); + $this->assertContains( 'ext.plausible.scripts.citizen.track-search-links', $out->getModules() ); + $this->assertContains( 'ext.plausible.scripts.citizen.track-menu-links', $out->getModules() ); + } + /** * @covers \MediaWiki\Extension\Plausible\Hooks\PageHooks::onArticleDeleteAfterSuccess * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest @@ -52,7 +130,10 @@ public function testArticleDeleteAfterSuccess() { $this->mockQueue ); - $hooks->onArticleDeleteAfterSuccess( Title::newFromText( 'Foo' ), new OutputPage( RequestContext::getMain() ) ); + $hooks->onArticleDeleteAfterSuccess( + Title::newFromText( 'Foo' ), + new OutputPage( RequestContext::getMain() ) + ); } /** @@ -76,6 +157,7 @@ public function testPageSaveComplete() { '', 0, $this->getMockBuilder( RevisionRecord::class )->disableOriginalConstructor()->getMock(), + // phpcs:ignore Generic.Files.LineLength.TooLong new EditResult( true, false, null, null, null, false, false, [] ) ); } @@ -154,7 +236,10 @@ public function testArticleDeleteAfterSuccessDisabled() { $this->mockQueue ); - $hooks->onArticleDeleteAfterSuccess( Title::newFromText( 'Foo' ), new OutputPage( RequestContext::getMain() ) ); + $hooks->onArticleDeleteAfterSuccess( + Title::newFromText( 'Foo' ), + new OutputPage( RequestContext::getMain() ) + ); } /** @@ -187,6 +272,7 @@ public function testPageSaveCompleteDisabled() { '', 0, $this->getMockBuilder( RevisionRecord::class )->disableOriginalConstructor()->getMock(), + // phpcs:ignore Generic.Files.LineLength.TooLong new EditResult( true, false, null, null, null, false, false, [] ) ); } diff --git a/tests/phpunit/Hooks/ParserHooksTest.php b/tests/phpunit/Hooks/ParserHooksTest.php new file mode 100644 index 0000000..8c0d251 --- /dev/null +++ b/tests/phpunit/Hooks/ParserHooksTest.php @@ -0,0 +1,66 @@ +assertInstanceOf( ParserHooks::class, $hooks ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\ParserHooks::onParserFirstCallInit + * + * @return void + * @throws Exception + */ + public function testAddOptOut() { + $this->overrideConfigValues( [ + 'PlausibleEnableOptOutTag' => true, + ] ); + + $hooks = new ParserHooks(); + $parser = $this->getServiceContainer()->getParser(); + + $hooks->onParserFirstCallInit( $parser ); + + $this->assertContains( 'plausible-opt-out', $parser->getTags() ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\ParserHooks::onParserFirstCallInit + * + * @return void + * @throws Exception + */ + public function testNotAddOptOut() { + $this->overrideConfigValues( [ + 'PlausibleEnableOptOutTag' => false, + ] ); + + $hooks = new ParserHooks(); + $parser = $this->getServiceContainer()->getParser(); + + $hooks->onParserFirstCallInit( $parser ); + + $this->assertNotContains( 'plausible-opt-out', $parser->getTags() ); + } + +} diff --git a/tests/phpunit/Hooks/SearchHooksTest.php b/tests/phpunit/Hooks/SearchHooksTest.php index b055bcb..e31856b 100644 --- a/tests/phpunit/Hooks/SearchHooksTest.php +++ b/tests/phpunit/Hooks/SearchHooksTest.php @@ -32,6 +32,21 @@ protected function setUp(): void { ->getMock(); } + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\SearchHooks + * + * @return void + * @throws Exception + */ + public function testConstructor() { + $hooks = new SearchHooks( + $this->getServiceContainer()->getMainConfig(), + $this->getServiceContainer()->getJobQueueGroup() + ); + + $this->assertInstanceOf( SearchHooks::class, $hooks ); + } + /** * @covers \MediaWiki\Extension\Plausible\Hooks\SearchHooks::onSpecialSearchGoResult * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest diff --git a/tests/phpunit/Hooks/UserHooksTest.php b/tests/phpunit/Hooks/UserHooksTest.php new file mode 100644 index 0000000..6d12463 --- /dev/null +++ b/tests/phpunit/Hooks/UserHooksTest.php @@ -0,0 +1,140 @@ +overrideConfigValues( [ + 'PlausibleTrackOutboundLinks' => false, + 'PlausibleTrackFileDownloads' => false, + 'PlausibleTrackLoggedIn' => false, + 'PlausibleEnableTaggedEvents' => false, + 'PlausibleServerSideTracking' => [ + 'userregister' => true, + 'userlogin' => true, + 'userlogout' => true, + ] + ] ); + + $this->mockQueue = $this->getMockBuilder( JobQueueGroup::class ) + ->disableOriginalConstructor() + ->onlyMethods( [ 'push' ] ) + ->getMock(); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\UserHooks + * + * @return void + * @throws Exception + */ + public function testConstructor() { + $hooks = new UserHooks( + $this->getServiceContainer()->getMainConfig(), + $this->getServiceContainer()->getJobQueueGroup() + ); + + $this->assertInstanceOf( UserHooks::class, $hooks ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\UserHooks::onLocalUserCreated + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testOnLocalUserCreated() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new UserHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $user = $this->getServiceContainer()->getUserFactory()->newFromName( 'OnLocalUserCreated' ); + + $hooks->onLocalUserCreated( $user, false ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\UserHooks::onUserLoginComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testOnUserLoginComplete() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new UserHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $user = $this->getServiceContainer()->getUserFactory()->newFromName( 'OnUserLoginComplete' ); + + $html = ''; + + $hooks->onUserLoginComplete( $user, $html, true ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\UserHooks::onUserLoginComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testOnUserLoginCompleteNotDirect() { + $this->mockQueue->expects( $this->never() )->method( 'push' ); + + $hooks = new UserHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $user = $this->getServiceContainer()->getUserFactory()->newFromName( 'OnUserLoginComplete' ); + + $html = ''; + + $hooks->onUserLoginComplete( $user, $html, false ); + } + + /** + * @covers \MediaWiki\Extension\Plausible\Hooks\UserHooks::onUserLogoutComplete + * @covers \MediaWiki\Extension\Plausible\PlausibleEventJob::newFromRequest + * + * @return void + * @throws Exception + */ + public function testOnUserLogoutComplete() { + $this->mockQueue->expects( $this->once() )->method( 'push' ); + + $hooks = new UserHooks( + $this->getServiceContainer()->getMainConfig(), + $this->mockQueue + ); + + $user = $this->getServiceContainer()->getUserFactory()->newFromName( 'OnUserLogoutComplete' ); + + $html = ''; + + $hooks->onUserLogoutComplete( $user, $html, '' ); + } + +} From e74aae96861826f8cc14b828203d55661b69122e Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Tue, 3 Oct 2023 20:20:14 +0200 Subject: [PATCH 20/22] fix: Fix loading pageservice when api key is empty --- includes/Hooks/MediaWikiServices.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/includes/Hooks/MediaWikiServices.php b/includes/Hooks/MediaWikiServices.php index 94c335c..fa47de5 100644 --- a/includes/Hooks/MediaWikiServices.php +++ b/includes/Hooks/MediaWikiServices.php @@ -15,7 +15,8 @@ class MediaWikiServices implements MediaWikiServicesHook { * @inheritDoc */ public function onMediaWikiServices( $services ): void { - if ( !ExtensionRegistry::getInstance()->isLoaded( 'PageViewInfo' ) ) { + if ( !ExtensionRegistry::getInstance()->isLoaded( 'PageViewInfo' ) || + empty( $services->getMainConfig()->get( 'PlausibleApiKey' ) ) ) { return; } From b67c9739831f37c203174cefd34bfb516f5f9345 Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Thu, 14 Dec 2023 09:18:28 +0100 Subject: [PATCH 21/22] ci: Add missing db group --- tests/phpunit/Hooks/FileHooksTest.php | 1 + tests/phpunit/Hooks/PageHooksTest.php | 1 + tests/phpunit/Hooks/UserHooksTest.php | 1 + 3 files changed, 3 insertions(+) diff --git a/tests/phpunit/Hooks/FileHooksTest.php b/tests/phpunit/Hooks/FileHooksTest.php index b3bcd45..cc40d08 100644 --- a/tests/phpunit/Hooks/FileHooksTest.php +++ b/tests/phpunit/Hooks/FileHooksTest.php @@ -15,6 +15,7 @@ /** * @group Plausible + * @group Database */ class FileHooksTest extends MediaWikiIntegrationTestCase { private $mockQueue; diff --git a/tests/phpunit/Hooks/PageHooksTest.php b/tests/phpunit/Hooks/PageHooksTest.php index 7ead90c..736bcbe 100644 --- a/tests/phpunit/Hooks/PageHooksTest.php +++ b/tests/phpunit/Hooks/PageHooksTest.php @@ -17,6 +17,7 @@ /** * @group Plausible + * @group Database */ class PageHooksTest extends MediaWikiIntegrationTestCase { private $mockQueue; diff --git a/tests/phpunit/Hooks/UserHooksTest.php b/tests/phpunit/Hooks/UserHooksTest.php index 6d12463..441e0f9 100644 --- a/tests/phpunit/Hooks/UserHooksTest.php +++ b/tests/phpunit/Hooks/UserHooksTest.php @@ -11,6 +11,7 @@ /** * @group Plausible + * @group Database */ class UserHooksTest extends MediaWikiIntegrationTestCase { private $mockQueue; From 35424f8a5b3b8c077af632eabd67c10c0992545f Mon Sep 17 00:00:00 2001 From: "H. C. Kruse" Date: Thu, 14 Dec 2023 09:29:21 +0100 Subject: [PATCH 22/22] dist: Bump version to 1.4.0 --- README.md | 1 + composer.json | 2 +- extension.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6111ee7..3da728e 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ Some events can be sent serverside without having to rely on the included plausi The following custom events can be activated: ```php +# Default Configuration $wgPlausibleServerSideTracking = [ // Event Name: pageview 'pageview' => false, diff --git a/composer.json b/composer.json index c7d5b09..c4c959d 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "octfx/plausible", - "version": "1.3.1", + "version": "1.4.0", "type": "mediawiki-extension", "description": "Integrates plausible analytics", "homepage": "https://www.mediawiki.org/wiki/Extension:Plausible", diff --git a/extension.json b/extension.json index 5bdd046..f501819 100644 --- a/extension.json +++ b/extension.json @@ -1,6 +1,6 @@ { "name": "Plausible", - "version": "1.3.1", + "version": "1.4.0", "author": [ "[https://www.mediawiki.org/wiki/User:Octfx Octfx]" ],