9

There are questions about searching for Unregistered users such as Is there a way to sift through a list of unregistered users? but none appear address this or provide a solution to what I desire.

I would like to have a (moderator) tool to view a list of Unregistered users ranked by reputation.

This would be useful for finding users who should be encouraged to register an account, among other things.

1

You can use the Stack API to get that list.

The user_type is an attribute of the user with these possible values:

unregistered, registered, moderator, or does_not_exist

by calling the /users endpoint you get a paged resultset with 100 users per page. By simply requesting the next page until no more records are returned you can inspect all users on the site. In this case I check if the user has an user_type that is 'unregistered' and if so, add a row for that user to the table.

I have limited the number of pages to 10 by default. You can enter a higher number if you wish but the API will throttle you if you fire > 10000 requests per day.

var SEApi;

// build api url for an endpoint and its optional parameters
function apiBuilder(endpoint, params) {
  var url = 'https://api.stackexchange.com/2.2/',
      urlPath = url + endpoint;
  params.key ='zHcti*qApcyvicd06oAFog((';
  if (params !== undefined)  {
    var query = [];
    for(var prop in params) {
      if (params.hasOwnProperty(prop)) {
        query.push( prop + '=' + encodeURI(params[prop]));
      }
    }
    urlPath = urlPath + '?' + query.join('&');
  }
  return urlPath;
}

// build url for /users endpoint
function apiUserBuilder(site, page) {
 return apiBuilder(
    'users', 
    {
      site: site,
      order: 'asc',
      page: page,
      pagesize: 100,
      sort: 'reputation',
      filter: '!T6oHhgf634-miq)LJo'
    });
}
 
// build url for /sites api endpoint
function apiSitesBuilder() {
  return apiBuilder(
    'sites', 
    {
      pagesize: 500,
      filter: '!2--Yion.3M.K5PJ6Ea0*R'
    });
}

// do a get on the API for the given url
// and invoke the callback with the JSON result
function API () {
  
  var backlog = [],
      getfunction;
  
  // simply push the params on the queue
  function cacheget(url, callback) {
    backlog.push({ url: url, callback: callback});
  }
  
  // this makes the actual xhr call
  function realget(url, callback) {
    var xhr = new XMLHttpRequest();
    
    // handles pending calls by invoking realget
    // and resetting the getfunction when 
    // the backlog is cleared
    function handleBacklog() {
      var item = backlog.shift();
      if (item !== undefined) {
        console.log('from cache');
        // handle this single item
        realget(item.url, item.callback);
      } 
      if (backlog.length === 0) {
        // if the backlog is empty 
        // use realget for the next call
        getfunction = realget;
      }
    }
    
    xhr.addEventListener('error', function () {
       console.log(xhr.status);
    });
    
    xhr.addEventListener('load', function () {
      var response = JSON.parse(xhr.responseText);
      var backoff = response.backoff || 0;
      // backoff received
      if (backoff > 0) {
        // start caching calls
        console.log('backoff recv');
        getfunction = cacheget;
      }
      if (response.error_id === 502) {
         console.log(reponse.error_message);
         getfunction = cacheget;
         backoff = 120; 
      }
      // process pending backlog 
      setTimeout(handleBacklog, backoff * 1000);
      // invoke the callback 
      callback(response);
    });
    xhr.open('GET', url);
    xhr.send();
  }
  
  // calls either xhr or the cache
  function get(url, callback)
  {
    getfunction(url, callback);
  }
  
  // initially we start with a realget
  getfunction = realget;
  
  // return the public api
  return {
    get: get
  }
}

SEApi = new API(); // keep an instance

// shows a message in the top div
function showMessage(msg) {
  document.getElementById('msg')
          .textContent = msg;
}

// format a date as YYYY-MM-DD
function formatDate(d) {
  return 1900 + d.getYear() 
         + '-' 
         + ('0' + d.getMonth()).slice(-2)
         + '-'
         + ('0' + d.getDate()).slice(-2);
}

// add a single user to the table row
function addUser(user) {
  var tr = document.createElement('tr'),
      td = document.createElement('td'),
      a = document.createElement('a'),
      lad;
  a.textContent = user.display_name;
  a.href = user.link;
  td.appendChild(a);
  tr.appendChild(td);
  td = document.createElement('td');
  lad = new Date(user.last_access_date*1000);
  td.textContent = formatDate(lad);
  tr.appendChild(td);
  return tr;
}

// handle user to add them to the result table
function addUsers(items) {
   var i,
       tb = document.getElementById('result');
   for(i = 0; i < items.length; i = i + 1) {
     // check if this user belongs in our result set
     if (items[i].user_type === 'unregistered') {
       tb.appendChild(addUser(items[i]));     
     }
   }
}

// get users on a specific page
function processUserPage(site, page, maxpage) {

  showMessage('Loading ' + page + ' ...');
  // call hand hadle result of userlist
  SEApi.get(apiUserBuilder(site, page), function (result) {
    if ( result.items && 
        (result.items.length > 0) &&
         page < maxpage) {
      addUsers(result.items);
      // wait the backoff (or 1 second at least)
      setTimeout(function () {
        processUserPage(site, page + 1, maxpage);
        }, (result.backoff || 1) * 1000);
    } else {
      showMessage('Done ...');
    }
  });
}

// site changed
function siteChanged(site) {
   var sp = document.getElementById('startpage'),
       startpage = parseInt(sp.value, 10),
       mp = document.getElementById('maxpages'),
       maxpages = parseInt(mp.value,10);
   // start processing, will be async
   processUserPage(site, startpage, startpage + maxpages);
   // remove current results
   var node = document.getElementById('result');
   while(node.firstChild) {
      node.removeChild(node.firstChild);
   }
}

// loadsites
// keep site records in allsites array
function  loadSites() {
  SEApi.get(apiSitesBuilder(), function(result) {
     var i, 
         sites = document.getElementById('sites'), 
         option;
      // loop over the items, being site types
      
      for(i = 0; i < result.items.length; i = i + 1) {
        // add site selection element
        option = document.createElement('option');
        option.textContent = result.items[i].name;
        option.value = result.items[i].api_site_parameter;
        sites.appendChild(option);
      }
      sites.selectedIndex = -1;
      sites.addEventListener('change', function() {
        if (sites.selectedIndex !== -1) {
          siteChanged(
              sites.options[sites.selectedIndex].value
          );
        }
      });
      showMessage('Enter # of pages and select a site ...');
   });
}

// hookup search button and start loadsites
function init() {
  showMessage('Loading ...');
  loadSites();
}

// startup!
init();
table { border: solid black 1px;}
div {padding: 5px; }
th {font-style: bold; padding-bottom: 5px;}
label { display: inline-block; width: 70px; }
input {width: 100px;}
span {display: inline-block; width: 20px;}
<div id="msg">Start</div>
<div>
<label for="maxpages">Max pages</label>
<input id="maxpages" type="number" value="10" maxlength="5"/>
<span>&nbsp;</span><label for="startpage">Start page</label>
<input id="startpage" type="number" value="1" maxlength="5"/>
</div>
<div>
<label for="sites">Site</label>
<select id="sites">
</select>
<div>
<hr/>
<table>
  <thead>
    <tr>
      <th>user</th>
      <th>last_access_date</th>
    </tr>
  </thead>
  <tbody id="result">
  
  </tbody>
</table>

|improve this answer|||||

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .