Jump to content

User:Splarka/ajaxmassrollback.js

From Wikipedia, the free encyclopedia
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/* Ajax mass user-rollback, version [0.0.1b]
Originally from: http://en.wikipedia.org/wiki/User:Splarka/ajaxmassrollback.js

Notes:
* Oh god this is ugly code. Haha.
* This does not revert moves but thinks it does. Not sure how to skip them either. BE AWARE.
* This only goes back 7 (configurable) days by default, but should work with any number of contribs in that timeframe.

Operation:
* Gets user's contribs (query-continues until reaching the time limit).
** For each contrib that is (top) and not (new) it leaves a checkbox (and info/links).
* After selecting which to rollback via checkboxes, it iterates over these checkboxes.
** For each revid, it gets the rollback token, title, and user.
*** Upon getting the token, it attempts rollback.
**** If successful, checkbox is unchecked and next is selected (after 1 second delay).

To do:
* Delete link for pages created by user? Maybe.
* Rewrite for efficiency when generator=usercontribs becomes implemented! Oh yah.
* Markbot optional?
* Reason field?
*/

var amrNumContribs;
if(!window.amrNumDays) var amrNumDays = 7
var amrWorking = false;

if((mw.config.get('wgNamespaceNumber') == 2 || mw.config.get('wgNamespaceNumber') == 3) && mw.config.get('wgTitle').indexOf('/') == -1 && (mw.config.get('wgAction') != 'edit' || mw.config.get('wgAction') != 'submit') && true) $(function() {
  mw.util.addPortletLink('p-cactions','/wiki/Special:BlankPage?blankspecial=ajaxmr&user=' + encodeURIComponent(mw.config.get('wgTitle')),'Mass Rollback','p-mr');
});

if(mw.config.get('wgCanonicalSpecialPageName') && mw.config.get('wgCanonicalSpecialPageName') == 'Contributions' && true) $(function() {
  var ucfrm = document.getElementsByTagName('form')[0];
  var targ = '';
  if(ucfrm.target && ucfrm.target.value != '') {
    targ = '&user=' + encodeURIComponent(ucfrm.target.value);
  }
  mw.util.addPortletLink('p-cactions','/wiki/Special:BlankPage?blankspecial=ajaxmr' + targ,'Mass Rollback','p-mr');
});

if(mw.config.get('wgCanonicalSpecialPageName') && mw.config.get('wgCanonicalSpecialPageName').toLowerCase() == 'blankpage' && queryString('blankspecial') == 'ajaxmr') {
  document.title = 'Ajax Mass Rollback';
  addOnloadHook(amrForm);
  appendCSS('#amr-contriblist {border:2px solid black;margin:.7em .1em;padding:.5em;height:20em;overflow:auto;}'
  + '\n#amr-contriblist li {white-space:nowrap;} .amr-step1 {background-color:#ffff99;} .amr-step2 {background-color:#9999ff;} .amr-step3 {background-color:#99ff99;}');
}

function amrForm() {
  //subvert this Special: page to our own needs.
  var con = document.getElementById('content') || document.getElementById('mw_content');
  var bcon = document.getElementById('bodyContent') || document.getElementById('mw_contentholder');
  var fh = getElementsByClassName(con,'h1','firstHeading')[0];
  while(fh.firstChild) fh.removeChild(fh.firstChild)
  fh.appendChild(document.createTextNode('Ajax Mass Rollback'));
  for(var i=0;i<bcon.childNodes.length;i++) {
    bcur = bcon.childNodes[i];
    if(bcur.id != 'siteSub' && bcur.id != 'contentSub' && bcur.className != 'visualClear') {
      while(bcur.firstChild) bcur.removeChild(bcur.firstChild)
      if(bcur.nodeType == 3) bcur.nodeValue = '';
    }
  }

  var form = document.createElement('form');
  form.setAttribute('action','javascript:void(0)');
   var lab1 = document.createElement('label');
    lab1.setAttribute('for','amr-user')
    lab1.appendChild(document.createTextNode('User (vandal): '));
   form.appendChild(lab1);
   var inp1 = document.createElement('input');
    inp1.style.width = '20em';
    inp1.setAttribute('type','text');
    if(queryString('user')) inp1.setAttribute('value',queryString('user'));
    inp1.setAttribute('id','amr-user');
   form.appendChild(inp1);
   var sub1 = document.createElement('input');
    sub1.setAttribute('type','button');
    sub1.setAttribute('id','amr-getcontribs');
    sub1.setAttribute('value','start');
    sub1.setAttribute('onclick','amrGetContribs()');
   form.appendChild(sub1);
   var ul = document.createElement('ul');
    ul.setAttribute('id','amr-contriblist');
   form.appendChild(ul);
  bcon.appendChild(form);
  var pre = document.createElement('pre');
   pre.setAttribute('id','amr-output');
  bcon.appendChild(pre);
}

