User:Writ Keeper/Scripts/cuStaleness.js
Appearance
From Wikipedia, the free encyclopedia
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump.
This code will be executed when previewing this page.
This code will be executed when previewing this page.
Documentation for this user script can be added at User:Writ Keeper/Scripts/cuStaleness.
//<nowiki> /* Checkuser staleness checker, written by Writ Keeper and Tamzin. Checks contribs, deleted contribs, and user creation date, and determines whether the account has activity past the 90-day checkuser staleness mark. Runs on SPI case pages, i.e. subpages of [[Wikipedia:Sockpuppet_investigations]]. */ if(typeofmaxUsersCUStaleness!=="number"||maxUsersCUStaleness<1) { maxUsersCUStaleness=50; } cuStaleNewestCreate=null; cuStaleNewestCreateID=null; cuStaleOldestCreate=null; cuStaleOldestCreateID=null; cuStaleNewestContrib=null; cuStaleNewestContribID=null; cuStaleOldestContrib=null; cuStaleOldestContribID=null; cuStaleRunCount=0; if(typeoflazyCheckCUStaleness!=="boolean"||!(lazyCheckCUStaleness===false)) { lazyCheckCUStaleness=true; } functioncuStaleInsertStalenessIndicator(siblingNode,message,color,finished) { varnewNode="<span style='color:"+color+";'> -- "+message+"</span>"; $(siblingNode).after(newNode); $(siblingNode).parent("span.cuStaleChecking").removeClass("cuStaleChecking"); finished.resolve(); } functioncuStalePerformStalenessCheck() { cuStaleRunCount++; //initialize some variables varcurrentTimestamp=newDate().getTime(); varcanViewDeleted=true;//assume this is true, update if the first call fails vartimestampDifference=90*24*60*60*1000;//90 days in milliseconds varnotStaleColor="#339900"; varproblemColor="red"; varmaybeStaleColor="#e6ac00"; varpromises=[]; //for each cu entry (as defined by use of the {{checkuser}} template)... varcuEntries=$($("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 varcontribsData= { "action":"query", "list":"usercontribs", "ucprop":"timestamp", "ucuser":"", "uclimit":"1", "ucdir":"older", "format":"json" }; vardeletedData= { "action":"query", "list":"alldeletedrevisions", "adrprop":"timestamp", "adruser":"", "adrlimit":"1", "adrdir":"older", "format":"json" }; varcreatedData= { "action":"query", "format":"json", "list":"users|logevents", "usprop":"registration", "ususers":"", "letype":"newusers", "letitle":"" }; varsockName=newmw.Title($(this).children(":first").text()).getMain(); varcuLogLinks=$(this).children("span.cuLink"); varmessage=""; //insert it into the API data packages contribsData.ucuser=sockName; deletedData.adruser=sockName; createdData.ususers=sockName; createdData.letitle="User:"+sockName; //initialize values varlastWasDeleted=false; varnotStale=false; //first search and display creation date if(index<maxUsersCUStaleness) { varfinished=$.Deferred(); promises.push(finished.promise()); varindexString=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(typeofresponse.query.users[0].missing!=="undefined") { cuStaleInsertStalenessIndicator(cuLogLinks,"account does not exist",problemColor,finished); } else { //check who created the account varaccountCreator=sockName; if(response.query.logevents.length!==0) { accountCreator=newmw.Title(response.query.logevents[0].user).getMain(); } varcreatorMessage=""; if(accountCreator!==sockName) { creatorMessage="<span style='font-weight:bold;'>by <a href='/wiki/User:"+accountCreator+"'>User:"+accountCreator.replaceAll("_"," ")+"</a></span> "; } //check registration date, if it exists. if(typeofresponse.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 "+creatorMessage+"<span style='font-weight:bold;'>on or before 2005年12月22日</span>, "; cuStaleOldestCreate=newDate(0); cuStaleOldestCreateID=null; } else { varregTime=newDate(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 varformattedDatestamp=cuStaleDateFormatter(regTime,indexString,"Create"); if(currentTimestamp-regTime.getTime()<timestampDifference) { if(lazyCheckCUStaleness) { message="created "+creatorMessage+formattedDatestamp+", not stale"; cuStaleInsertStalenessIndicator(cuLogLinks,message,notStaleColor,finished); return; } else { notStale=true; } } message="created "+creatorMessage+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(typeofresponse.error!=="undefined") { cuStaleInsertStalenessIndicator(cuLogLinks,"Error retrieving contribs details; might be an IP address range",problemColor,finished); } if(typeofresponse.query!=="undefined"&&response.query.usercontribs.length>0) { //retrieve the current stamp varlastTimestamp=newDate(response.query.usercontribs[0].timestamp); if(cuStaleOldestContrib==null||lastTimestamp<cuStaleOldestContrib) { cuStaleOldestContrib=lastTimestamp; cuStaleOldestContribID=""+indexString; } if(cuStaleNewestContrib==null||lastTimestamp>cuStaleNewestContrib) { cuStaleNewestContrib=lastTimestamp; cuStaleNewestContribID=""+indexString; } varformattedDate=cuStaleDateFormatter(lastTimestamp,""+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) { cuStaleInsertStalenessIndicator(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(typeofresponse.error!=="undefined"&&response.error.code=="permissiondenied") { canViewDeleted=false; if(notStale) { cuStaleInsertStalenessIndicator(cuLogLinks,message+"last edit "+formattedDate+", not stale",notStaleColor,finished); } else { cuStaleInsertStalenessIndicator(cuLogLinks,message+"last edit "+formattedDate+", possibly stale",maybeStaleColor,finished); } return; } //otherwise, check the to see if there are any elseif(response.query.alldeletedrevisions.length>0) { vardeletedTimestamp=newDate(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=cuStaleDateFormatter(deletedTimestamp,""+indexString,"Contrib"); if(currentTimestamp-deletedTimestamp.getTime()<timestampDifference) { cuStaleInsertStalenessIndicator(cuLogLinks,message+"last (deleted) edit "+formattedDate+", not stale",notStaleColor,finished); return; } else { cuStaleInsertStalenessIndicator(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) { cuStaleInsertStalenessIndicator(cuLogLinks,message+"last edit "+formattedDate+", not stale",notStaleColor,finished); } else { cuStaleInsertStalenessIndicator(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) { cuStaleInsertStalenessIndicator(cuLogLinks,message+"last edit "+formattedDate+", not stale",notStaleColor,finished); } else { cuStaleInsertStalenessIndicator(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) { cuStaleInsertStalenessIndicator(cuLogLinks,message+"last edit "+formattedDate+", not stale",notStaleColor,finished); } else { cuStaleInsertStalenessIndicator(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(!response||!response.query){ return; } //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 elseif(typeofresponse.error!=="undefined"&&response.error.code=="permissiondenied") { canViewDeleted=false; if(notStale) { cuStaleInsertStalenessIndicator(cuLogLinks,message+"no visible contribs, not stale",notStaleColor,finished); } else { cuStaleInsertStalenessIndicator(cuLogLinks,message+"no visible contribs, possibly stale",maybeStaleColor,finished); } return; } //otherwise, check the to see if there are any elseif(response.query.alldeletedrevisions.length>0) { vardeletedTimestamp=newDate(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=cuStaleDateFormatter(deletedTimestamp,""+indexString,"Contrib"); if(currentTimestamp-deletedTimestamp.getTime()<timestampDifference) { cuStaleInsertStalenessIndicator(cuLogLinks,message+"last (deleted) edit "+formattedDate+", not stale",notStaleColor,finished); return; } else { if(notStale) { cuStaleInsertStalenessIndicator(cuLogLinks,message+"last (deleted) edit "+formattedDate+", not stale",notStaleColor,finished); } else { cuStaleInsertStalenessIndicator(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) { cuStaleInsertStalenessIndicator(cuLogLinks,message+"no contribs, not stale",notStaleColor,finished); } else { cuStaleInsertStalenessIndicator(cuLogLinks,message+"no contribs, probably stale",maybeStaleColor,finished); } return; } } ); } } } ); } } ); } else { varnewNode="<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(cuStaleResumeStalenessCheck); returnfalse; } }); $.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"); } }); } functioncuStaleDateFormatter(date,index,type) { vardateString=date.getUTCFullYear()+"-"+(date.getUTCMonth()+1)+"-"+date.getUTCDate(); vardatetimeString=dateString+" at "+date.toUTCString().substr(17,8); varmessage="<span id='"+type+index+"' title='"+datetimeString+"'>"+dateString+"</span>"; returnmessage; } functioncuStaleResolvePromise(promise) { returnfunction(){promise.resolve()}; } functioncuStaleResumeStalenessCheck() { $(".cuStalenessContinue").remove(); cuStalePerformStalenessCheck(); } $(document).ready(function() { vartitleRegex=/Wikipedia:Sockpuppet_investigations\/[^\/]+/; //only use on a SPI page (or my sandbox for testing) if(titleRegex.test(mw.config.get("wgPageName"))||mw.config.get("wgPageName")==="User:Writ_Keeper/sandbox") { //load required modules mw.loader.using(['mediawiki.api','mediawiki.Title']).then(function(){ $("span.cuEntry").addClass("cuStaleChecking"); cuStalePerformStalenessCheck(); }); } }); //</nowiki>