Skip to content

Commit d448100

Browse files
committed
Port contributor chart to frontend
1 parent 231a0f9 commit d448100

File tree

5 files changed

+228
-171
lines changed

5 files changed

+228
-171
lines changed

routes/cache.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export default function(req, res, next){
3434
res.set('Cache-Control', `public, max-age=60, stale-while-revalidate=${cdn_cache}`);
3535

3636
if(doc){
37-
const revision = 7; // bump to invalidate all caches
37+
const revision = 12; // bump to invalidate all caches
3838
const etag = `W/"${doc._id}${revision}"`;
3939
const date = new Date(doc._published.getTime() + revision * 1000).toUTCString();
4040
res.set('ETag', etag);

routes/universe.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import express from 'express';
22
import url from 'node:url';
3-
import {get_universe_packages, get_universe_vignettes, get_package_info} from '../src/db.js';
3+
import {get_universe_packages, get_universe_vignettes, get_package_info, get_universe_contributors, get_universe_contributions} from '../src/db.js';
44
const router = express.Router();
55

66
function sort_by_package(x,y){
@@ -91,6 +91,33 @@ function retry_url(x){
9191
return `https://${x._user}.r-universe.dev/api/packages/${x.Package}/${retryversion}/${retrytype}`;
9292
}
9393

94+
function get_contrib_data(user, max = 20){
95+
const p1 = get_universe_contributors(user, 1000);
96+
const p2 = get_universe_contributions(user, 1000);
97+
return Promise.all([p1, p2]).then(function([contributors, contributions]){
98+
if(contributions.length == 0){
99+
return contributors.slice(0,max); //org users dont make contributions themselves
100+
}
101+
var data = contributors.map(function(x){
102+
x.contributions = 0;
103+
x.packages = [];
104+
return x;
105+
});
106+
contributions.forEach(function(x, i){
107+
x.maintainers.forEach(function(maintainer){
108+
var rec = data.find(y => y.login == maintainer);
109+
if(!rec){
110+
rec = {login: maintainer, total: 0, contributions: 0, repos: [], packages: []};
111+
data.push(rec);
112+
}
113+
rec.contributions = rec.contributions + x.contributions;
114+
rec.packages = rec.packages.concat(x.packages);
115+
});
116+
});
117+
return data.sort(function(x,y){return (x.total + x.contributions > y.total + y.contributions) ? -1 : 1}).filter(x => x.login != user).slice(0,max);
118+
});
119+
}
120+
94121
/* Langing page (TODO) */
95122
router.get('/', function(req, res, next) {
96123
//res.render('index');
@@ -179,7 +206,9 @@ router.get("/datasets", function(req, res, next){
179206
});
180207

181208
router.get("/contributors", function(req, res, next){
182-
res.render('contributors', {});
209+
return get_contrib_data(res.locals.universe).then(function(contributors){
210+
res.render('contributors', {contributors: contributors});
211+
});
183212
});
184213

185214
router.get("/articles", function(req, res, next){

src/db.js

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,45 @@ function mongo_universe_binaries(user, type){
227227
return cursor.toArray();
228228
}
229229

230+
/* NB Contributions are grouped by upstream url instead of package namme to avoid duplicate counting
231+
* of contributions in repos with many packages, e.g. https://github.com/r-forge/ctm/tree/master/pkg */
232+
function mongo_universe_contributors(user, limit = 20){
233+
var query = {_universes: user, _type: 'src', '_registered' : true};
234+
var cursor = mongo_aggregate([
235+
{$match: query},
236+
{$project: {
237+
_id: 0,
238+
contributors: '$_contributors',
239+
upstream: '$_upstream'
240+
}},
241+
{$unwind: "$contributors"},
242+
{$group: {_id: "$contributors.user", repos: {$addToSet: {upstream: '$upstream', count: '$contributors.count'}}}},
243+
{$project: {_id:0, login: '$_id', total: {$sum: '$repos.count'}, repos: 1}},
244+
{$sort:{ total: -1}},
245+
{$limit: limit}
246+
]);
247+
return cursor.toArray();
248+
}
249+
250+
function mongo_universe_contributions(user, limit = 20){
251+
var query = {_type: 'src', '_contributors.user': user, '_indexed' : true, '_maintainer.login': {$ne: user}};
252+
var cursor = mongo_aggregate([
253+
{$match: query},
254+
{$addFields: {contrib: {$arrayElemAt:['$_contributors', { $indexOfArray: [ "$_contributors.user", user ]}]}}},
255+
{$group: {
256+
_id: "$_upstream",
257+
owner: {$first: '$_user'}, //equals upstream org
258+
packages: {$addToSet: '$Package'},
259+
maintainers: {$addToSet: '$_maintainer.login'}, //upstreams can have multiple pkgs and maintainers
260+
contributions: {$max: '$contrib.count'}
261+
}},
262+
{$project: {_id:0, contributions:'$contributions', upstream: '$_id', owner: '$owner', packages: '$packages', maintainers: '$maintainers'}},
263+
{$sort:{ contributions: -1}},
264+
{$limit: limit}
265+
]);
266+
return cursor.toArray();
267+
}
268+
230269
function mongo_all_universes(organizations_only){
231270
var query = {_type: 'src', _registered: true};
232271
if(organizations_only){
@@ -479,6 +518,24 @@ export function get_universe_binaries(universe, type){
479518
}
480519
}
481520

521+
export function get_universe_contributors(universe, limit){
522+
if(production){
523+
return mongo_universe_contributors(universe, limit);
524+
} else {
525+
console.warn(`Fetching contributors data from API...`);
526+
return get_ndjson(`https://${universe}.r-universe.dev/stats/contributors?all=1&limit=${limit}`);
527+
}
528+
}
529+
530+
export function get_universe_contributions(universe, limit){
531+
if(production){
532+
return mongo_universe_contributions(universe, limit);
533+
} else {
534+
console.warn(`Fetching contributions data from API...`);
535+
return get_ndjson(`https://${universe}.r-universe.dev/stats/contributions?limit=${limit}`);
536+
}
537+
}
538+
482539
export function get_repositories(){
483540
if(production){
484541
return mongo_all_universes()
@@ -609,6 +666,8 @@ export function get_all_universes(){
609666
if(production){
610667
return universes;
611668
} else {
612-
throw "Not implemented for devel";
669+
return get_json('https://r-universe.dev/api/universes').then(function(data){
670+
return data.map(x => x.universe);
671+
});
613672
}
614673
}

0 commit comments

Comments
 (0)