5

Is there any easy way to see how many users on a site have attained a particular privilege?

For example, the number of users on this site who have the 3,000 reputation needed to cast close/re-open votes.

  • Data Explorer, as always. Easy enough to count users by their reputation in there. e.g data.stackexchange.com/meta.stackexchange/query/625740/… – Shadow9 Feb 8 '17 at 23:31
  • @ShadowWizard I'm hoping for something via the browser GUI of the Main sites. SEDE is only easy for some. – PolyGeo Feb 8 '17 at 23:33
  • I can come with a more flexible query tomorrow where you will be able to say the desired reputation, or even what privilege. As for main site GUI, no such thing. Only thing I can think of is client side scripting to go over the user pages automatically and count them. – Shadow9 Feb 8 '17 at 23:35
  • @ShadowWizard That SEDE query above did the trick for now but your more flexible query tomorrow is certainly something that I would accept as an answer if there is nothing in the GUI. – PolyGeo Feb 8 '17 at 23:39
  • Well, you got two ways without SEDE, both actually better... :-) – Shadow9 Feb 9 '17 at 13:41
  • @ShadowWizard srsly: data.stackexchange.com/stackoverflow/query/… – rene Feb 9 '17 at 17:54
  • @rene lol, I meant something like you'll input a privilege name and the query will know to translate it to required reputation. :) – Shadow9 Feb 9 '17 at 19:22
  • @rene well, we can always just hard code it. – Shadow9 Feb 9 '17 at 19:33
  • I think doing this by privilege name would be overkill especially since privilege numbers, names and rep levels are not written in stone. – PolyGeo Feb 9 '17 at 19:37
7

The closest thing I can think of is the reputation league table per site which can be reached by going to the Users tab of a site and clicking reputation leagues at the bottom of that page.

enter image description here

It kind of misses the 15K and a lot of the lower reputation level, but it is as simple as it gets

  • But the results would not exclude users whose accounts are or have been inactive for six or more months. – Mari-Lou A Feb 9 '17 at 11:38
  • No it would not - but it does fit what's said in the comments to the main question. You trade ease for completeness I guess? ;p – Journeyman Geek Feb 9 '17 at 11:39
  • Well, if the OP is only interested in bare statistics, then the proffered solution is easy and effective. If the OP wants statistics to support an argument, the data needs to be more complete. If only five users out of twenty have active accounts (hypothesis) that's very relevant. – Mari-Lou A Feb 9 '17 at 11:44
  • OP's got two alternate methods - one promised in comments, one in actual answers then – Journeyman Geek Feb 9 '17 at 12:33
8
+50

You can leverage the Stack Exchange API for that.

The /users endpoint offers an 'min' search parameter, which can be used to query the field you sort on, in this scenario that will be reputation.

I created below Stack Snippet to fetch all sites and then offers you to select a site and a reputation level.
After selecting the site, the privileges are fetched as well as those can vary per site.
Click on the calculate button to see how many users match the give reputation criteria.
The script will call /users to fetch the total number users with at least that reputation level.

// 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;
  if (params !== undefined)  {
    var query = [];
    for(var prop in params) {
      if (params.hasOwnProperty(prop)) {
        query.push( prop + '=' + params[prop]);
      }
    }
    urlPath = urlPath + '?' + query.join('&');
  }
  return urlPath;
}

// build url for /users endpoint
function apiUsersBuilder(site, rep) {
  return apiBuilder(
    'users', 
    {
      site: site,
      order: 'desc',
      page: 1,
      pagesize: 1,
      min: rep,
      sort: 'reputation',
      filter: '!6XcF36OyeUd48'
    });
}
    
// build url for /sites api endpoint
function apiSitesBuilder() {
  return apiBuilder(
    'sites', 
    {
      pagesize: 500,
      filter: '!2--Yion.3M.K5PJ6Ea0*R'
    });
}

// build url for /privileges api endpoint
function apiPrivilegesBuilder(site) {
  return apiBuilder(
    'privileges', 
    {
      site: site,
      pagesize: 100
    });
}


// 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('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;
      }
      // 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
  }
}

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

// calls the API
function get(url, callback) {
  SEApi.get(url, callback);
}

// for a given site and rep, fetch number of users
// and populate usercount html element
function getPrivilegedUserCount(site, rep) {
  get(
    apiUsersBuilder(site, rep), 
    function (result) {
      var uc = document.getElementById('usercount');
      uc.textContent = result.total;
    });
}

// build option
function buildSiteOption(site) {
  // build option element
  var opt = document.createElement('option');
  opt.value = site.api_site_parameter;
  opt.textContent = site.name;
  return opt;
}

function buildPrivilege(privilege, datalist) {
  var dd,
      num,
      span,
      des;
  dd = document.createElement('dd');
  num = document.createElement('dt');        
  span = document.createElement('span');        
  span.textContent = privilege.reputation;
  num.appendChild(span);
  des =  document.createElement('dd');        
  des.textContent = privilege.short_description;
  dd.appendChild(num);
  dd.appendChild(des);
  datalist.appendChild(dd);
}

// fetch and show privileges for a site
function updatePrivileges(key) {
  get(apiPrivilegesBuilder(key), 
    function (result) {
     var dl = document.getElementById('priv'),
         i;
      while(dl.firstChild) {
        dl.removeChild(dl.firstChild);
      }
      for(i = 0; i < result.items.length; i++) {
        buildPrivilege(
          result.items[i], 
          dl 
        );
      }
  });
}

// loadsites and populate site select list
// keep site records in allsites array
function  loadSites(search) {
  get(apiSitesBuilder(), function(result) {
     var sites = document.getElementById('sites'),
         i;
      // loop over the items, being site types
      for(i = 0; i < result.items.length; i = i + 1) {
        // add site selection element
        sites.appendChild(
          buildSiteOption(result.items[i])
        );
      }
      search.disabled = false;
      sites.addEventListener(
        'change', 
        function(e) {
          var key = sites.item(sites.selectedIndex).value;
          updatePrivileges(key);
        });
      updatePrivileges(sites.item(0).value);
  });
}

// hookup search button and start loadsites
function init() {
  var go = document.getElementById('go');
  go.addEventListener('click', function () {
    var sites = document.getElementById('sites'),
        site,
        siteKey;
    if (sites.selectedIndex > -1) {    
      siteKey = sites.item(sites.selectedIndex).value;
      getPrivilegedUserCount(
        siteKey, 
        document.getElementById('rep').value);
    }
  });
  go.disabled = true;
  loadSites(go);
}

// startup!
init();
label {display:block; padding: 5px;}
select {margin-left: 45px;}
button {padding: 5px; margin: 5px 5px 5px 5px;}
dt { width: 50px; clear:left;float:left;}
dd { margin-left: 25px; }
dt > span { width: 80%; text-align: right; display:inline-block;}
<p>Number of users for a site above given reputation</p>
<label>Site : <select id="sites">
</select>
</label>
<label>
  Reputation :
  <input id="rep" value="3000" type="text"/>
</label>
<div id="result">
  <button id="go">Calculate</button>
  users : <span id="usercount"></span>
</div>
Privileges/reputation
<dl id="priv">
</dl>

  • Wow, this's really cool – Panda Feb 9 '17 at 10:53
  • Many thanks for this @rene I've accepted the other answer because I can get a lot of what I want from the GUI that way, but this is a great intro to using Stack Snippets that are not turned on for my two main sites. I'll try to remeber to reward it with a bounty when it becomes eligible for that tomorrow. – PolyGeo Feb 9 '17 at 22:36

You must log in to answer this question.

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