MediaWiki:Gadget-dashboard.AddToFlickrBlacklist.js
Jump to navigation
Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
Documentation for this user script can be added at MediaWiki:Gadget-dashboard.AddToFlickrBlacklist. |
/**
* Script providing the logic
* and the user interface
* for adding users to both flickr blacklists
* with just one click
*
* Adds an UI to [[Template:Dashboard/Widgets/Add blacklist user]].
* Also a dashboard widget.
*
* @rev 1 (2013-02-06)
* @author [[User:Rillke]], 2013
* <nowiki>
*/
// List the global variables for jsHint-Validation. Please make sure that it passes http://jshint.com/
// Scheme: globalVariable:allowOverwriting[, globalVariable:allowOverwriting][, globalVariable:allowOverwriting]
/*global jQuery:false, mediaWiki:false, TextCleaner:false, importScript:false*/
// Set jsHint-options. You should not set forin or undef to false if your script does not validate.
/*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, curly:false, browser:true, smarttabs:true*/
(function($, mw) {
"use strict";
var fbl;
function firstItem(o) {
for (var i in o) {
if (o.hasOwnProperty(i)) {
return o[i];
}
}
}
function firstItemName(o) {
for (var i in o) {
if (o.hasOwnProperty(i)) {
return i;
}
}
}
fbl = {
version: '0.0.0.5',
flickrAPIUrl: 'https://api.flickr.com/services/rest/',
flickrAPIKey: 'secret',
flickrDoAPICall: function(params, cb, errCb) {
$.support.cors = true;
params.format = 'json';
params.api_key = fbl.flickrAPIKey;
if (fbl.flickrAPIKey === 'secret') throw new Error("You *must* set the API key before calling the FlickrAPI!");
var $jqXHR = $.ajax({
url: fbl.flickrAPIUrl,
cache: false,
type: 'GET',
crossDomain: true,
jsonp: 'jsoncallback',
dataType: 'jsonp',
data: params,
success: function(r, textStatus, jqXHR) {
if (r.stat === 'fail') {
return fbl.secureCall(errCb, $jqXHR, 'FlickrAPI returned error: ' + r.message, r.code);
} else if (r.stat !== 'ok') {
return fbl.secureCall(errCb, $jqXHR, 'FlickrAPI issue: ' + r.stat);
}
fbl.secureCall(cb, r, textStatus, jqXHR);
},
error: function(jqXHR, textStatus, errorThrown) {
fbl.secureCall(errCb, jqXHR, textStatus, errorThrown);
}
});
},
flickrGetIDByURL: function(URL, cb, errCb) {
// sample response: test({"user":{"id":"57124063@N03", "username":{"_content":"Valerii9116"}}, "stat":"ok"})
fbl.flickrDoAPICall({
method: 'flickr.urls.lookupUser',
url: URL
}, cb, errCb);
},
flickrGetInfoById: function(ID, cb, errCb) {
// sample response:
// test({"person":{"id":"62465723@N04", "nsid":"62465723@N04", "ispro":0, "iconserver":"0", "iconfarm":0, "path_alias":null,
// "username":{"_content":"pdamasceno"}, "realname":{"_content":""}, "location":{"_content":""}, "description":{"_content":""},
// "photosurl":{"_content":"http:\/\/www.flickr.com\/photos\/62465723@N04\/"}, "profileurl":{"_content":"http:\/\/www.flickr.com\/people\/62465723@N04\/"},
// "mobileurl":{"_content":"http:\/\/m.flickr.com\/photostream.gne?id=62433584"}, "photos":{"firstdatetaken":{"_content":"2012-09-30 14:02:20"},
// "firstdate":{"_content":"1349039021"}, "count":{"_content":1}}}, "stat":"ok"})
fbl.flickrDoAPICall({
method: 'flickr.people.getInfo',
user_id: ID
}, cb, errCb);
},
fetchFlickrAPIKey: function(cb, errCb) {
if (fbl.flickrAPIKey !== 'secret') return cb();
$.get(mw.util.getUrl('Special:UploadWizard'), function(r) {
var m = r.match(/[\"\']?flickrApiKey[\"\']?\s*:\s*[\"\']([0-9a-f]{10,50})[\"\']/);
if (!m) return errCb("Flickr API Key could not be retrieved!");
fbl.flickrAPIKey = m[1];
cb();
});
},
flickrIsURL: function(url) {
return (/flickr\.com\//).test(url);
},
flickrContainsId: function(txt) {
var m = txt.match(/\d{1,11}@\D\d{2}/);
if (m) {
return m[0];
} else {
return false;
}
},
flickrIsValidId: function(txt) {
return (/^\d{1,11}@\D\d{2}$/).test(txt);
},
mwChangePage: function(title, modifier, summary, done, failed) {
mw.libs.commons.api.query({
action: 'query',
prop: 'info|revisions',
rvprop: 'content|timestamp',
intoken: 'edit',
titles: title
}, {
method: 'GET',
cache: false,
cb: function(r) {
var pg = firstItem(r.query.pages),
rv = pg.revisions[0],
t = modifier(rv['*']);
mw.libs.commons.api.editPage({
cb: done,
errCb: function() {
fbl.secureCall(failed);
throw new Error("Editing " + title + " failed!");
},
editType: 'text',
title: title,
text: t,
summary: summary,
nocreate: true,
minor: true,
starttimestamp: pg.starttimestamp,
timestamp: rv.timestamp,
watchlist: 'nochange'
});
},
// r-result, query, text
errCb: function(t, r, q) {
throw new Error("Server error while retrieving contents of " + title + "!");
}
});
},
botPageTitle: 'User:FlickreviewR/bad-authors',
addAuthorToBotPage: function(id, cb, errCb) {
if (!fbl.flickrIsValidId(id)) throw new Error("Not a valid ID!");
var _changeContent = function(t_in) {
if (!t_in) throw new Error("Unable to retrieve contents of the bot list!");
var m = t_in.match(/\d{1,11}@\D\d{2}/g);
if ($.inArray(id, m) >= 0) {
return cb('already-in-list');
}
m.push(id);
m.sort();
var t_out = '#Add NSIDs of bad authors below this line. See [[Commons:Questionable Flickr images]] for more information.\n\n' +
m.join('\n');
return t_out;
};
fbl.secureCall('mwChangePage', fbl.botPageTitle, _changeContent, 'Adding ' + id, cb, errCb);
},
userListTitle: 'Commons:Questionable Flickr images/Users',
qfiFromInfo: function(info) {
info.path_alias = info.path_alias || '';
// Running Lupo's text cleaner over the reason preventing invalidation of the whole page
// by typos/missing closing brackets etc.
if (window.TextCleaner) info.reason = TextCleaner.sanitizeWikiText(info.reason, true);
return '{{qfi|' + info.username.replace(/\|/g, '|') + '|' + (info.path_alias || '') + '|' + info.nsid + '|4=' + info.reason + '}}';
},
addAuthorToUserList: function(info, cb) {
var _changeContent = function(t_in) {
var m = t_in.split('\n'),
posToInsert = {
t: '',
i: 0
},
confirmed = 0,
userNameL = info.username.toLowerCase();
var toInsert = fbl.qfiFromInfo(info);
// We assume that the list is already sorted
// "confirmed" for achieving a minimum error tolerance
$.each(m, function(i, line) {
var nextLine = m[i + 1];
// Skip irrelevant lines
if (-1 === line.indexOf('{{qfi|') && nextLine !== '|}') {
confirmed = 0;
return;
}
var currentName = line.match(/\{\{qfi\|([^\|]*)\|/)[1];
if (!currentName) return;
currentName = currentName.toLowerCase();
if (currentName < userNameL) {
posToInsert.t = currentName;
posToInsert.i = i;
confirmed = 0;
} else {
confirmed++;
if (2 === confirmed) return false;
}
});
// Insert the new line directly after the last line that was
// alphabetically "lower" than the name to insert
m.splice(posToInsert.i + 1, 0, toInsert);
return m.join('\n');
};
fbl.secureCall('mwChangePage', fbl.userListTitle, _changeContent, 'Adding ' + info.username + ' (' + info.nsid + ') because ' + info.reason, cb);
},
/**
* TextCleaner is piece of solid work made by [[User:Lupo]]!
**/
textCleanerLocation: 'MediaWiki:TextCleaner.js',
textCleanerRequested: false,
submit: function($ui, e) {
// UI helper functions
var _blink = function($el) {
$el.addClass('ui-state-error');
setTimeout(function() {
$el.removeClass('ui-state-error');
}, 1200);
};
var _finish = function(buttonclass) {
$ui.$flickrXWrap.remove();
$ui.$reasonWrap.remove();
$ui.$submit.remove();
$ui.$ok = $('<button type="button" role="button" id="fblSubmit">').text("Ok").attr({
'style': 'min-height:2em; width:97%; text-align:center; font-weight: bold; font-size: 1.3em',
'class': (buttonclass || 'ui-button-green') + ' ui-button-large'
}).button().appendTo($ui);
$ui.$ok.click(function() {
var $p = $ui.parent();
$ui.remove();
$p.append(fbl.$getUI());
});
};
var _setStatus = function(txt) {
$ui.$status.text(txt);
};
// First validate input
var flickrX = $.trim($ui.$flickrX.val()),
isURL = fbl.flickrIsURL(flickrX),
isNSID = fbl.flickrIsValidId(flickrX),
reason = $ui.$reason.val();
if (!isURL && !isNSID) {
_blink($ui.$flickrXWrap);
$ui.$flickrX
.attr('title', "Please specify a valid URL pointing to a Flickr profile, a flickr file or gallery or enter a valid NSID like 12345678@N94")
.tipsy({
gravity: $.fn.tipsy.autoWE,
trigger: 'focus'
}).focus();
return;
}
if (reason.length < 8) {
_blink($ui.$reasonWrap);
$ui.$reason.attr('title', "A reason with at least 8 letter is mandatory!")
.tipsy({
gravity: $.fn.tipsy.autoWE,
trigger: 'focus'
}).focus();
return;
}
// Then, disable the submit
// and query info we need
$ui.$submit.button({
'disabled': true
});
var gatheredInfo = {
reason: reason
};
var _flickrUserInfo = function() {
_setStatus("Asking FlickrAPI for user info.");
fbl.secureCall('flickrGetInfoById', gatheredInfo.nsid, function(r) {
var p = r.person;
$.extend(gatheredInfo, {
username: p.username._content,
path_alias: p.path_alias,
ispro: p.ispro,
realname: p.realname ? p.realname._content : ''
});
_setStatus("Got user info.");
_doEdits();
}, function($xhr, text) {
_setStatus(text);
_finish('ui-button-red');
});
};
_setStatus("Fetching API key.");
fbl.secureCall('fetchFlickrAPIKey', function() {
if (isURL) {
_setStatus("Asking FlickrAPI for NSID of the user.");
fbl.secureCall('flickrGetIDByURL', flickrX, function(r) {
gatheredInfo.nsid = r.user.id;
_setStatus("Got user ID.");
_flickrUserInfo();
}, function($xhr, text) {
_setStatus(text);
_finish('ui-button-red');
});
} else {
gatheredInfo.nsid = flickrX;
_flickrUserInfo();
}
}, function(err) {
_setStatus(err);
_finish('ui-button-red');
});
// Finally do the edits,
// if everything worked
var _doEdits = function() {
_setStatus("Doing edits. User name: " + gatheredInfo.username + " Path alias: " +
gatheredInfo.path_alias + " Real name: " + gatheredInfo.realname + " ID: " + gatheredInfo.nsid);
fbl.secureCall('addAuthorToBotPage', gatheredInfo.nsid, function(r) {
if ('already-in-list' === r) {
_setStatus("Flickr user ID already in bot list. Aborting.");
return _finish('ui-button-blue');
}
_setStatus("Added ID to bot blacklist. Now processing full list.");
fbl.secureCall('addAuthorToUserList', gatheredInfo, function() {
_setStatus("Done.");
_finish();
});
}, function() {
_setStatus("Editing the bot list failed. Here are all required information: " +
fbl.qfiFromInfo(gatheredInfo));
_finish('ui-button-red');
});
};
},
/**
** Method to catch errors and report where they occurred
**/
secureCall: function(fn) {
var o = fbl;
try {
o.currentTask = arguments[0];
if ($.isFunction(fn)) {
if (fn.name) o.log(fn);
return fn.apply(o, Array.prototype.slice.call(arguments, 1)); // arguments is not of type array so we can't just write arguments.slice
} else if ('string' === typeof fn) {
o.log(fn);
return o[fn].apply(o, Array.prototype.slice.call(arguments, 1)); // arguments is not of type array so we can't just write arguments.slice
} else {
o.log('This is not a function!');
}
} catch (ex) {
o.log('failure at ' + fn);
o.fail(ex);
}
},
log: function(key, val) {
if (window.console && $.isFunction(window.console.log)) window.console.log('FBL> ' + key, val /*, this*/ );
},
fail: function(err) {
// Handle error or report or whatever
// TODO build an error-report script
fbl.log(err);
},
/**
* Implement Commons Dashboard Widget interface
* @dashboardwidgetinterface
**/
$getUI: function() {
if (fbl.textCleanerRequested) {
importScript(fbl.textCleanerLocation);
fbl.textCleanerRequested = true;
}
// Creating root node for our widget
var $ui = $('<div>').attr({
'class': 'dashbord-item flickr-blacklist-adder'
});
if (mw.user.isAnon()) {
$('<div>').text("{{Dashboard/Widgets/Add blacklist user}}: In order to use this widget, please log in.").css('font-weight', 'bold').appendTo($ui);
return $ui;
}
$ui.$flickrXWrap = $('<div>').attr({
'title': "Insert Flickr URL or FlickrID"
}).appendTo($ui);
$ui.$flickrXL = $('<label>', {
'text': "Insert Flickr URL or Flickr user ID (nsid):"
}).attr({
'for': 'fblFlickrX'
}).appendTo($ui.$flickrXWrap);
$ui.$flickrX = $('<input>').attr({
'id': 'fblFlickrX',
'style': 'width:97%',
'placeholder': 'Flickr URL or Flickr user ID'
}).appendTo($ui.$flickrXWrap);
$ui.$reasonWrap = $('<div>').attr({
'title': "Why should the user be blacklisted?"
}).appendTo($ui);
$ui.$reasonL = $('<label>', {
'text': "Reason for blacklisting:"
}).attr({
'for': 'fblReasonFlickr'
}).appendTo($ui.$reasonWrap);
$ui.$reason = $('<input>').attr({
'id': 'fblReasonFlickr',
'style': 'width:97%',
'placeholder': 'Reason'
}).appendTo($ui.$reasonWrap);
$ui.$spacer = $('<div>').attr({
'style': 'height:1em; width:97%'
}).appendTo($ui);
$ui.$submit = $('<button type="button" role="button" id="fblSubmit">').text("Add user to blacklists").attr({
'style': 'min-height:2em; width:97%; text-align:center; font-weight: bold; font-size: 1.3em',
'class': 'ui-button-orange ui-button-large'
}).button().appendTo($ui);
$ui.$status = $('<div>').appendTo($ui);
$ui.$submit.click($.proxy(fbl.submit, fbl, $ui));
return $ui;
},
createUI: function() {
var $container = $('#fblContainer').text('');
if ($container.length) $container.append(fbl.$getUI());
}
};
// Expose globally
window.flickrBlacklist = fbl;
var launch = function($c) {
if ($('#fblContainer', $c).length) mw.loader.using(['ext.gadget.libAPI', 'jquery.ui', 'ext.gadget.tipsyDeprecated', 'mediawiki.user'], fbl.createUI);
};
mw.hook( 'wikipage.content' ).add( launch );
}(jQuery, mediaWiki));
// </nowiki>