MaxSem has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/253060

Change subject: WIP: Stats thingie
......................................................................

WIP: Stats thingie

Change-Id: I497364fc18c2183fc0b793d0d1e7d158ef094cd4
---
M package.json
A site-stats.js
A tests/site-stats-test.js
3 files changed, 206 insertions(+), 3 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/wikimedia/portals 
refs/changes/60/253060/1

diff --git a/package.json b/package.json
index f74db3e..6573784 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,10 @@
 {
-  "dependencies": {},
-  "devDependencies": {
+  "name": "portals",
+  "version": "1.0.0",
+  "description": "",
+  "main": "gulpfile.js",
+  "dependencies": {
+    "bluebird": "^3.0.5",
     "gulp": "^3.9.0",
     "gulp-imagemin": "^2.3.0",
     "gulp-inline": "^0.1.0",
@@ -10,6 +14,19 @@
     "gulp-minify-css": "^1.2.1",
     "gulp-uglify": "^1.4.2",
     "imagemin-pngquant": "^4.2.0",
+    "moment": "^2.10.6",
+    "preq": "^0.4.6",
+    "underscore": "^1.8.3",
     "yargs": "^3.29.0"
-  }
+  },
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "ssh://[email protected]:29418/wikimedia/portals"
+  },
+  "author": "",
+  "license": "ISC"
 }
diff --git a/site-stats.js b/site-stats.js
new file mode 100644
index 0000000..205b748
--- /dev/null
+++ b/site-stats.js
@@ -0,0 +1,171 @@
+var preq = require( 'preq' );
+var BBPromise = require( 'bluebird' );
+var moment = require( 'moment' );
+var _ = require( 'underscore' );
+
+
+var projects = {
+       'wikipedia': /wiki$/,
+       'wiktionary': /wiktionary$/,
+       'wikinews': /wikinews$/,
+       'wikiquote': /wikiquote$/,
+       'wikisource': /wikisource$/,
+       'wikibooks': /wikibooks$/,
+       'wikiversity': /wikiversity$/,
+       'wikivoyage': /wikivoyage$/
+};
+
+var codeMapping = {
+       b: 'wikibooks',
+       d: 'wiktionary',
+       f: 'foundationwiki',
+       m: 'wiki',
+       mw: 'wiki',
+       n: 'wikinews',
+       q: 'wikiquote',
+       s: 'wikisource',
+       v: 'wikiversity',
+       voy: 'wikivoyage',
+       w: 'wiki',
+       wd: 'wikidatawiki',
+       zero: 'wiki'
+};
+
+var soloProjects = {
+       f: 'foundationwiki',
+       wd: 'wikidatawiki'
+};
+
+function httpGet( url ) {
+       //console.log( url );
+       var preqOptions = { headers: { 'User-Agent': 'Hi Öłïvér!' } };
+
+       return preq.get( url, preqOptions )
+               .then( function( request ) {
+                       return BBPromise.resolve( request.body );
+               } )
+               .catch( function( err ) {
+                       // I can haz error message that makes sense?
+                       var msg = err.toString() + ' requesting ' + url;
+                       console.error( msg );
+                       BBPromise.reject( msg );
+               } );
+}
+
+function getPageCounts() {
+       if ( process.env.MEDIAWIKI_DEPLOYMENT_DIR && false ) {
+               // Production
+               // TODO:
+       } else {
+               // Developer's machine
+               return httpGet( 
'https://tools.wmflabs.org/pagecounts/pagecounts.json' )
+                       .then( function( pagecounts ) {
+                               var stats = {};
+
+                               _.each( pagecounts, function( wiki, code ) {
+                                       stats[code] = wiki.contentPages;
+                               } );
+                               return BBPromise.resolve( stats );
+                       } );
+       }
+}
+
+function getSiteMatrix() {
+       return httpGet( 
'https://meta.wikimedia.org/w/api.php?action=sitematrix&format=json&smtype=language&smlangprop=code%7Csite&smsiteprop=url%7Cdbname%7Ccode'
 );
+}
+
+function parseProjectString( str ) {
+       var parts = str.split( '.' );
+       var name = parts.shift(); //
+       if ( parts.length > 1 ) {
+               parts.shift(); // Qualifier like mobile or zero
+       }
+       if ( parts.length ) {
+               if ( !codeMapping[ parts[0] ] ) {
+                       throw 'Cannot parse wiki ' + str;
+               }
+               name += codeMapping[ parts[0] ];
+       } else {
+               name += 'wiki';
+       }
+       if ( parts.length > 1 ) {
+               throw 'Cannot parse wiki ' + str;
+       }
+       return name;
+}
+
+function getProjectViews() {
+       var yesterday = moment.utc().subtract( 1, 'days' ).startOf( 'day' );
+       var baseUrl = 'https://dumps.wikimedia.org/other/pageviews/' + 
yesterday.format( 'YYYY/YYYY-MM' ) + '/projectviews-' + yesterday.format( 
'YYYYMMDD' );
+       var promises = [];
+
+       for ( var i = 0; i <= 23; i++ ) {
+               var url = baseUrl + '-' + ( i < 10 ? '0' : '' ) + i.toString() 
+ '0000';
+               promises.push( httpGet( url ) );
+       }
+
+       return BBPromise
+               .all( promises )
+               .then( function( hourlies ) {
+                       var views = {};
+
+                       _.each( hourlies, function( hourly ) {
+                               if ( !hourly ) {
+                                       return;
+                               }
+                               var lines = hourly.toString().split( '\n' );
+                               _.each( lines, function( line ) {
+                                       var parts = line.split( /\s+-?\s*/ );
+                                       var wiki = parseProjectString( parts[0] 
);
+                                       views[wiki] = views[wiki] || 0;
+                                       views[wiki] += parseInt( parts[1] );
+                               } );
+                       } );
+                       if ( !views ) {
+                               // We permit some hourly files to fail to be 
downloaded, but all of them missing
+                               // is a sign of a problem
+                               return BBPromise.reject( 'No hourly project 
views file was successfully loaded' );
+                       }
+                       return BBPromise.resolve( views );
+               } )
+               .error( function() {} ); // Do nothing, last file can be being 
generated right now
+}
+
+
+function getSiteStats() {
+       var stats = {};
+
+       BBPromise.all( [ getPageCounts(), getSiteMatrix(), getProjectViews() ] )
+               .then( function( data ) {
+                       var counts = data[0];
+                       var siteMatrix = data[1].sitematrix;
+                       var views = data[2];
+
+                       _.each( siteMatrix, function( lang, propName ) {
+                               if ( !/^\d+$/.test( propName ) ) {
+                                       return; // Not a language... Fuck, this 
API's output is ugly
+                               }
+                               _.each( lang.site, function( site ) {
+                                       stats[site.code] = stats[site.code] || 
{};
+                                       stats[site.code][lang.code] = {
+                                               url: site.url,
+                                               articles: counts[site.dbname] 
|| 0,
+                                               views: views[site.dbname] || 0,
+                                               closed: site.closed !== 
undefined
+                                       };
+                               } );
+                       } );
+
+                       //console.log(stats);
+               } );
+
+}
+
+module.exports = {
+       get: getSiteStats(),
+       parseProjectString: parseProjectString
+};
+
+console.log( parseProjectString( 'm.f' ) );
+
+getSiteStats();
diff --git a/tests/site-stats-test.js b/tests/site-stats-test.js
new file mode 100644
index 0000000..0cb589c
--- /dev/null
+++ b/tests/site-stats-test.js
@@ -0,0 +1,15 @@
+var siteStats = require( '../site-stats' );
+
+module.exports.testParseProjectString = function( test ) {
+       var parseProjectString = siteStats.parseProjectString;
+
+       test.equals( 'enwiki', parseProjectString( 'en' ) );
+       test.equals( 'enwiki', parseProjectString( 'en.zero' ) );
+       test.equals( 'enwiki', parseProjectString( 'en.m' ) );
+       test.equals( 'enwikibooks', parseProjectString( 'en.m.b' ) );
+
+       test.equals( 'foundationwiki', parseProjectString( 'm.f' ) );
+       test.equals( 'foundationwiki', parseProjectString( 'f' ) );
+
+       test.done();
+};
\ No newline at end of file

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I497364fc18c2183fc0b793d0d1e7d158ef094cd4
Gerrit-PatchSet: 1
Gerrit-Project: wikimedia/portals
Gerrit-Branch: master
Gerrit-Owner: MaxSem <[email protected]>

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

Reply via email to