User:DarkMatterMan4500/cuStaleness.js

From Test Wiki
Jump to navigation Jump to search

Note: After publishing, 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 / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
//<nowiki>
/**
 * @brief Checkuser staleness checker.
 * @desc Checks contribs, deleted contribs, and user creation date, and determines whether the account has activity past the 90-day checkuser staleness mark.
 * @author Originally written by Writ Keeper. Modified by User:mdaniels5757 for Commons.
 * @license CC-BY-SA-3.0
 * @copyright (c) 2017-2020 by the Authors
*/

if(typeof maxUsersCUStaleness !== "number" || maxUsersCUStaleness < 1)
{
    maxUsersCUStaleness = 50;
}
cuStaleNewestCreate = null;
cuStaleNewestCreateID = null;
cuStaleOldestCreate = null;
cuStaleOldestCreateID = null;
cuStaleNewestContrib = null;
cuStaleNewestContribID = null;
cuStaleOldestContrib = null;
cuStaleOldestContribID = null;
cuStaleRunCount = 0;

if(typeof lazyCheckCUStaleness !== "boolean" || !(lazyCheckCUStaleness === false))
{
    lazyCheckCUStaleness = true;
}
function insertStalenessIndicator(siblingNode, message, color, finished)
{
	var newNode = "<span style='color:" + color + ";'> -- " + message + "</span>";
	$(siblingNode).after(newNode);
	$(siblingNode).parent("span.cuStaleChecking").removeClass("cuStaleChecking");
	finished.resolve();
}
function performStalenessCheck()
{
	cuStaleRunCount++;
	//initialize some variables
	var currentTimestamp = new Date().getTime();
	var canViewDeleted = true; //assume this is true, update if the first call fails
	var timestampDifference = 90 * 24 * 60 * 60 * 1000; //90 days in milliseconds
	var notStaleColor = "#339900";
	var problemColor = "red";
	var maybeStaleColor = "#e6ac00";
	var promises = [];
	//for each cu entry (as defined by use of the {{checkuser}} template)...
	var cuEntries =  $($("span.cuStaleChecking").get().reverse());
	if(cuStaleNewestCreateID != null)
	{
		$("#Create" + cuStaleNewestCreateID).css("font-style","normal");
	}
	if(cuStaleNewestContribID != null)
	{
		$("#Contrib" + cuStaleNewestContribID).css("font-style","normal");
	}
	if(cuStaleOldestCreateID != null)
	{
		$("#Create" + cuStaleOldestCreateID).css("font-weight","normal");
	}
	if(cuStaleOldestContribID != null)
	{
		$("#Contrib" + cuStaleOldestContribID).css("font-weight","normal");
	}
	cuEntries.each(function (index)
	{
		//first, retrieve the current iteration's user name from the text of the template
		var contribsData =
		{
			"action": "query",
			"list": "usercontribs",
			"ucprop": "timestamp",
			"ucuser": "",
			"uclimit": "1",
			"ucdir": "older",
			"format": "json"
		};
		var deletedData =
		{
			"action": "query",
			"list": "alldeletedrevisions",
			"adrprop": "timestamp",
			"adruser": "",
			"adrlimit": "1",
			"adrdir": "older",
			"format": "json"
		};
		var createdData =
		{
			"action": "query",
			"list": "users",
			"ususers": "",
			"usprop": "registration",
			"format": "json"
		};

		var sockName = $(this).children(":first").text();
		var cuLogLinks = $(this).children("span.cuLink");
		var message = "";
		//insert it into the API data packages
		contribsData.ucuser = sockName;
		deletedData.adruser = sockName;
		createdData.ususers = sockName;
		//initialize values
		var lastWasDeleted = false;
		var notStale = false;
		//first search and display creation date
		if (index < maxUsersCUStaleness)
		{
			var finished = $.Deferred();
			promises.push(finished.promise());
			var indexString = cuStaleRunCount + "-" + index;
			$.post("/w/api.php", createdData, function (response)
			{
				//if this, the account doesn't exist; don't bother to run any more queries
				if (typeof response.query.users[0].missing !== "undefined")
				{
					insertStalenessIndicator(cuLogLinks, "account does not exist", problemColor, finished);
				}
				else
				{
					//check registration date, if it exists.
					if (typeof response.query.users[0].registration !== "undefined")
					{
						//API-accessible user creation logs started on December 22, 2005; anything before that would display the epoch date without special handling
						if (response.query.users[0].registration === null)
						{
							message = "created <span style='font-weight:bold;'>on or before 2005-12-22</span>, ";
							cuStaleOldestCreate = new Date(0);
							cuStaleOldestCreateID = null;
						}
						else
						{
							var regTime = new Date(response.query.users[0].registration);
							if(cuStaleOldestCreate == null || regTime < cuStaleOldestCreate)
							{
								cuStaleOldestCreate = regTime;
								cuStaleOldestCreateID = "" + indexString;
							}
							if(cuStaleNewestCreate == null || regTime > cuStaleNewestCreate)
							{
								cuStaleNewestCreate = regTime;
								cuStaleNewestCreateID = "" + indexString;
							}
							//if the account itself is newer than 90 days, and we're being lazy, we don't have to check anything else, we already know it's not stale
							var formattedDatestamp = dateFormatter(regTime.getUTCFullYear() + "-" + (regTime.getUTCMonth() + 1) + "-" + regTime.getUTCDate(), indexString, "Create");
							if (currentTimestamp - regTime.getTime() < timestampDifference)
							{
								if(lazyCheckCUStaleness)
								{
									message = "created "+ formattedDatestamp + ", not stale";									
									insertStalenessIndicator(cuLogLinks, message, notStaleColor, finished);
									return;
								}
								else
								{
									notStale = true;
								}
							}
							message = "created " + formattedDatestamp + ", ";
						}
					}
					else //it's an IP, make note of the fact and move on
					{
						message = "IP address, ";
					}
					//look up contribs

					$.post("/w/api.php", contribsData, function (response)
					{
						if(typeof response.error !== "undefined")
						{
							insertStalenessIndicator(cuLogLinks, "Error retrieving contribs details; might be an IP address range", problemColor, finished);
						}
						else if (typeof response.query !== "undefined" && response.query.usercontribs.length > 0)
						{
							//retrieve the current stamp
							var lastTimestamp = new Date(response.query.usercontribs[0].timestamp);
							if(cuStaleOldestContrib == null || lastTimestamp < cuStaleOldestContrib)
							{
								cuStaleOldestContrib = lastTimestamp;
								cuStaleOldestContribID = "" + indexString;
							}
							if(cuStaleNewestContrib == null || lastTimestamp > cuStaleNewestContrib)
							{
								cuStaleNewestContrib = lastTimestamp;
								cuStaleNewestContribID = "" + indexString;
							}
							var formattedDate = dateFormatter(lastTimestamp.getUTCFullYear() + "-" + (lastTimestamp.getUTCMonth() + 1) + "-" + lastTimestamp.getUTCDate(), "" + indexString, "Contrib");
							//a contrib more recent than 90 days, so it's not stale; no need to check the deleted contribs if we're lazy
							if (currentTimestamp - lastTimestamp.getTime() < timestampDifference)
							{
								if(lazyCheckCUStaleness)
								{
									insertStalenessIndicator(cuLogLinks, message + "last edit " + formattedDate + ", not stale", notStaleColor, finished);
									return;
								}
								else
								{
									notStale = true;
								}
							}
							//normal contribs were all stale, so now try deleted (if we can)
							if (canViewDeleted)
							{
								$.post("/w/api.php", deletedData, function (response)
								{
									//if we can't see deleted edits due to not being an admin, flag as possibly stale based on the normal contribs and flip the bit so that we don't waste time on deleted contribs in the future
									if (typeof response.error !== "undefined" && response.error.code == "permissiondenied")
									{
										canViewDeleted = false;
										if(notStale)
										{
											insertStalenessIndicator(cuLogLinks, message + "last edit " + formattedDate + ", not stale", notStaleColor, finished);
										}
										else
										{
											insertStalenessIndicator(cuLogLinks, message + "last edit " + formattedDate + ", possibly stale", maybeStaleColor, finished);
										}
										return;
									}
									//otherwise, check the to see if there are any
									else if (response.query.alldeletedrevisions.length > 0)
									{
										var deletedTimestamp = new Date(response.query.alldeletedrevisions[0].revisions[0].timestamp);
										//there are deleted contribs, so compare the timestamp to see if they're more recent than the normal contrib
										if (deletedTimestamp > lastTimestamp)
										{
											//deleted contrib is newer, so display it and use it to decide whether the account is possibly stale or not
											if(cuStaleOldestContrib == null || deletedTimestamp < cuStaleOldestContrib)
											{
												cuStaleOldestContrib = deletedTimestamp;
												cuStaleOldestContribID = "" + indexString;
											}
											if(cuStaleNewestContrib == null || deletedTimestamp > cuStaleNewestContrib)
											{
												cuStaleNewestContrib = deletedTimestamp;
												cuStaleNewestContribID = "" + indexString;
											}
											formattedDate = dateFormatter(deletedTimestamp.getUTCFullYear() + "-" + (deletedTimestamp.getUTCMonth() + 1) + "-" + deletedTimestamp.getUTCDate(), "" + indexString, "Contrib");
											if (currentTimestamp - deletedTimestamp.getTime() < timestampDifference)
											{
												insertStalenessIndicator(cuLogLinks, message + "last (deleted) edit " + formattedDate + ", not stale", notStaleColor, finished);
												return;
											}
											else
											{
												insertStalenessIndicator(cuLogLinks, message + "last (deleted) edit " + formattedDate + ", probably stale", maybeStaleColor, finished);
												return;
											}
										}
										else //the deleted contribs existed but aren't any newer than the normal contribs, so report the normal contribs and flag as probably stale
										{
											if(notStale)
											{
												insertStalenessIndicator(cuLogLinks, message + "last edit " + formattedDate + ", not stale", notStaleColor, finished);
											}
											else
											{
												insertStalenessIndicator(cuLogLinks, message + "last edit " + formattedDate + ", probably stale", maybeStaleColor, finished);
											}
											return;
										}
									}
									else //no deleted contribs, so report the normal contribs and flag as probably stale
									{
										if(notStale)
										{
											insertStalenessIndicator(cuLogLinks, message + "last edit " + formattedDate + ", not stale", notStaleColor, finished);
										}
										else
										{
											insertStalenessIndicator(cuLogLinks, message + "last edit " + formattedDate + ", probably stale", maybeStaleColor, finished);
										}
										return;
									}
								}
								);
							}
							else //we already know we can't see deleted contribs, so just settle for possibly stale from the normal contribs
							{
								if(notStale)
								{
									insertStalenessIndicator(cuLogLinks, message + "last edit " + formattedDate + ", not stale", notStaleColor, finished);
								}
								else
								{
									insertStalenessIndicator(cuLogLinks, message + "last edit " + formattedDate + ", possibly stale", maybeStaleColor, finished);
								}
								return;
							}
						}
						else //no normal contribs, so check deleted contribs if we can
						{
							if (canViewDeleted)
							{
								$.post("/w/api.php", deletedData, function (response)
								{
									//if we can't see deleted edits due to not being an admin, flag as possibly stale based on the normal contribs and flip the bit so that we don't waste time on deleted contribs in the future
									if (typeof response.error !== "undefined" && response.error.code == "permissiondenied")
									{
										canViewDeleted = false;
										if(notStale)
										{
											insertStalenessIndicator(cuLogLinks, message + "no visible contribs, not stale", notStaleColor, finished);
										}
										else
										{
											insertStalenessIndicator(cuLogLinks, message + "no visible contribs, possibly stale", maybeStaleColor, finished);
										}
										return;
									}
									//otherwise, check the to see if there are any
									else if (response.query.alldeletedrevisions.length > 0)
									{
										var deletedTimestamp = new Date(response.query.alldeletedrevisions[0].revisions[0].timestamp);
										if(cuStaleOldestContrib == null || deletedTimestamp < cuStaleOldestContrib)
										{
											cuStaleOldestContrib = deletedTimestamp;
											cuStaleOldestContribID = "" + indexString;
										}
										if(cuStaleNewestContrib == null || deletedTimestamp > cuStaleNewestContrib)
										{
											cuStaleNewestContrib = deletedTimestamp;
											cuStaleNewestContribID = "" + indexString;
										}
										formattedDate = dateFormatter(deletedTimestamp.getUTCFullYear() + "-" + (deletedTimestamp.getUTCMonth() + 1) + "-" + deletedTimestamp.getUTCDate(), "" + indexString, "Contrib");
										if (currentTimestamp - deletedTimestamp.getTime() < timestampDifference)
										{
											insertStalenessIndicator(cuLogLinks, message + "last (deleted) edit " + formattedDate + ", not stale", notStaleColor, finished);
											return;
										}
										else
										{
											if(notStale)
											{
												insertStalenessIndicator(cuLogLinks, message + "last (deleted) edit " + formattedDate + ", not stale", notStaleColor, finished);
											}
											else
											{
												insertStalenessIndicator(cuLogLinks, message + "last (deleted) edit " + formattedDate + ", probably stale", maybeStaleColor, finished);
											}
											return;
										}
									}
									else //no deleted contribs, so report the normal contribs and flag as probably stale
									{
										if(notStale)
										{
											insertStalenessIndicator(cuLogLinks, message + "no contribs, not stale", notStaleColor, finished);
										}
										else
										{
											insertStalenessIndicator(cuLogLinks, message + "no contribs, probably stale", maybeStaleColor, finished);
										}
										return;
									}
								}
								);
							}
						}
					}
					);
				}
			}
			);
		}
		else
		{
			var newNode = "<a class='cuStalenessContinue' style='color:" + problemColor + ";'> -- too many users to process at once; this user not checked. click to continue...</a>";
			$(cuLogLinks).after(newNode);
			$(".cuStalenessContinue").click(resumeStalenessCheck);
			return false;
		}
	}
	);
	$.when.apply($, promises).then(function()
	{
		if(cuStaleNewestCreateID != null)
		{
			$("#Create" + "" + cuStaleNewestCreateID).css("font-style","italic");
		}
		if(cuStaleNewestContribID != null)
		{
			$("#Contrib" + "" + cuStaleNewestContribID).css("font-style","italic");
		}
		if(cuStaleOldestCreateID != null)
		{
			$("#Create" + "" + cuStaleOldestCreateID).css("font-weight","bold");
		}
		if(cuStaleOldestContribID != null)
		{
			$("#Contrib" + "" + cuStaleOldestContribID).css("font-weight","bold");
		}
	});
}
function dateFormatter(dateString, index, type)
{
	var message = "<span id='" + type + index + "'>" + dateString + "</span>";
	return message;
}
function resolvePromise(promise)
{
	return function(){promise.resolve()};
}
function resumeStalenessCheck()
{
	$(".cuStalenessContinue").remove();
	performStalenessCheck();
}
mw.hook('wikipage.content').add(function ()
{
	var titleRegex = /Commons:Requests_for_checkuser/;
	var sandboxRegex = /User:.+\/[Ss]andbox/;
	//only use on a RFCU page (or a sandbox page for testing)
	if (titleRegex.test(mw.config.get("wgPageName")) || sandboxRegex.test(mw.config.get("wgPageName")))
	{
		$("span.cuEntry").addClass("cuStaleChecking");
		performStalenessCheck();
	}
}
);
//</nowiki>