function amrGetContribs(tsoffset) {
  var start = '';
  if(tsoffset) {
    start = '&ucstart=' + tsoffset;
  } else {
    if(amrWorking) return
    amrWorking = true;
    document.getElementById('amr-user').setAttribute('disabled','disabled');
    injectSpinner(document.getElementById('amr-getcontribs'),'getcontribs-spin');
    var ul = document.getElementById('amr-contriblist');
    while(ul.firstChild) ul.removeChild(ul.firstChild)
    amrNumContribs = 0;
  }
  var user = document.getElementById('amr-user').value;
  var now = new Date();
  var stop = parseInt(now.getTime() / 1000) - 86400 * amrNumDays;
  var url = mw.config.get('wgScriptPath') + '/api.php?action=query&format=json&list=usercontribs&ucprop=flags|title|ids|comment|timestamp&uclimit=50' + start + '&ucend=' + stop + '&ucuser=' + encodeURIComponent(user);

  var req = sajax_init_object();
  req.open('GET', url, true);
  req.onreadystatechange = function() {
    if(req.readyState == 4 && req.status == 200) {
      eval("amrPopulatContribs(" + req.responseText + ",'" + req.responseText.replace(/\'/g,"`") + "')");
    }
  }
  req.send(null);
}

function amrPopulatContribs(obj,txt) {
  var ul = document.getElementById('amr-contriblist');
  if(obj['error']) {
    ul.parentNode.appendChild(document.createTextNode('Api error: ' + obj['error']['code'] + ' - ' + obj['error']['info'] + '\n'));
    return;
  }
  if(!obj['query'] || !obj['query']['usercontribs']) {
    ul.parentNode.appendChild(document.createTextNode('Unexpected response: ' + txt + '\n'));
    return;
  }
  var uc = obj['query']['usercontribs'];
  for(var i=0;i<uc.length;i++) {
    if(uc[i]['new'] == '') {
      // delete link?
    } else if(uc[i]['top'] == '') {
      var li = document.createElement('li');
       var inp = document.createElement('input');
        inp.setAttribute('type','checkbox');
        inp.setAttribute('checked','checked');
        inp.setAttribute('class','amr-cl');
        inp.setAttribute('title',uc[i].title);
        inp.setAttribute('id','amr-cl-' + uc[i].revid);
       li.appendChild(inp);
       var lab = document.createElement('label');
        lab.setAttribute('for','amr-cl-' + uc[i].revid);
        lab.appendChild(document.createTextNode(uc[i].timestamp.replace(/[TZ]/g,' ')));
       li.appendChild(lab);
       li.appendChild(document.createTextNode('('));
       addlinkchild(li, mw.config.get('wgScript') + '?curid=' + uc[i].pageid + '&diff=prev&oldid=' + uc[i].revid,'diff');
       li.appendChild(document.createTextNode(') ('));
       addlinkchild(li, mw.config.get('wgScript') + '?curid=' + uc[i].pageid + '&action=history','hist');
       li.appendChild(document.createTextNode(') . . '));
       addlinkchild(li, mw.config.get('wgScript') + '?curid=' + uc[i].pageid,uc[i].title);
       if(uc[i].comment) li.appendChild(document.createTextNode(' (' + uc[i].comment + ')'))
      ul.appendChild(li);
      amrNumContribs++;
    }
  }

  if(obj['query-continue'] && obj['query-continue']['usercontribs'] && obj['query-continue']['usercontribs']['ucstart']) {
    amrGetContribs(obj['query-continue']['usercontribs']['ucstart']);
  } else {
    amrWorking = false;
    document.getElementById('amr-user').removeAttribute('disabled');
    removeSpinner('getcontribs-spin');
    var li = document.createElement('li');
     li.appendChild(document.createTextNode(amrNumContribs + ' top contributions found for user (over last ' + amrNumDays + ' days). '));
     var sub = document.createElement('input');
      sub.setAttribute('type','button');
      sub.setAttribute('id','amr-startrollbacks');
      sub.setAttribute('value','rollback selected');
      sub.setAttribute('onclick','amrRollbackContribs()');
     li.appendChild(sub);
    ul.insertBefore(li,ul.firstChild);
  }
}

function amrRollbackContribs(automated) {
  var out = document.getElementById('amr-output');
  if(!automated) {
    if(amrWorking) return
    amrWorking = true;
    injectSpinner(document.getElementById('amr-startrollbacks'),'startrollbacks-spin');
  }

  var ul = document.getElementById('amr-contriblist');
  var ucs = getElementsByClassName(ul,'input','amr-cl');
  var uc = false;

  for(var i=0;i<ucs.length;i++) {
    if(ucs[i].checked && ucs[i].parentNode.className == '') {
      uc = ucs[i];
      break;
    }
  }

  if(!uc) {
    out.appendChild(document.createTextNode('* Done!'));
    amrWorking = false;
  } else {
    var id = uc.id.replace(/amr\-cl\-/,'');
    uc.parentNode.className = 'amr-step1';
    uc.removeAttribute('checked');
    var page = uc.title;
    out.appendChild(document.createTextNode('> Attempting to rollback [[' + page + ']]\n'));
    amrGetToken(id,page);
  }
}

function amrGetToken(id,page) {
  var out = document.getElementById('amr-output');
  out.appendChild(document.createTextNode(' > Fetching rollback token for [[' + page + ']]\n'));
  var url = mw.config.get('wgScriptPath') + '/api.php?action=query&format=json&prop=revisions&indexpageids&rvprop=user|ids&rvtoken=rollback&revids=' + id;
  var req = sajax_init_object();
  req.open('GET', url, true);
  req.onreadystatechange = function() {
    if(req.readyState == 4 && req.status == 200) {
      eval("amrRollback(" + req.responseText + ",'" + req.responseText.replace(/\'/g,"`") + "')");
    }
  }
  req.send(null);
}

function amrRollback(obj,txt) {
  var out = document.getElementById('amr-output');
  if(obj['error']) {
    out.appendChild(document.createTextNode(' ! Api error: ' + obj['error']['code'] + ' - ' + obj['error']['info'] + '\n'));
    return;
  }
  if(!obj['query'] || !obj['query']['pageids'] || !obj['query']['pages'][obj['query']['pageids'][0]]) {
    out.appendChild(document.createTextNode('  ? Unexpected response: ' + txt + '\n'));
    return;
  }
  var pid = obj['query']['pages'][obj['query']['pageids'][0]];
  if(!pid['title'] || !pid['revisions'] || !pid['revisions'][0] || !pid['revisions'][0]['user'] || !pid['revisions'][0]['revid'] || !pid['revisions'][0]['rollbacktoken']) {
    out.appendChild(document.createTextNode('  ?? Unexpected response: ' + txt + '\n'));
    return;
  }
  var id = pid['revisions'][0]['revid'];
  var uc = document.getElementById('amr-cl-' + id);
  if(uc) uc.parentNode.className = 'amr-step2'
  var user = pid['revisions'][0]['user'];
  var token = pid['revisions'][0]['rollbacktoken'];
  var title = pid['title'];
  out.appendChild(document.createTextNode('  > Token found, attempting rollback\n'));

  var params = 'action=rollback&format=json&markbot=1&token=' + encodeURIComponent(token) + '&title=' + encodeURIComponent(title) + '&user=' + encodeURIComponent(user);
  var url = mw.config.get('wgScriptPath') + '/api.php';

  var req = sajax_init_object();
  req.open('POST', url, true);
  req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
  req.setRequestHeader('Content-length', params.length);
  req.setRequestHeader('Connection', 'close');
  req.onreadystatechange = function() {
    if(req.readyState == 4 && req.status == 200) {
      eval("amrRollbackAftermath(" + req.responseText + ",'" + req.responseText.replace(/\'/g,"`") + "')");
    }
  }
  req.send(params);
}

function amrRollbackAftermath(obj,txt) {
  var out = document.getElementById('amr-output');
  if(obj['error']) {
    out.appendChild(document.createTextNode('   ! Api error: ' + obj['error']['code'] + ' - ' + obj['error']['info'] + '\n'));
  } else if(obj['rollback'] && obj['rollback']['title']) {
    var rb = obj['rollback'];
    out.appendChild(document.createTextNode('   > Page [[' + rb['title'] + ']] rollbacked ('));
    addlinkchild(out, mw.config.get('wgScript') + '?curid=' + rb['pageid'] + '&diff=next&oldid=' + rb['old_revid'],'diff');
    out.appendChild(document.createTextNode(').\n'));
    if(obj['rollback']['old_revid']) {
      var uc = document.getElementById('amr-cl-' + obj['rollback']['old_revid']);
      uc.setAttribute('disabled','disabled');
      if(uc) uc.parentNode.className = 'amr-step3'
    }
  } else {
    out.appendChild(document.createTextNode('   ? Unexpected response: ' + txt + '\n'));
    return;
  }
  setTimeout('amrRollbackContribs(true)',1000);
}

function addlinkchild(obj,href,text,id,classes) {
  if(!obj || !href || !text) return false;
  var a = document.createElement('a');
  a.setAttribute('href',href);
  a.appendChild(document.createTextNode(text));
  if(id) a.setAttribute('id',id);
  if(classes) a.setAttribute('class',classes);
  obj.appendChild(a);
  return a;
}

function queryString(p) {
  var re = RegExp('[&?#]' + p + '=([^&#]*)');
  var matches;
  if (matches = re.exec(document.location)) {
    try { 
      return decodeURI(matches[1]);
    } catch (e) {
    }
  }
  return null;
}