Welcome to the DFO World Wiki. With many major updates since the release of DFO, many items are missing. Visit Item Database Project to learn more.
Please remember to click "show preview" before saving the page.
Thanks for the updated logo snafuPop!

MediaWiki:Gadget-dashboard.AddToFlickrBlacklist.js

From DFO World Wiki
Jump to: navigation, search

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
/**
 * 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:' === location.protocol) ? 'https://secure.flickr.com/services/rest/' : 'http://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, '&#124;') + '|' + (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.button', 'jquery.tipsy', 'mediawiki.user'], fbl.createUI);
	};
	mw.hook( 'wikipage.content' ).add( launch );

}(jQuery, mediaWiki));

// </nowiki>