diff --git a/server/boot/about.js b/server/boot/about.js index e310bc4566..7e596394f3 100644 --- a/server/boot/about.js +++ b/server/boot/about.js @@ -1,32 +1,59 @@ +import { Observable } from 'rx'; import dedent from 'dedent'; import moment from 'moment'; -import { observeMethod } from '../utils/rx'; +import { timeCache, observeMethod } from '../utils/rx'; function numberWithCommas(x) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } +// userCount(where: Object) => Observable[Number] +// getCertCount(userCount: userCount, cert: String) => Observable[Number] +function getCertCount(userCount, cert) { + return userCount({ [cert]: true }) + // using This-Bind operator + ::timeCache(2, 'hours'); +} + export default function about(app) { const router = app.loopback.Router(); const User = app.models.User; - const userCount$ = observeMethod(User, 'count'); + const userCount = observeMethod(User, 'count'); + const frontEndCount$ = getCertCount(userCount, 'isFrontEndCert'); + const dataVisCount$ = getCertCount(userCount, 'isDataVisCert'); + const backEndCount$ = getCertCount(userCount, 'isBackEndCert'); function showAbout(req, res, next) { const daysRunning = moment().diff(new Date('10/15/2014'), 'days'); - userCount$() - .map(camperCount => numberWithCommas(camperCount)) - .doOnNext(camperCount => { + Observable.combineLatest( + frontEndCount$, + dataVisCount$, + backEndCount$, + (frontEndCount = 0, dataVisCount = 0, backEndCount = 0) => ({ + frontEndCount, + dataVisCount, + backEndCount + }) + ) + .doOnNext(({ frontEndCount, dataVisCount, backEndCount }) => { res.render('resources/about', { - camperCount, + frontEndCount: numberWithCommas(frontEndCount), + dataVisCount: numberWithCommas(dataVisCount), + backEndCount: numberWithCommas(backEndCount), daysRunning, title: dedent` About our Open Source Community, our social media presence, - and how to contact us`.split('\n').join(' '), + and how to contact us + `.split('\n').join(' '), globalCompletedCount: numberWithCommas( 5612952 + (Math.floor((Date.now() - 1446268581061) / 1800)) - ) + ), + globalPledgedAmount: numberWithCommas(Math.floor( + 28000 + + ((Date.now() - 1456207176902) / (2629746000 / 2000) * 8.30) + )) }); }) .subscribe(() => {}, next); diff --git a/server/utils/rx.js b/server/utils/rx.js index 891d24e9f3..20976dfeb8 100644 --- a/server/utils/rx.js +++ b/server/utils/rx.js @@ -1,4 +1,5 @@ -import Rx from 'rx'; +import Rx, { AsyncSubject, Observable } from 'rx'; +import moment from 'moment'; import debugFactory from 'debug'; const debug = debugFactory('fcc:rxUtils'); @@ -31,3 +32,22 @@ export function observeQuery(Model, method, query) { export function observeMethod(context, methodName) { return Rx.Observable.fromNodeCallback(context[methodName], context); } + +// timeChache(amount: Number, unit: String) => Observable +export function timeCache(time, unit) { + const source = this; + let cache; + let expireCacheAt; + return Observable.create(observable => { + // if there is no expire time set + // or if expireCacheAt is smaller than now, + // set new expire time in MS and create new subscription to source + if (!expireCacheAt || expireCacheAt < Date.now()) { + // set expire in ms; + expireCacheAt = moment().add(time, unit).valueOf(); + cache = new AsyncSubject(); + source.subscribe(cache); + } + return cache.subscribe(observable); + }); +} diff --git a/server/views/resources/about.jade b/server/views/resources/about.jade index a3dd445de3..e13a74bd15 100644 --- a/server/views/resources/about.jade +++ b/server/views/resources/about.jade @@ -9,18 +9,31 @@ block content span.tag Established: span.text-primary #{daysRunning} | days ago - li - span.tag Population: - span.text-primary #{camperCount} - | campers - li - span.tag Completed: - span.text-primary #{globalCompletedCount} - | challenges li.nowrap span.tag Donated: span.text-primary $850,000 | in pro-bono code + li.nowrap + span.tag Pledged: + span.text-primary $#{globalPledgedAmount} + | to nonprofits + .row + .col-xs-12.col-sm-10.col-sm-offset-1.col-md-6.col-md-offset-3 + h2.text-center Certifications + hr + ul.population-table + li.nowrap + span.tag Front End: + span.text-primary #{frontEndCount} + | earned + li.nowrap + span.tag Data Viz: + span.text-primary #{dataVisCount} + | earned + li.nowrap + span.tag Back End: + span.text-primary #{backEndCount} + | earned .spacer .row .col-xs-12.col-sm-10.col-sm-offset-1.col-md-6.col-md-offset-3