User:Martijn Hoekstra/checkrange.js

From Wikipedia, the free encyclopedia
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.
//stuff for sanity-checking rangeblocks
 
var checkrange = {
  check_months : 1,
  check_days : 0,
  check_years : 0,
  min_edits : 1,
  ip_prefixes : [],
  range : "92.41.0.0/22",
  ips : {},
  num_ips : 0,
  startdate: {},

  addlink : function() {
    return mw.util.addPortletLink(
    	"p-cactions",
    	"#",
    	"Check range",
    	"ca-rangeChecker",
    	"Check range"
    	);
  },

  init : function() {
  	console.debug("called init");
    this.num_ips = 0;
    this.ips = {};
    this.show_form();
    var default_startdate = this.get_default_startdate();
    var default_minedits = this.min_edits;
    var default_range = "";
    var ranges_on_page = document.body.innerHTML.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}/);
    if (ranges_on_page ){
      default_range = ranges_on_page[0];
    }
    mw.log("default range:" + default_range);
    document.getElementById("checkrange_range").value = default_range;
    document.getElementById("checkrange_minedits").value = default_minedits;
    document.getElementById("checkrange_startyear").value = default_startdate.getFullYear();
    document.getElementById("checkrange_startmonth").value = (default_startdate.getMonth() + 1);
    document.getElementById("checkrange_startdate").value = default_startdate.getDate();
  },

  get_default_startdate : function() {
    var now = new Date();
    return new Date(now.getUTCFullYear() - this.check_years, now.getUTCMonth() - this.check_months, now.getUTCDate() - this.check_days);
  },

   
  show_form : function() {
    var form = '<div id="checkrange_form">' + 
               '<h3>Give parameters for the block you want to test</h3>' + 
               '<label>start date: (year, month, day)</label>' + 
               '<input type="text" id="checkrange_startyear" "name=checkrange_startyear" size="4" maxlength="4" />' + 
               '<input type="text" id="checkrange_startmonth" name="checkrange_startmonth" size="2" maxlength="2" />' +
               '<input type="text" id="checkrange_startdate" name="checkrange_startmonth" size="2" maxlength="2" /> <br />' +
               '<label for="checkrange_minedits">with at least</label>'+
               '<input type="text" id="checkrange_minedits" name = "checkrange_minedits" size="2" maxlength="2">' +
               '<label for="checkrange_minedits">edits in this period</label><br />' + 
               '<label for="checkrange_range">range:</label>' +
               '<input type="text" id="checkrange_range" name="checkrange_range">' +
               '<input type="button" id="checkrange_start" name="checkrange_start" value="calculate" onclick="checkrange.start_check()" />' + 
               '</div>';
    mediaWiki.notify(form);
  },

  start_check : function(){
    var startyear = parseInt(document.getElementById("checkrange_startyear").value, 10);
    var startmonth = parseInt(document.getElementById("checkrange_startmonth").value, 10) - 1;
    var startdate = parseInt(document.getElementById("checkrange_startdate").value, 10);
    this.startdate = new Date(startyear, startmonth, startdate);
    var myrange = document.getElementById("checkrange_range").value;
    var found = myrange.match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}/);
    if (found){
      this.range = found[0];
    } else {
      alert("misformatted range");
      return;
    }
    var my_min_edits = parseInt(document.getElementById("checkrange_minedits").value);
    if (isNaN(my_min_edits)){
      alert("misformatted min edits");
      return;
    } else {
      this.min_edits = my_min_edits;
    }
    this.get_recently_active_ips();
  },

  showbox : function() {
    var message = "<h1>getting active IP's</h1>";
    message += "prefixes:<ul id='prefixlist'></ul>";
    message += "unique IP's <span id='IPs'>0</span>";
    mediaWiki.notify(message);
  },
 
  add_prefix : function(prefix){ 
    this.ip_prefixes.push(prefix);
    var msg_prefixes = document.getElementById('prefixlist');
    var listitem = document.createElement('li');
    listitem.appendChild(document.createTextNode(prefix + ' ' ));
    var s = document.createElement("span");
    s.id = prefix;
    s.innerText = 'fetching';
    listitem.appendChild(s);
    msg_prefixes.appendChild(listitem);
  },

  get_recently_active_ips : function (){
    var used_ips = {};
    this.showbox();
    this.get_active_ips();
 },

  get_active_ips: function(){
    var calls = this.construct_api_calls();
    for (var next_call in calls){
      this.get_ips(calls[next_call], calls[next_call]);
    }
  },

  get_ips : function(base_url, call_url){
    var prefix = call_url.match(/ucuserprefix=([^&]*)/)[1];
    $.getJSON(call_url, function(data) {
      var usercontribs = data.query.usercontribs;
      for(var item in usercontribs){
        var realitem=usercontribs[item];
        if (checkrange.check_timestamp(realitem.timestamp)){
          if (checkrange.ips.hasOwnProperty(realitem.user)){
            checkrange.ips[realitem.user] ++;
          } else {
            checkrange.ips[realitem.user] = 1;
          }
          if (checkrange.ips[realitem.user] == checkrange.min_edits) {
             checkrange.num_ips += 1;
             document.getElementById("IPs").innerText=checkrange.num_ips;
          }
        }
      }
      if (data.hasOwnProperty("query-continue")){
        var next_call_postfix = data["query-continue"].usercontribs.uccontinue;
        if (next_call_postfix){
          mw.log("more for "+prefix);
          mw.log(base_url + "&uccontinue="+next_call_postfix);
          document.getElementById(prefix).innerText='fetching more';
          checkrange.get_ips(base_url, base_url + "&uccontinue="+next_call_postfix);
        } else {
          mw.log("huh? no next_call_postfix, but there is a query-continue");
          mw.log(data("query-continue"));
        }
      } else {
        document.getElementById(prefix).innerHTML='<b>done</b>';
        mw.log("done for "+prefix);
      }
    });
  },

  check_timestamp : function(timestamp){
    //2010-10-09T06:22:05Z
    var date = timestamp.split("T")[0];
    var year = parseInt(date.substring(0,4), 10);
    var month = parseInt(date.substring(5,2), 10)-1;
    var day = parseInt(date.substring(8,2), 10);
    var timestamp_date = new Date(year, month, day);
    return (timestamp_date > this.startdate);
  },

  construct_api_calls : function(){
//    var api_call_base_url = "https://en.wikipedia.org/w/api.php?action=query&list=usercontribs&format=json&rawcontinue=&ucuserprefix=";
    var api_call_base_url = "/w/api.php?action=query&list=usercontribs&format=json&rawcontinue=&ucuserprefix=";
    var api_calls = [];
    this.ip_prefixes = [];
    this.get_prefixes();
    for (var prefix in this.ip_prefixes){
      api_calls.push(api_call_base_url + this.ip_prefixes[prefix]);
      mw.log(api_call_base_url + this.ip_prefixes[prefix]);
    }
    return api_calls;
  },

  get_prefixes_notdone : function(){
    var prefixes = [];
    var parts = this.range.split('/');
    var start = parts[0];
    var size = parseInt(parts[1]);
    var num_fixed_octets = Math.floor((size + 1)/8);
    mw.log("fixed octets: " + num_fixed_octets);
    var octets = $.map(start.split('.'), function(n){
      return parseInt(n);
    });
    mw.log(octets);
    var factor = (8 * (num_fixed_octets +1) - size) % 8;
    mw.log("factor: " + factor);
    if (!confirm("factor: " + factor)){
      return;
    }
    var num_blocks = 1 << factor;
    mw.log('num blocks: ' + num_blocks);
    var max_octet = octets[num_fixed_octets] + num_blocks - 1;
    mw.log('max octet: ' + max_octet);
    var current_octet = octets[num_fixed_octets];
    while(current_octet <= max_octet){
    mw.log('current octet: ' + current_octet);
      var prefix = "";
      for(var i = 0; i < num_fixed_octets; i++){
        prefix += octets[i] + '.';
      }
      prefix += current_octet;
      if (size > 24) prefix += '.';
      this.add_prefix(prefix);
      mw.log(prefix);
      current_octet++;
    }
  },

  get_prefixes : function(){
    var prefixes = [];
    var parts = this.range.split('/');
    var start = parts[0];
    var size = parseInt(parts[1]);

    var octets = $.map(start.split('.'), function(n){
      return parseInt(n);
    });

    var range = this.range.split('.');

    var octet1 = parseInt(range[0]);
    var octet2 = parseInt(range[1]);
    var octet3 = parseInt(range[2]);
    var octet4 = parseInt(range[3]);
    
    var factor = 0;
    var num_blocks = 1;
 
    //now the annoying part
    if (size <= 8) {
      factor = 8 - size;
      num_blocks = 1 << factor;
      max_octet = octets[0] + num_blocks - 1;
      var current_octet = octets[0];
      while(current_octet1 <= max_octet1){
        this.add_prefix(current_octet.toString() + '.');
        current_octet++;
      }
    } else if (size > 8 && size <= 16){
      factor = 16 - size;
      num_blocks = 1 << factor;
      max_octet2 = octet2 + num_blocks - 1;
      var current_octet2 = octet2;
      while(current_octet2 <= max_octet2){
        this.add_prefix(octet1.toString() + '.' + current_octet2.toString() + '.', prefixes);
        current_octet2++;
      }
    } else if (size > 16 && size <= 24){
      factor = 24 - size;
      num_blocks = 1 << factor;
      max_octet3 = octet3 + num_blocks - 1;
      var current_octet3 = octet3;
      while(current_octet3 <= max_octet3){
        this.add_prefix(octet1.toString() + '.' + octet2.toString() + '.' + current_octet3.toString() + '.');
        current_octet3++;
      }
    } else {
      factor = 32 - size;
      var num_d = 1 << factor;
      max_octet4 = octet4 + num_d - 1;
      var current_octet4 = octet4;
      while(current_octet4 <= max_octet4){
        this.add_prefix(octet1.toString() + '.' + octet2.toString() + '.' + octet3.toString() + '.' + current_octet4.toString());
        current_octet4++;
      }
    }
  }
}

jQuery( function(){
  var link = checkrange.addlink();
  console.debug("link is", link);
  link.click(function(e){
  	e.preventDefault();
  	checkrange.init()
  	});
});

// Expose globally
window.checkrange = checkrange;