| var pmcs = [] // array of PMC names (excludes non-PMC committees) |
| var people = {} // public_ldap_people.json |
| var ldapauth = {} // public_ldap_authgroups.json |
| // TODO don't rely on ldap_groups containing PMC :members groups |
| var ldapgroups = {} // public_ldap_groups.json |
| var ldapservices = {} // public_ldap_services.json |
| var ldapprojects = {} // public_ldap_projects.json |
| |
| var members = {} // copy of member-info.json |
| var committees = {} // copy of committee-info.json (plus details for 'member' dummy PMC) |
| var iclainfo = {} // copy of icla-info.json (committers only) |
| var podlings = {} // public_ldap_projects.json where podling is 'current' |
| |
| var info = {} // copies of json info |
| |
| // Constants for query types. |
| // Do NOT change the values once established, as they are part of the public API |
| // For example they may be used in projects.a.o and reporter.a.o |
| // The values are used for matching HTTP queries and linkifying lists (to generate a valid HTML link) |
| |
| var Q_USER = 'user' // search users |
| var Q_PROJECT = 'project' // search PMC names |
| var Q_UID = 'uid' // availid, exact match |
| var Q_PMC = 'pmc' // PMC, exact match |
| var Q_UNIX = 'unix' // LDAP group |
| var Q_CTTE = 'ctte' // LDAP group |
| var Q_SERVICE = 'service' // LDAP group |
| var Q_PODLING = 'podling' // podling (non-LDAP group) |
| var Q_AUTH = 'auth' // podling (LDAP auth group) |
| |
| |
| // Not intended for general use; may change at any time |
| var Q_DEBUG = 'debug' // print some debug info |
| |
| // compatibility shim for IE8 and other older browsers |
| if (!Date.now) { |
| Date.now = function() { |
| return new Date().getTime(); |
| } |
| } |
| |
| // This is faster than parseInt, and it's more obvious why it is being done |
| function toInt(number) { |
| return number | 0 // |
| } |
| |
| var fetchCount = 0; |
| // Fetch an array of URLs, each with their description and own callback plus a final callback |
| // Used to fetch everything before rendering a page that relies on multiple JSON sources. |
| |
| |
| function getAsyncJSONArray(urls, finalCallback) { |
| var obj = document.getElementById('progress'); |
| if (fetchCount == 0) { |
| fetchCount = urls.length; |
| } |
| |
| if (urls.length > 0) { |
| var a = urls.shift(); |
| var URL = a[0]; |
| var desc = a[1]; |
| var cb = a[2]; |
| var xmlHttp = null; |
| if (window.XMLHttpRequest) { |
| xmlHttp = new XMLHttpRequest(); |
| } else { |
| xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); |
| } |
| |
| if (obj) { |
| obj.innerHTML = "loading file #" + (fetchCount - urls.length) + " / " + fetchCount + "<br>" + desc |
| } |
| var start = Date.now() |
| xmlHttp.open("GET", URL, true); |
| xmlHttp.onreadystatechange = function(state) { |
| if (xmlHttp.readyState == 4) { |
| if (cb) { |
| if (xmlHttp.status == 200) { |
| elapsed = Date.now() - start |
| cb(JSON.parse(xmlHttp.responseText)); |
| // must be done after as cb creates the hash |
| info[desc]['elapsed'] = elapsed |
| } else { |
| cb({}); |
| alert("Error: '" + xmlHttp.statusText + "' while loading " + URL) |
| } |
| } |
| getAsyncJSONArray(urls, finalCallback); |
| } |
| } |
| xmlHttp.send(null); |
| } else { |
| if (obj) { |
| obj.innerHTML = "building page content..." |
| } |
| finalCallback(); |
| } |
| } |
| |
| // get list of projects on which uid is a committer |
| function getProjectCommittership(uid) { |
| var cl = [] |
| for (var i in ldapprojects) { |
| if (ldapprojects[i].pmc && ldapprojects[i].members.indexOf(uid) > -1) { |
| cl.push(i) |
| } |
| } |
| return cl |
| } |
| |
| //get list of projects on which uid is an owner (member karma) |
| function getProjectOwnership(uid) { |
| var cl = [] |
| for (var i in ldapprojects) { |
| if (ldapprojects[i].pmc && ldapprojects[i].owners.indexOf(uid) > -1) { |
| cl.push(i) |
| } |
| } |
| return cl |
| } |
| |
| // Get the roster from a json group |
| // returns: all the keys where the uid is [not] a member |
| function getRoster(json, uid, notIn) { |
| var cl = [] |
| for (var i in json) { |
| if (json[i].roster.indexOf(uid) > -1) { |
| if (typeof notIn === 'undefined') { |
| cl.push(i) |
| } else { |
| if (notIn.indexOf(i) == -1) { |
| cl.push(i) |
| } |
| } |
| } |
| } |
| return cl |
| } |
| |
| // get data from committee-info for a person |
| // return [list of pmcs, list of chairs] |
| function getCommitteeRoles(uid) { |
| var pl = [] |
| var ch = [] |
| for (var i in committees) { |
| // Only list actual PMCs |
| if (committees[i].pmc && uid in committees[i].roster) { |
| pl.push(i) |
| } |
| //var chair = committees[i].chair // might not be one (eg members) |
| //if (chair && uid in committees[i].chair) { |
| ch.push(i) |
| //} |
| } |
| return [pl, ch] |
| } |
| |
| function getCommitterName(uid) { |
| var noicla = { |
| 'andrei': '(Andrei Zmievski)', |
| 'pcs': '(Paul Sutton)', |
| 'rasmus': '(Rasmus Lerdorf)' |
| } |
| var name |
| if (uid in people) { // it's possible for a list to contain a uid that is not in people (e.g. andrei in member) |
| name = people[uid].name |
| } |
| if (!name) { |
| name = iclainfo[uid] |
| } |
| if (!name) { // try the backup specials |
| name = noicla[uid] |
| } |
| return name |
| } |
| |
| // Linkify list of group names by adding the appropriate ?type= href |
| |
| function linkifyList(type, names) { |
| var text = '' |
| var index, len, i |
| names.sort() |
| for (i = 0, len = names.length; i < len; ++i) { |
| if (i > 0) { |
| text = text + ", " |
| } |
| text = text + "<a href='?" + type + "=" + names[i] + "'>" + names[i] + "</a>" |
| } |
| return text |
| } |
| |
| // Linkify user ids |
| |
| function userList(ua) { |
| var text = '' |
| var index, len |
| ua.sort() |
| for (index = 0, len = ua.length; index < len; ++index) { |
| if (index > 0) { |
| text = text + ", " |
| } |
| text = text + hiliteMember(ua[index]) |
| } |
| return text |
| } |
| |
| //Linkify URLs |
| |
| function linkifyURLs(ua) { |
| var text = '' |
| var index, len |
| ua.sort() |
| for (index = 0, len = ua.length; index < len; ++index) { |
| if (index > 0) { |
| text = text + ", " |
| } |
| text = text + "<a target='_blank' href='" + ua[index] + "'>" + ua[index] + "</a>" |
| } |
| return text |
| } |
| |
| function showCommitter(obj, uid) { |
| var details = document.getElementById('details_committer_' + uid) |
| if (!details) { |
| details = document.createElement('p') |
| details.setAttribute("id", 'details_committer_' + uid) |
| var cl = getProjectCommittership(uid) // committer(in :members) of these LDAP PMC projects |
| var roles = getCommitteeRoles(uid) |
| var cttees = getProjectOwnership(uid) // member(in :owners) of these LDAP PMC projects |
| var pl = roles[0] // pmc membership |
| var ch = roles[1] // chairs |
| if (isNologin(uid)) { |
| details.innerHTML += "<b>Login is currently disabled</b><br/><br/>" |
| } |
| if (isMember(uid)) { |
| details.innerHTML += "<i>Foundation member</i><br/><br/>" |
| } |
| if (ch.length > 0) { |
| details.innerHTML += "<b>Chair of:</b> " + linkifyList(Q_PMC, ch) |
| if (!isChair(uid)) { |
| details.innerHTML += " <b>Not a member of pmc-chairs!</b>" |
| } |
| details.innerHTML += "<br/><br/>" |
| } |
| var purls = urls(uid) |
| if (purls.length > 0) { |
| details.innerHTML += "<b>Personal URLs:</b> " + linkifyURLs(purls) + "<br/><br/>" |
| } |
| if (cl.length > 0) { |
| details.innerHTML += "<b>Committer on:</b> " + linkifyList(Q_UNIX, cl) + "<br/><br/>" |
| } |
| var nc = [] // On PMC but not in LDAP unix |
| var nl = [] // On PMC but not in LDAP committee |
| var np = [] // Not in PMC even though in LDAP committee |
| var nu = [] // In LDAP committee but not in LDAP unix |
| var pn; |
| if (pl.length > 0) { |
| details.innerHTML += "<b>PMC member of:</b> " + linkifyList(Q_PMC, pl) + "<br/><br/>" |
| for (p in pl) { |
| pn = pl[p] |
| // There is an LDAP PMC group but the uid is not in the committer(:members) group |
| if (isProjectPMC(pn) && cl.indexOf(pn) < 0) { |
| nc.push(pn) |
| } |
| // There is an LDAP PMC group but the uid is not in the committee(:owners) group |
| if (isProjectPMC(pn) && cttees.indexOf(pn) < 0) { |
| nl.push(pn) |
| } |
| } |
| } |
| |
| if (cttees.length > 0) { |
| for (p in cttees) { |
| pn = cttees[p] |
| // name is a PMC but uid is not on the PMC |
| if (isPMC(pn) && pl.indexOf(pn) < 0) { |
| np.push(pn) |
| } |
| // name has LDAP project entry but uid is not in the committer (member) list |
| if (isProjectPMC(pn) && cl.indexOf(pn) < 0) { |
| nu.push(pn) |
| } |
| } |
| details.innerHTML += "<b>LDAP committee group membership:</b> " + linkifyList(Q_CTTE, cttees) + "<br/><br/>" |
| } |
| |
| var services = getRoster(ldapservices, uid) |
| if (services.length > 0) { |
| details.innerHTML += "<b>Service group membership:</b> " + linkifyList(Q_SERVICE, services) + "<br/><br/>" |
| } |
| var auths = getRoster(ldapauth, uid) |
| if (auths.length > 0) { |
| details.innerHTML += "<b>Auth group membership:</b> " + linkifyList(Q_AUTH, auths) + "<br/><br/>" |
| } |
| var pods = getRoster(podlings, uid) |
| if (pods.length > 0) { |
| details.innerHTML += "<b>Podling membership:</b> " + linkifyList(Q_PODLING, pods) + "<br/><br/>" |
| } |
| |
| // Note any discrepancies |
| if (np.length > 0) { |
| details.innerHTML += "<span class='error'>In LDAP committee group, but <b>not a PMC member</b>:</span> " + linkifyList(Q_CTTE, np) + "<br/><br/>" |
| } |
| if (nc.length > 0) { |
| details.innerHTML += "<span class='error'>On PMC, but not a member of the committer group:</span> " + linkifyList(Q_PMC, nc) + "<br/><br/>" |
| } |
| if (nl.length > 0) { |
| details.innerHTML += "<span class='error'>On PMC, but not member of the LDAP committee group:</span> " + linkifyList(Q_CTTE, nl) + "<br/><br/>" |
| } |
| if (nu.length > 0) { |
| details.innerHTML += "<span class='error'>In LDAP committee group but not a member of the committer group:</span> " + linkifyList(Q_UNIX, nu) + "<br/><br/>" |
| } |
| obj.appendChild(details) |
| } else { |
| obj.removeChild(details) |
| } |
| } |
| |
| function hoverCommitter(parent, uid) { |
| var div = document.getElementById('hoverbar') |
| |
| // If the datepicker object doesn't exist, spawn it |
| if (!div) { |
| div = document.createElement('div') |
| document.body.appendChild(div) |
| div.setAttribute("id", "hoverbar") |
| div.style.position = "fixed" |
| div.style.width = "400px" |
| div.style.background = "linear-gradient(to bottom, rgba(254,255,232,1) 0%,rgba(214,219,191,1) 100%)" |
| div.style.borderRadius = "4px" |
| div.style.border = "1px solid #333" |
| div.style.zIndex = "9999" |
| } |
| |
| // Reset the contents of the datepicker object |
| div.innerHTML = "" |
| |
| var bb = parent.getBoundingClientRect() |
| div.style.top = (bb.bottom + 24) + "px" |
| div.style.left = (bb.left + 32) + "px" |
| |
| if (uid) { |
| div.style.display = "block" |
| div.innerHTML = "<h4>" + getCommitterName(uid) + "</h4>" |
| var cl = getProjectCommittership(uid) |
| var roles = getCommitteeRoles(uid) |
| var pl = roles[0] |
| var ch = roles[1] |
| if (isMember(uid) == true) { |
| div.innerHTML += "<i>Foundation member</i><br/><br/>" |
| } |
| if (isNologin(uid)) { |
| div.innerHTML += "<b>Login is currently disabled</b><br/><br/>" |
| } |
| if (ch.length > 0) { |
| ch.sort() |
| div.innerHTML += "<b>Chair of:</b> " + ch.join(", ") |
| if (!isChair(uid)) { |
| div.innerHTML += " <b>Not a member of pmc-chairs!</b>" |
| } |
| div.innerHTML += "<br/><br/>" |
| } |
| if (cl.length > 0) { |
| cl.sort() |
| div.innerHTML += "<b>Committer on:</b> " + cl.join(", ") + "<br/><br/>" |
| } |
| var nc = [] |
| if (pl.length > 0) { |
| pl.sort() |
| div.innerHTML += "<b>PMC member of:</b> " + pl.join(", ") + "<br/><br/>" |
| for (p in pl) { |
| var pn = pl[p] |
| if (pn != 'member' && cl.indexOf(pn) < 0) { |
| nc.push(pn) |
| } |
| } |
| } |
| if (nc.length > 0) { |
| div.innerHTML += "<i>On PMC, but not a Committer on:</i> " + nc.join(", ") + "<br/><br/>" |
| } |
| |
| |
| } else { |
| div.style.display = "none" |
| } |
| } |
| |
| function isNologin(uid) { |
| return !(uid in people) || people[uid].noLogin |
| } |
| |
| function isMember(uid) { |
| return members['members'].indexOf(uid) > -1 |
| } |
| |
| function isChair(uid) { |
| return ldapservices['pmc-chairs'].roster.indexOf(uid) > -1 |
| } |
| |
| function urls(uid) { |
| return people[uid].urls || [] |
| } |
| |
| // Is a PMC according to committee-info |
| function isPMC(name) { |
| return pmcs.indexOf(name) >= 0; |
| } |
| |
| //Is a PMC according to ldap_projects |
| function isProjectPMC(name) { |
| return name in ldapprojects && ldapprojects[name].pmc |
| } |
| |
| function linkifyUid(uid) { |
| if (isNologin(uid)) { |
| return uid |
| } |
| return uid |
| } |
| |
| function hiliteMember(uid) { |
| if (isMember(uid)) { |
| return linkifyUid(uid) |
| } else { |
| return linkifyUid(uid) |
| } |
| } |
| |
| function getChair(uid) { |
| var chair = committees[uid].chair |
| if (chair) { |
| for (var x in chair) { |
| return chair[x].name |
| } |
| } |
| return null |
| } |
| |
| function showProject(obj, prj) { |
| var details = document.getElementById('details_project_' + prj) |
| if (!details) { |
| details = document.createElement('p') |
| details.setAttribute("id", 'details_project_' + prj) |
| var desc = committees[prj].description |
| if (!desc) { |
| desc = 'TBA (please ensure that <a href="http://www.apache.org/index.html#projects-list">the projects list</a> is updated)' |
| } |
| var chair = getChair(prj) |
| if (chair) { |
| details.innerHTML += "<b>Chair:</b> " + chair + "<br/><br/>" |
| } |
| var url = committees[prj].site |
| var cl |
| var clExists = false // Does the unix group exist? |
| try { |
| cl = ldapgroups[prj].roster.slice() |
| clExists = true |
| } catch (err) { // Allow for missing Unix group |
| cl = [] |
| } |
| var pl = [] |
| var pmc = committees[prj] |
| |
| var pmcnoctte = [] // on pmc but not in LDAP committee |
| var cttenopmc = [] // In LDAP ctte but not on PMC |
| var ldappmc = [] |
| var ctteeExists = false |
| if (isProjectPMC(prj)) { // may not exist, e.g. for 'member' PMC and if group has yet to be created |
| ldappmc = ldapprojects[prj].owners |
| ctteeExists = true |
| } |
| var pmcnounix = [] // on PMC but not in LDAP unix group |
| var cttenounix = [] // In LDAP ctte but not in LDAP unix |
| if (pmc) { |
| for (var c in pmc.roster) { |
| pl.push(c) |
| } |
| for (var i in ldappmc) { |
| if (!(ldappmc[i] in pmc.roster)) { |
| cttenopmc.push(ldappmc[i]) |
| } |
| } |
| } |
| cl.sort() |
| pl.sort() |
| |
| // Must use cl before it is re-used to hold the entries |
| if (clExists && prj != 'member') { // does not exist for 'member' PMC |
| for (var i in ldappmc) { |
| var id = ldappmc[i] |
| if (cl.indexOf(id) < 0) { // in LDAP cttee but not in LDAP unix |
| cttenounix.push(id) |
| } |
| } |
| } |
| |
| for (var i in pl) { |
| var id = pl[i] |
| pl[i] = "<tr><td><b>" + getCommitterName(pl[i]) + "</b></td><td>(" + hiliteMember(pl[i]) + ")</td></tr>" |
| if (clExists && cl.indexOf(id) < 0) { // On PMC but not in LDAP unix group |
| pmcnounix.push(id) |
| } |
| if (prj != 'member' && ldappmc && ldappmc.indexOf(id) < 0) { // in PMC but not in LDAP committee (does not apply to member) |
| pmcnoctte.push(id) |
| } |
| } |
| |
| for (var i in cl) { |
| cl[i] = "<tr><td><b>" + getCommitterName(cl[i]) + "</b></td><td>(" + hiliteMember(cl[i]) + ")</td></tr>" |
| } |
| |
| if (pl.length > 0) { |
| if (prj == 'member') { |
| details.innerHTML += "<b>ASF members</b><br><br><table>" + pl.join("\n") + "</table><br/>" |
| } else { |
| details.innerHTML += "<h4>PMC members (also in the committer group): " + pl.length + "</h4><table>" + pl.join("\n") + "</table><br/>" |
| } |
| } |
| |
| if (cl && cl.length > 0) { |
| details.innerHTML += "<h4>Committers: " + cl.length + "</h4><table>" + cl.join("\n") + "</table>" |
| if (podlings[prj]) { |
| details.innerHTML += "<span class='error'>WARNING: <a href='?podling=" + prj + "'>" + prj + " podling group</a> also exists - this can cause authentication issues</span><br/><br/>" |
| } |
| } else { |
| if (!clExists) { |
| details.innerHTML += "<span class='error'>LDAP unix group not present!</span><br/><br/>" |
| } |
| } |
| |
| if (pmcnoctte.length) { |
| if (ctteeExists) { |
| details.innerHTML += "<span class='error'>PMC members not in LDAP committee group:</span> " + userList(pmcnoctte) + "<br/><br/>" |
| } else { |
| details.innerHTML += "<span class='error'>LDAP committee group not present!</span><br/><br/>" |
| } |
| } |
| if (pmcnounix.length) { |
| if (prj == 'member') { |
| details.innerHTML += "<span class='error'>ASF members not in committers(unix) group:</span> " + userList(pmcnounix) + "<br/><br/>" |
| } else { |
| details.innerHTML += "<span class='error'>PMC members not in committers(unix) group:</span> " + userList(pmcnounix) + "<br/><br/>" |
| } |
| } |
| if (cttenounix.length) { |
| details.innerHTML += "<span class='error'>LDAP committee group members not in committers(unix) group:</span> " + userList(cttenounix) + "<br/><br/>" |
| } |
| if (cttenopmc.length) { |
| details.innerHTML += "<span class='error'>LDAP committee group members not on PMC:</span> " + userList(cttenopmc) + "<br/><br/>" |
| } |
| |
| |
| obj.appendChild(details) |
| } else { |
| obj.removeChild(details) |
| } |
| } |
| |
| // Generic group display function |
| // attr is either missing or 'owners' or 'members' |
| function showJsonRoster(obj, type, json, name, attr, checkUnix) { |
| var id = 'details_' + type + '_' + name |
| var details = document.getElementById(id) |
| if (!details) { |
| details = document.createElement('p') |
| details.setAttribute("id", id) |
| var podtype = json[name]['podling'] |
| if (podtype) { |
| details.innerHTML += "<b>podling:</b> " + podtype + "<br><br>" |
| } |
| var cl; |
| if (attr == 'owners') { |
| cl = json[name].owners.slice() |
| } else if (attr == 'members') { |
| cl = json[name].members.slice() |
| } else { |
| cl = json[name].roster.slice() |
| } |
| cl.sort() |
| for (var i in cl) { |
| var uid = cl[i] |
| cl[i] = "<tr><td onmouseover='hoverCommitter(this, \"" + uid + "\");' onmouseout='hoverCommitter(this, null);'><kbd>" + hiliteMember(uid) + "</kbd></td><td>" + getCommitterName(uid) + "</td>" |
| if (checkUnix) { // check against Unix group |
| if (ldapgroups[name]) { // make sure group exists! |
| if (ldapgroups[name].roster.indexOf(uid) > -1) { |
| cl[i] += "<td> </td>" |
| } else { |
| cl[i] += "<td> N.B. not found in corresponding Unix group</td>" |
| } |
| } |
| } |
| cl[i] += "</tr>" |
| } |
| |
| if (cl && cl.length > 0) { |
| details.innerHTML += "<b>Roster:</b><br><br><table>" + cl.join("\n") + "</table><br/>" |
| } |
| obj.appendChild(details) |
| } else { |
| obj.removeChild(details) |
| } |
| } |
| |
| // Show a single Service group |
| function showServiceRoster(obj, name) { |
| showJsonRoster(obj, 'service', ldapservices, name) |
| } |
| |
| // Show a single Auth group |
| function showAuthRoster(obj, name) { |
| showJsonRoster(obj, 'auth', ldapauth, name) |
| } |
| |
| function showPodlingRoster(obj, name) { |
| showJsonRoster(obj, 'podling', podlings, name) |
| } |
| |
| // Show an LDAP Unix group |
| |
| function showGroup(obj, name) { |
| showJsonRoster(obj, 'group', ldapgroups, name) |
| } |
| |
| // Show an LDAP Commiteee group |
| |
| function showCommittee(obj, name) { |
| showJsonRoster(obj, 'ctte', ldapprojects, name, 'owners', true) |
| } |
| |
| function searchProjects(keyword, open) { |
| var obj = document.getElementById('phonebook') |
| if (keyword != '') { |
| obj.innerHTML = "" |
| } else { |
| obj.innerHTML = '' |
| } |
| for (var i in pmcs) { |
| var pmc = pmcs[i] |
| if (pmc.search(keyword.toLowerCase()) != -1) { |
| var ppmc = committees[pmc].display_name |
| obj.innerHTML += "<div id='project_" + pmc + "' class='group'><h3>Apache " + ppmc + "</h3></div>" |
| if (open) { |
| showProject(document.getElementById('project_' + pmc), pmc) |
| } |
| } |
| } |
| } |
| |
| function searchService(keyword, open) { |
| var obj = document.getElementById('phonebook') |
| if (keyword != '') { |
| obj.innerHTML = "<h3>Search results:</h3><hr/>" |
| } else { |
| obj.innerHTML = '' |
| } |
| for (var srv in ldapservices) { |
| if (srv.search(keyword.toLowerCase()) != -1) { |
| obj.innerHTML += "<div id='service_" + srv + "' class='group'><h3 onclick=\"showServiceRoster(this.parentNode, '" + srv + "');\">" + srv + "</h3></div>" |
| if (open) { |
| showServiceRoster(document.getElementById('service_' + srv), srv) |
| } |
| } |
| } |
| } |
| |
| function searchAuth(keyword, open) { |
| var obj = document.getElementById('phonebook') |
| if (keyword != '') { |
| obj.innerHTML = "<h3>Search results:</h3><hr/>" |
| } else { |
| obj.innerHTML = '' |
| } |
| for (var auth in ldapauth) { |
| if (auth.search(keyword.toLowerCase()) != -1) { |
| obj.innerHTML += "<div id='auth_" + auth + "' class='group'><h3 onclick=\"showAuthRoster(this.parentNode, '" + auth + "');\">" + auth + "</h3></div>" |
| if (open) { |
| showauthRoster(document.getElementById('auth_' + auth), auth) |
| } |
| } |
| } |
| } |
| |
| // Show a single PMC |
| |
| function showPMC(pmc) { |
| var obj = document.getElementById('phonebook') |
| if (pmc in committees) { |
| var ppmc = committees[pmc].display_name |
| obj.innerHTML = "<div id='project_" + pmc + "' class='group'><h3 onclick=\"showProject(this.parentNode, '" + pmc + "');\">Apache " + ppmc + "</h3></div>" |
| showProject(document.getElementById('project_' + pmc), pmc) |
| } else { |
| obj.innerHTML = "<h3>Could not find PMC: '" + pmc + "'</h3>" |
| } |
| } |
| |
| // Show a single Unix Group |
| |
| function showUNIX(unix) { |
| var obj = document.getElementById('phonebook') |
| var id = 'group_' + unix |
| if (unix in ldapgroups) { |
| obj.innerHTML = "<div id='" + id + "' class='group'><h3 onclick=\"showGroup(this.parentNode, '" + unix + "');\">" + unix + " (LDAP unix group)</h3></div>" |
| showGroup(document.getElementById(id), unix) |
| } else { |
| obj.innerHTML = "<h3>Could not find unix group: '" + unix + "'</h3>" |
| } |
| } |
| |
| // Show a single Committee group |
| |
| function showCTTE(ctte) { |
| var obj = document.getElementById('phonebook') |
| var id = 'ctte_' + ctte |
| if (ctte in ldapprojects && ldapprojects[ctte].pmc) { |
| obj.innerHTML = "<div id='" + id + "' class='group'><h3 onclick=\"showCommittee(this.parentNode, '" + ctte + "');\">" + ctte + " (LDAP committee group)</h3></div>" |
| showCommittee(document.getElementById(id), ctte) |
| } else { |
| obj.innerHTML = "<h3>Could not find committee group: '" + ctte + "'</h3>" |
| } |
| } |
| |
| function showSVC(name) { |
| var obj = document.getElementById('phonebook') |
| var id = 'service_' + name |
| if (name in ldapservices) { |
| obj.innerHTML = "<div id='" + id + "' class='group'><h3 onclick=\"showServiceRoster(this.parentNode, '" + name + "');\">" + name + " (LDAP service group)</h3></div>" |
| showServiceRoster(document.getElementById(id), name) |
| } else { |
| obj.innerHTML = "<h3>Could not find the service group: '" + name + "'</h3>" |
| } |
| } |
| |
| function showAUTH(name) { |
| var obj = document.getElementById('phonebook') |
| var id = 'auth_' + name |
| if (name in ldapauth) { |
| obj.innerHTML = "<div id='" + id + "' class='group'><h3 onclick=\"showAuthRoster(this.parentNode, '" + name + "');\">" + name + " (LDAP auth group)</h3></div>" |
| showAuthRoster(document.getElementById(id), name) |
| } else { |
| obj.innerHTML = "<h3>Could not find the auth group: '" + name + "'</h3>" |
| } |
| } |
| |
| function showPOD(name) { |
| var obj = document.getElementById('phonebook') |
| var id = 'podling_' + name |
| if (name in podlings) { |
| obj.innerHTML = "<div id='" + id + "' class='group'><h3 onclick=\"showPodlingRoster(this.parentNode, '" + name + "');\">" + name + " (podling)</h3></div>" |
| showPodlingRoster(document.getElementById(id), name) |
| } else { |
| obj.innerHTML = "<h3>Could not find the podling: '" + name + "'</h3>" |
| } |
| } |
| |
| function searchPodlings(keyword, open) { |
| var obj = document.getElementById('phonebook') |
| obj.innerHTML = "<h3>Search results:</h3><hr/>" |
| for (var name in podlings) { |
| if (name.search(keyword.toLowerCase()) != -1) { |
| var id = 'podling_' + name |
| obj.innerHTML += "<div id='" + id + "' class='group'><h3 onclick=\"showPodlingRoster(this.parentNode, '" + name + "');\">" + name + " (podling)</h3></div>" |
| } |
| } |
| } |
| |
| function showDBG(name) { |
| var obj = document.getElementById('phonebook') |
| if (name == 'info') { |
| obj.innerHTML = "<h3>info</h3>" |
| obj.innerHTML += "<pre>" + JSON.stringify(info, null, 1) + "</pre>" |
| |
| } else { |
| obj.innerHTML = "<h3>Unknown debug name: '" + name + "'</h3>" |
| } |
| } |
| |
| // Show a single User |
| |
| function showUid(uid) { |
| var obj = document.getElementById('phonebook') |
| if (uid in people) { |
| var name = getCommitterName(uid) |
| obj.innerHTML = "<div class='group' id='committer_" + uid + "'><h4 onclick=\"showCommitter(this.parentNode, '" + uid + "');\">" + name + " (<kbd>" + uid + "</kbd>)</h4></div>" |
| showCommitter(document.getElementById('committer_' + uid), uid) |
| } else { |
| obj.innerHTML = "<h3>Could not find user id: '" + uid + "'</h3>" |
| } |
| } |
| |
| function showError(error) { |
| var obj = document.getElementById('phonebook') |
| if (typeof(error) === 'string') { |
| obj.innerHTML = "<h3>Error detected</h3>" |
| obj.innerHTML += error |
| } else { // assume it's an error object |
| obj.innerHTML = "<h3>Javascript Error detected</h3>" |
| obj.innerHTML += "<hr/>" |
| obj.innerHTML += "<pre>" + error.message + "</pre>" |
| obj.innerHTML += "<pre>" + error.stack + "</pre>" |
| obj.innerHTML += "<hr/>" |
| } |
| } |
| |
| function searchCommitters(keyword, open) { |
| if (keyword.length < 2) { |
| return |
| } |
| var n = 0 |
| var obj = document.getElementById('phonebook') |
| obj.innerHTML = "" |
| for (var uid in people) { |
| if (!people[uid].noLogin) { // don't display disabled logins |
| var name = getCommitterName(uid) |
| if (uid.search(keyword.toLowerCase()) != -1 || name.toLowerCase().search(keyword.toLowerCase()) != -1) { |
| n++ |
| if (n > 50) { |
| return; |
| } |
| obj.innerHTML += "<div class='group' id='committer_" + uid + "'><h4 onclick=\"showCommitter(this.parentNode, '" + uid + "');\">" + name + |
| " (<kbd>" + uid + "</kbd>) <a title='Link to committer details' href='phonebook.html?uid=" + uid + "'>•</a></h4></div>" |
| if (open) { |
| showCommitter(document.getElementById('committer_' + uid), uid) |
| } |
| } |
| } |
| } |
| } |
| |
| function saveInfo(json, name) { |
| info[name] = {} |
| try { |
| info[name]['lastTimestamp'] = json.lastTimestamp |
| } catch (err) {} // ignored |
| try { |
| info[name]['lastCreateTimestamp'] = json.lastCreateTimestamp |
| } catch (err) {} // ignored |
| try { |
| info[name]['last_updated'] = json.last_updated |
| } catch (err) {} // ignored |
| } |
| |
| function preRender() { |
| getAsyncJSONArray([ |
| ['https://whimsy.apache.org/public/public_ldap_projects.json', "projects", function(json) { |
| ldapprojects = json.projects; |
| saveInfo(json, 'projects'); |
| }], |
| ['https://whimsy.apache.org/public/member-info.json', "members", function(json) { |
| members = json; |
| saveInfo(json, 'members'); |
| }], |
| ['https://whimsy.apache.org/public/public_ldap_people.json', "people", function(json) { |
| people = json.people; |
| saveInfo(json, 'people'); |
| }], |
| ['https://whimsy.apache.org/public/committee-info.json', "committees", function(json) { |
| committees = json.committees; |
| saveInfo(json, 'committees'); |
| }], |
| ['https://whimsy.apache.org/public/icla-info.json', "iclainfo", function(json) { |
| iclainfo = json.committers; |
| saveInfo(json, 'iclainfo'); |
| }], |
| ['https://whimsy.apache.org/public/public_ldap_groups.json', "ldapgroups", function(json) { |
| ldapgroups = json.groups; |
| saveInfo(json, 'ldapgroups'); |
| }], |
| ['https://whimsy.apache.org/public/public_ldap_authgroups.json', "ldapauth", function(json) { |
| ldapauth = json.auth; |
| saveInfo(json, 'ldapauth'); |
| }], |
| ['https://whimsy.apache.org/public/public_ldap_services.json', "services", function(json) { |
| ldapservices = json.services; |
| saveInfo(json, 'services'); |
| }], |
| ], |
| allDone); |
| } |
| |
| // Called when all the async GETs have been completed |
| |
| function allDone() { |
| try { |
| pmcs = [] |
| for (var k in committees) { // actual committees, not LDAP committee groups |
| if (committees[k].pmc) { // skip non-PMCs |
| pmcs.push(k) |
| } |
| } |
| for (var g in ldapprojects) { |
| // get podlings from projects |
| if (ldapprojects[g]['podling'] == 'current') { |
| podlings[g] = {} |
| podlings[g].roster = ldapprojects[g].members |
| } |
| } |
| pmcs.push('member') |
| pmcs.sort() |
| var mMap = {} |
| for (var m in members.members) { |
| mMap[members.members[m]] = {} |
| } |
| // copy across the members info |
| committees['member'] = { |
| 'roster': mMap, |
| 'display_name': 'Foundation Members', |
| 'description': "Current ASF members (Committers == those with member karma)", |
| 'site': 'http://www.apache.org/foundation/' |
| } |
| |
| // Match ?type=name |
| searchProjects('cloudstack', true) |
| |
| } catch (error) { |
| showError(error) |
| } |
| } |