jenkins-bot has submitted this change and it was merged.

Change subject: Initial commit
......................................................................


Initial commit

Change-Id: I6e67772c1cc25092099eca1307313bd10bcd101f
---
A GoogleAnalyticsTopPages.php
A i18n/en.json
A i18n/qqq.json
A includes/GoogleAnalyticsTopPages.body.php
A includes/GoogleAnalyticsTopPages.hooks.php
A includes/api/ApiGooglePageStatsUpdate.php
A includes/specials/SpecialGoogleAnalyticsTopPages.php
A includes/sql/page_google_stats.sql
8 files changed, 415 insertions(+), 0 deletions(-)

Approvals:
  Florianschmidtwelzow: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/GoogleAnalyticsTopPages.php b/GoogleAnalyticsTopPages.php
new file mode 100644
index 0000000..e6f90c0
--- /dev/null
+++ b/GoogleAnalyticsTopPages.php
@@ -0,0 +1,113 @@
+<?php
+       /**
+       GoogleAnalyticsTopPages License
+       Copyright (c) 2014 Florian Schmidt
+
+       Permission is hereby granted, free of charge, to any person obtaining a 
copy
+       of this software and associated documentation files (the "Software"), 
to deal
+       in the Software without restriction, including without limitation the 
rights
+       to use, copy, modify, merge, publish, distribute, sublicense, and/or 
sell
+       copies of the Software, and to permit persons to whom the Software is
+       furnished to do so, subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be included 
in all
+       copies or substantial portions of the Software.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
OR
+       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+       FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
THE
+       AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+       LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
IN THE
+       SOFTWARE.
+       */
+
+       if ( !defined( 'MEDIAWIKI' ) ) {
+               die( 'This is an extension for Mediawiki and can not run 
standalone.' );
+       }
+
+       $wgExtensionCredits['parserhook'][] = array(
+               'path' => __FILE__,
+               'name' => 'GoogleAnayltcisTopPages',
+               'author' => 'Florian Schmidt',
+               'url' => 
'https://www.mediawiki.org/wiki/Extension:GoogleAnalyticsTopPages',
+               'descriptionmsg' => 'googleanalyticstoppages-description',
+               'version'  => '0.0.1',
+               'license-name' => "MIT",
+       );
+
+       $dir = __DIR__;
+
+       // Messages
+       $wgMessagesDirs['MobileFrontend'] = $dir . '/i18n';
+
+       // Autoload Classes
+       $wgAutoloadClasses[ 'GoogleAnalyticsTopPages' ] =
+               $dir . '/includes/GoogleAnalyticsTopPages.body.php';
+       $wgAutoloadClasses[ 'GoogleAnalyticsTopPagesHooks' ] =
+               $dir . '/includes/GoogleAnalyticsTopPages.hooks.php';
+       $wgAutoloadClasses[ 'SpecialGoogleAnalyticsTopPages' ] =
+               $dir . '/includes/specials/SpecialGoogleAnalyticsTopPages.php';
+       $wgAutoloadClasses[ 'ApiGooglePageStatsUpdate' ] =
+               $dir . '/includes/api/ApiGooglePageStatsUpdate.php';
+
+       // Special Page
+       $wgSpecialPageGroups[ 'GoogleAnalyticsTopPages' ] = 'other';
+       $wgSpecialPages[ 'GoogleAnalyticsTopPages' ] = 
'SpecialGoogleAnalyticsTopPages';
+
+       // API Modules
+       $wgAPIModules['googlepagestatsupdate'] = 'ApiGooglePageStatsUpdate';
+
+       // Hooks
+       $wgHooks['LoadExtensionSchemaUpdates'][] =
+               'GoogleAnalyticsTopPagesHooks::onLoadExtensionSchemaUpdates';
+       $wgHooks['ParserFirstCallInit'][] = 
'GoogleAnalyticsTopPagesHooks::onParserFirstCallInit';
+
+       // Configuration variables
+
+       /**
+        * Service account name of the service account to use for api requests 
(to Google Analytics API).
+        * Can be found in Google Developer console.
+        *
+        * @var string
+        */
+       $wgGATPServiceAccountName = '';
+
+       /**
+        * Absolute path to certificate file to access the service account. Can 
be downloaded
+        * from Google Developer console. Be sure to put the certificate 
somewhere, where only
+        * you can access it! ({wikiroot}/ isn't a good idea!)
+        *
+        * @var string
+        */
+       $wgGATPKeyFileLocation = '';
+
+       /**
+        * Optional name of this api app.
+        *
+        * @var string
+        */
+       $wgGATPAppName = "googleanalyticstoppages";
+
+       /**
+        * Google Analytics profile id to get the data from. Your service 
account need to have at
+        * least read access to access the data. The profile ID isn't the 
UA-XXXX string!
+        *
+        * @var string
+        */
+       $wgGATPProfileId = '';
+
+       /**
+        * Interval in days (from today) to get visitor data.
+        *
+        * @var integer
+        */
+       $wgGATPInterval = 30;
+
+       /**
+        * To protect the API against anonymous calls, you can set this to 
true. You will need to
+        * transmit $wgSecretKey in your request to authenticate the call als 
valid.
+        *
+        * @var boolean
+        */
+       $wgGATPProtectAPI = true;
diff --git a/i18n/en.json b/i18n/en.json
new file mode 100644
index 0000000..3882293
--- /dev/null
+++ b/i18n/en.json
@@ -0,0 +1,9 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Florian Schmidt"
+               ]
+       },
+       "googleanalyticstoppages-description": "Provides a top pages list with 
the use of Google Analytics data.",
+       "apihelp-googlepagestatsupdate-param-key": "Value of 
[[mw:Manual:$wgSecretKey|$wgSecretKey]]"
+}
diff --git a/i18n/qqq.json b/i18n/qqq.json
new file mode 100644
index 0000000..a7aa6d5
--- /dev/null
+++ b/i18n/qqq.json
@@ -0,0 +1,9 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Florian Schmidt"
+               ]
+       },
+       "googleanalyticstoppages-description": "Description of this Extension.",
+       "apihelp-googlepagestatsupdate-param-key": "Help text for API parameter 
key."
+}
diff --git a/includes/GoogleAnalyticsTopPages.body.php 
b/includes/GoogleAnalyticsTopPages.body.php
new file mode 100644
index 0000000..4f2b50f
--- /dev/null
+++ b/includes/GoogleAnalyticsTopPages.body.php
@@ -0,0 +1,159 @@
+<?php
+       class GoogleAnalyticsTopPages {
+               public static function getData( WebRequest $request ) {
+                       global $wgGATPServiceAccountName, 
$wgGATPKeyFileLocation, $wgGATPAppName,
+                               $wgGATPProfileId, $wgGATPInterval;
+
+                       // create a new Google_Client object
+                       $client = new Google_Client();
+                       // set app name
+                       $client->setApplicationName( $wgGATPAppName );
+                       // Create the needed Google Analytics service object
+                       $service = new Google_Service_Analytics( $client );
+
+                       // check, if the client is already authenticated
+                       if ( $request->getSessionData( 'service_token' ) !== 
null ) {
+                               $client->setAccessToken( 
$request->getSessionData( 'service_token' ) );
+                       }
+
+                       // load the certificate key file
+                       $key = file_get_contents( $wgGATPKeyFileLocation );
+                       // create the service account credentials
+                       $cred = new Google_Auth_AssertionCredentials(
+                               $wgGATPServiceAccountName,
+                               array( 
'https://www.googleapis.com/auth/analytics.readonly' ),
+                               $key
+                       );
+                       // set the credentials
+                       $client->setAssertionCredentials( $cred );
+                       if ( $client->getAuth()->isAccessTokenExpired() ) {
+                               // authenticate the service account
+                               $client->getAuth()->refreshTokenWithAssertion( 
$cred );
+                       }
+                       // set the service_token to the session for future 
requests
+                       $request->setSessionData( 'service_token', 
$client->getAccessToken() );
+
+                       // get the start and end time for the request
+                       $startTime = date( 'Y-m-d', time() - $wgGATPInterval * 
86400 );
+                       $endTime = date( 'Y-m-d', time() );
+
+                       // do the request to Google Analytics
+                       $response = $service->data_ga->get(
+                               'ga:' . $wgGATPProfileId,
+                               $startTime,
+                               $endTime,
+                               'ga:pageviews,ga:exits',
+                               array(
+                                       'dimensions' => 'ga:pagePath',
+                                       'max-results' => 10,
+                                       'sort' => '-ga:pageviews'
+                               )
+                       );
+
+                       // our response array
+                       $titles = array();
+                       foreach( $response['rows'] as $row ) {
+                               // try to get an actual title object of the 
returned pagePath
+                               $title = self::makeTitle( $row[0] );
+                               if ( $title ) {
+                                       $titles[] = array(
+                                               'page_title' => 
$title->getText(),
+                                               'page_visitors' => $row[1]
+                                       );
+                               }
+                       }
+
+                       return $titles;
+               }
+
+               public static function makeTitle( $text ) {
+                       global $wgArticlePath;
+
+                       // try to make a Title object without modifications
+                       $title = Title::newFromText( $text );
+                       if ( $title instanceof Title && $title->exists() ) {
+                               return $title;
+                       }
+
+                       // remove $wgArticle
+                       $article = str_replace( '$1', '', $wgArticlePath );
+                       $text = str_replace( $article, '', $text );
+                       $title = Title::newFromText( $text );
+                       if ( $title instanceof Title && $title->exists() ) {
+                               return $title;
+                       }
+
+                       // try parse_url and parse_str (maybe it's an 
index.php?title=Page construct)
+                       $url = parse_url( $text );
+                       if ( isset( $url['query'] ) ) {
+                               parse_str( $url['query'], $query );
+                               if ( isset( $query['title'] ) ) {
+                                       $title = Title::newFromText( 
$query['title'] );
+                                       if ( $title instanceof Title && 
$title->exists() ) {
+                                               return $title;
+                                       }
+                               }
+                       }
+
+                       return false;
+               }
+
+               /**
+                * Render the content which should be added with the 
gatp-parser tag
+                *
+                * @param string $input Inout between the tags
+                * @param array $args Tag arguments
+                * @param Parser $parser The parser object which is parsing the 
page with the tag
+                * @param PPFrame $frame The parent frame object
+                *
+                * @return string
+                */
+               public static function renderParserTag( $input, array $args, 
Parser $parser, PPFrame $frame ) {
+                       $dbw = wfGetDB( DB_SLAVE );
+                       $result = '';
+
+                       // get the actual list of top pages
+                       $res = $dbw->select(
+                               'page_google_stats',
+                               array(
+                                       'page_title',
+                                       'page_visitors'
+                               ),
+                               '',
+                               __METHOD__,
+                               array(
+                                       // FIXME: Should be configurable
+                                       'LIMIT' => '10',
+                                       'ORDER BY' => 'page_visitors DESC'
+                               )
+                       );
+
+                       // if there was an error or no rows, return empty string
+                       if ( !$res ) {
+                               return '';
+                       }
+
+                       // build the list of top pages
+                       $result .= Html::openElement( 'ol', array( 'class' => 
'special' ) );
+                       foreach( $res as $value ) {
+                               $title = Title::newFromText( $value->page_title 
);
+                               if ( $title->exists() ) {
+                                       $result .= self::makeListItem( $title );
+                               }
+                       }
+                       $result .= Html::closeElement( 'ol' );
+
+                       return $result;
+               }
+
+               /**
+                * Creates a list item (<li>) with a link. Label and location 
comes from the title object.
+                *
+                * @param Title $title Title object to get information from
+                * @return string Formatted HTML
+                */
+               private static function makeListItem( Title $title ) {
+                       return Html::rawElement( 'li', array(),
+                               Linker::linkKnown( $title, $title->getText() ) 
);
+               }
+       }
diff --git a/includes/GoogleAnalyticsTopPages.hooks.php 
b/includes/GoogleAnalyticsTopPages.hooks.php
new file mode 100644
index 0000000..98aa44b
--- /dev/null
+++ b/includes/GoogleAnalyticsTopPages.hooks.php
@@ -0,0 +1,46 @@
+<?php
+       class GoogleAnalyticsTopPagesHooks {
+               /**
+                * LoadExtensionSchemaUpdate Hook handler
+                * @see 
https://www.mediawiki.org/wiki/Manual:Hooks/LoadExtensionSchemaUpdate
+                */
+               public static function onLoadExtensionSchemaUpdates( $updater = 
null ) {
+                       global $wgDBname, $wgSharedDB, $wgDBtype;
+
+                       // Don't create tables on a shared database
+                       if(
+                               !empty( $wgSharedDB ) &&
+                               $wgSharedDB !== $wgDBname
+                       ) {
+                               return true;
+                       }
+                       // Tables to add to the database
+                       $tables = array( 'page_google_stats' );
+                       // Sql directory inside the extension folder
+                       $sql = dirname( __FILE__ ) . '/sql';
+                       // Extension of the table schema file (depending on the 
database type)
+                       switch ( $updater !== null ? 
$updater->getDB()->getType() : $wgDBtype ) {
+                               default:
+                                       $ext = 'sql';
+                       }
+                       // Do the updating
+                       foreach ( $tables as $table ) {
+                               // Location of the table schema file
+                               $schema = "$sql/$table.$ext";
+                               $updater->addExtensionUpdate( array( 
'addTable', $table, $schema, true ) );
+                       }
+                       return true;
+               }
+
+               /**
+                * ParserFirstCallInit Hook handler
+                *
+                * @see 
https://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit
+                * @param Parser $parser The parser object this hook is called 
from
+                * @return boolean
+                */
+               public static function onParserFirstCallInit( Parser $parser ) {
+                       // set our parser tag
+                       $parser->setHook( 'gatp', 
'GoogleAnalyticsTopPages::renderParserTag' );
+               }
+       }
diff --git a/includes/api/ApiGooglePageStatsUpdate.php 
b/includes/api/ApiGooglePageStatsUpdate.php
new file mode 100644
index 0000000..cc52bc9
--- /dev/null
+++ b/includes/api/ApiGooglePageStatsUpdate.php
@@ -0,0 +1,61 @@
+<?php
+       class ApiGooglePageStatsUpdate extends ApiBase {
+               public function execute() {
+                       global $wgGATPProtectAPI, $wgSecretKey;
+
+                       $apiResult = $this->getResult();
+                       $dbw = wfGetDB( DB_MASTER );
+                       $params = $this->extractRequestParams();
+                       $success = 'false';
+                       $tableName = 'page_google_stats';
+
+                       // check, if the api is protected and if the key is 
correct
+                       if (
+                               $wgGATPProtectAPI &&
+                               $params['key'] !== $wgSecretKey
+                       ) {
+                               // false key
+                               $text = 'Wrong key, try 42.';
+                       } else {
+                               // delete all rows to insert a complete new set 
of data
+                               $del = $dbw->delete(
+                                       $tableName,
+                                       '*'
+                               );
+
+                               if ( $del ) {
+                                       // get the actual data from Google 
Analytics
+                                       $data = 
GoogleAnalyticsTopPages::getData( $this->getRequest() );
+
+                                       // insert the new data
+                                       $res = $dbw->insert(
+                                               $tableName,
+                                               $data
+                                       );
+                                       if ( $res ) {
+                                               $success = 'true';
+                                       }
+                               }
+                               $text = $dbw->lastError();
+                       }
+                       // build result array
+                       $r = array(
+                               'success' => $success,
+                               'text' => $text
+                       );
+                       // add result to API output
+                       $apiResult->addValue( null, $this->getModuleName(), $r 
);
+               }
+
+               public function mustBePosted() {
+                       return true;
+               }
+
+               public function getAllowedParams() {
+                       return array(
+                               'key' => array(
+                                       ApiBase::PARAM_TYPE => 'string',
+                               ),
+                       );
+               }
+       }
diff --git a/includes/specials/SpecialGoogleAnalyticsTopPages.php 
b/includes/specials/SpecialGoogleAnalyticsTopPages.php
new file mode 100644
index 0000000..610048a
--- /dev/null
+++ b/includes/specials/SpecialGoogleAnalyticsTopPages.php
@@ -0,0 +1,10 @@
+<?php
+       class SpecialGoogleAnalyticsTopPages extends SpecialPage {
+               public function __construct() {
+                       parent::__construct( 'GoogleAnalyticsTopPages' );
+               }
+
+               public function execute( $par ) {
+
+               }
+       }
diff --git a/includes/sql/page_google_stats.sql 
b/includes/sql/page_google_stats.sql
new file mode 100644
index 0000000..601b9ec
--- /dev/null
+++ b/includes/sql/page_google_stats.sql
@@ -0,0 +1,8 @@
+--
+-- extension GoogleAnalyticsTopPages SQL schema
+--
+CREATE TABLE /*$wgDBprefix*/page_google_stats (
+  page_title varbinary(255) NOT NULL PRIMARY KEY,
+  page_visitors bigint(20) unsigned NOT NULL default 0,
+  page_latest int(10) unsigned NOT NULL default 0
+) /*$wgDBTableOptions*/;

-- 
To view, visit https://gerrit.wikimedia.org/r/175299
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I6e67772c1cc25092099eca1307313bd10bcd101f
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/GoogleAnalyticsTopPages
Gerrit-Branch: master
Gerrit-Owner: Florianschmidtwelzow <[email protected]>
Gerrit-Reviewer: Florianschmidtwelzow <[email protected]>
Gerrit-Reviewer: Siebrand <[email protected]>
Gerrit-Reviewer: Springle <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to