feat: Use prettier-eslint to format code

This commit is contained in:
Bouncey
2019-02-18 19:32:49 +00:00
committed by mrugesh mohapatra
parent 1ba67c4e2b
commit b13e5fb41a
82 changed files with 1767 additions and 1017 deletions

View File

@ -350,9 +350,8 @@ function createShowCert(app) {
messages: [
{
type: 'info',
message: `We could not find a user with the username "${
username
}"`
message:
'We could not find a user with the username "' + username + '"'
}
]
});

View File

@ -321,7 +321,7 @@ export default async function bootChallenge(app, done) {
) {
req.flash(
'danger',
'You haven\'t supplied the necessary URLs for us to inspect your work.'
"You haven't supplied the necessary URLs for us to inspect your work."
);
return res.sendStatus(403);
}

View File

@ -6,23 +6,13 @@ import dedent from 'dedent';
import { homeLocation } from '../../../config/env';
import nonprofits from '../utils/commit.json';
import {
commitGoals,
completeCommitment$
} from '../utils/commit';
import { commitGoals, completeCommitment$ } from '../utils/commit';
import {
unDasherize
} from '../utils';
import { unDasherize } from '../utils';
import {
observeQuery,
saveInstance
} from '../utils/rx';
import { observeQuery, saveInstance } from '../utils/rx';
import {
ifNoUserRedirectTo
} from '../utils/middleware';
import { ifNoUserRedirectTo } from '../utils/middleware';
const sendNonUserToSignIn = ifNoUserRedirectTo(
`${homeLocation}/signin`,
@ -41,12 +31,12 @@ const debug = debugFactory('fcc:commit');
function findNonprofit(name) {
let nonprofit;
if (name) {
nonprofit = _.find(nonprofits, (nonprofit) => {
nonprofit = _.find(nonprofits, nonprofit => {
return name === nonprofit.name;
});
}
nonprofit = nonprofit || nonprofits[ _.random(0, nonprofits.length - 1) ];
nonprofit = nonprofit || nonprofits[_.random(0, nonprofits.length - 1)];
return nonprofit;
}
@ -55,33 +45,15 @@ export default function commit(app) {
const api = app.loopback.Router();
const { Pledge } = app.models;
router.get(
'/commit',
commitToNonprofit
);
router.get('/commit', commitToNonprofit);
router.get(
'/commit/pledge',
sendNonUserToSignIn,
pledge
);
router.get('/commit/pledge', sendNonUserToSignIn, pledge);
router.get(
'/commit/directory',
renderDirectory
);
router.get('/commit/directory', renderDirectory);
api.post(
'/commit/stop-commitment',
sendNonUserToCommit,
stopCommit
);
api.post('/commit/stop-commitment', sendNonUserToCommit, stopCommit);
api.post(
'/commit/complete-goal',
sendNonUserToCommit,
completeCommitment
);
api.post('/commit/complete-goal', sendNonUserToCommit, completeCommitment);
app.use(api);
app.use(router);
@ -101,33 +73,26 @@ export default function commit(app) {
}
return Observable.just();
})
.subscribe(
pledge => {
if (pledge) {
debug('found previous pledge');
req.flash(
'info',
dedent`
.subscribe(pledge => {
if (pledge) {
debug('found previous pledge');
req.flash(
'info',
dedent`
Looks like you already have a pledge to ${pledge.displayName}.
Clicking "Commit" here will replace your old commitment. If you
do change your commitment, please remember to cancel your
previous recurring donation directly with ${pledge.displayName}.
`
);
}
res.render(
'commit/',
{
title: 'Commit to a nonprofit. Commit to your goal.',
pledge,
...commitGoals,
...nonprofit
}
);
},
next
);
}
res.render('commit/', {
title: 'Commit to a nonprofit. Commit to your goal.',
pledge,
...commitGoals,
...nonprofit
});
}, next);
}
function pledge(req, res, next) {
@ -143,14 +108,12 @@ export default function commit(app) {
observeQuery(user, 'pledge')
.flatMap(oldPledge => {
// create new pledge for user
const pledge = Pledge(
{
amount,
goal,
userId: user.id,
...nonprofit
}
);
const pledge = Pledge({
amount,
goal,
userId: user.id,
...nonprofit
});
if (oldPledge) {
debug('user already has pledge, creating a new one');
@ -159,28 +122,24 @@ export default function commit(app) {
oldPledge.formerUser = user.id;
oldPledge.endDate = new Date();
oldPledge.isOrphaned = true;
return saveInstance(oldPledge)
.flatMap(() => {
return saveInstance(pledge);
});
return saveInstance(oldPledge).flatMap(() => {
return saveInstance(pledge);
});
}
return saveInstance(pledge);
})
.subscribe(
({ displayName, goal, amount }) => {
req.flash(
'success',
dedent`
.subscribe(({ displayName, goal, amount }) => {
req.flash(
'success',
dedent`
Congratulations, you have committed to giving
${displayName} $${amount} each month until you have completed
your ${goal}. Please remember to cancel your pledge directly
with ${displayName} once you finish.
`
);
res.redirect('/' + user.username);
},
next
);
);
res.redirect('/' + user.username);
}, next);
}
function renderDirectory(req, res) {
@ -193,16 +152,12 @@ export default function commit(app) {
function completeCommitment(req, res, next) {
const { user } = req;
return completeCommitment$(user)
.subscribe(
msgOrPledge => {
if (typeof msgOrPledge === 'string') {
return res.send(msgOrPledge);
}
return res.send(true);
},
next
);
return completeCommitment$(user).subscribe(msgOrPledge => {
if (typeof msgOrPledge === 'string') {
return res.send(msgOrPledge);
}
return res.send(true);
}, next);
}
function stopCommit(req, res, next) {
@ -220,23 +175,20 @@ export default function commit(app) {
pledge.dateEnded = new Date();
return saveInstance(pledge);
})
.subscribe(
pledge => {
let msg = dedent`
.subscribe(pledge => {
let msg = dedent`
You have successfully stopped your pledge. Please
remember to cancel your recurring donation directly
with the nonprofit if you haven't already done so.
`;
if (!pledge) {
msg = dedent`
if (!pledge) {
msg = dedent`
It doesn't look like you had an active pledge, so
there's no pledge to stop.
`;
}
req.flash('info', msg);
return res.redirect(`/${user.username}`);
},
next
);
}
req.flash('info', msg);
return res.redirect(`/${user.username}`);
}, next);
}
}

View File

@ -6,7 +6,6 @@ import keys from '../../../config/secrets';
const log = debug('fcc:boot:donate');
export default function donateBoot(app, done) {
let stripe = false;
const { User } = app.models;
const api = app.loopback.Router();
@ -25,7 +24,8 @@ export default function donateBoot(app, done) {
currency: 'usd',
id: `monthly-donation-${current}`
}
}), {}
}),
{}
);
function connectToStripe() {
@ -70,23 +70,26 @@ export default function donateBoot(app, done) {
return res.status(400).send({ error: 'Amount Required' });
}
const { amount, token: {email, id} } = body;
const {
amount,
token: { email, id }
} = body;
const fccUser = user ?
Promise.resolve(user) :
new Promise((resolve, reject) =>
User.findOrCreate(
{ where: { email }},
{ email },
(err, instance, isNew) => {
log('is new user instance: ', isNew);
if (err) {
return reject(err);
}
return resolve(instance);
}
)
);
const fccUser = user
? Promise.resolve(user)
: new Promise((resolve, reject) =>
User.findOrCreate(
{ where: { email } },
{ email },
(err, instance, isNew) => {
log('is new user instance: ', isNew);
if (err) {
return reject(err);
}
return resolve(instance);
}
)
);
let donatingUser = {};
let donation = {
@ -96,14 +99,13 @@ export default function donateBoot(app, done) {
startDate: new Date(Date.now()).toISOString()
};
return fccUser.then(
user => {
return fccUser
.then(user => {
donatingUser = user;
return stripe.customers
.create({
email,
card: id
});
return stripe.customers.create({
email,
card: id
});
})
.then(customer => {
donation.customerId = customer.id;
@ -121,7 +123,9 @@ export default function donateBoot(app, done) {
return res.send(subscription);
})
.then(() => {
donatingUser.createDonation(donation).toPromise()
donatingUser
.createDonation(donation)
.toPromise()
.catch(err => {
throw new Error(err);
});

View File

@ -15,7 +15,7 @@ module.exports = function mountLoopBackExplorer(app) {
app.once('started', function() {
log(
'Run `npm install loopback-component-explorer` to enable ' +
'the LoopBack explorer'
'the LoopBack explorer'
);
});
return;

View File

@ -32,9 +32,7 @@ function createShortLinkHandler(app) {
if (!article) {
return res.redirect('/news');
}
const {
slugPart
} = article;
const { slugPart } = article;
const slug = `/news/${slugPart}`;
return res.redirect(slug);
}

View File

@ -88,7 +88,7 @@ module.exports = function(app) {
.then(() => {
req.flash(
'success',
'We\'ve successfully updated your email preferences.'
"We've successfully updated your email preferences."
);
return res.redirectWithFlash(
`${homeLocation}/unsubscribed/${unsubscribeId}`
@ -144,7 +144,7 @@ module.exports = function(app) {
.then(() => {
req.flash(
'success',
'We\'ve successfully updated your email preferences. Thank you ' +
"We've successfully updated your email preferences. Thank you " +
'for resubscribing.'
);
return res.redirectWithFlash(homeLocation);
@ -175,7 +175,7 @@ module.exports = function(app) {
}
pulls = pulls
? Object.keys(JSON.parse(pulls)).length
: 'Can\'t connect to github';
: "Can't connect to github";
return request(
[
@ -193,7 +193,7 @@ module.exports = function(app) {
issues =
pulls === parseInt(pulls, 10) && issues
? Object.keys(JSON.parse(issues)).length - pulls
: 'Can\'t connect to GitHub';
: "Can't connect to GitHub";
return res.send({
issues: issues,
pulls: pulls

View File

@ -1,6 +1,6 @@
export default function bootStatus(app) {
const api = app.loopback.Router();
api.get('/status/ping', (req, res) => res.json({msg: 'pong'}));
api.get('/status/ping', (req, res) => res.json({ msg: 'pong' }));
app.use(api);
}

View File

@ -5,8 +5,6 @@ module.exports = function(app) {
app.use(router);
function showForum(req, res) {
res.redirect(
'http://forum.freecodecamp.org/'
);
res.redirect('http://forum.freecodecamp.org/');
}
};

View File

@ -219,8 +219,7 @@ function createPostReportUserProfile(app) {
if (!username || !report || report === '') {
return res.json({
type: 'danger',
message:
'Oops, something is not right please re-check your submission.'
message: 'Oops, something is not right please re-check your submission.'
});
}
return Email.send$(

View File

@ -1,5 +1,7 @@
import passport from 'passport';
// eslint-disable-next-line
import {
// prettier ignore
PassportConfigurator
} from '@freecodecamp/loopback-component-passport';
import url from 'url';
@ -132,9 +134,7 @@ export function setupPassport(app) {
}
export const saveResponseAuthCookies = () => {
return (req, res, next) => {
const user = req.user;
if (!user) {
@ -157,7 +157,6 @@ export const saveResponseAuthCookies = () => {
};
export const loginRedirect = () => {
return (req, res) => {
const successRedirect = req => {
if (!!req && req.session && req.session.returnTo) {

View File

@ -11,11 +11,7 @@ const pathsOfNoReturn = [
'css'
];
const pathsWhiteList = [
'challenges',
'map',
'commit'
];
const pathsWhiteList = ['challenges', 'map', 'commit'];
const pathsOfNoReturnRegex = new RegExp(pathsOfNoReturn.join('|'), 'i');
const whiteListRegex = new RegExp(pathsWhiteList.join('|'), 'i');
@ -33,9 +29,9 @@ export default function addReturnToUrl() {
) {
return next();
}
req.session.returnTo = req.originalUrl.includes('/map') ?
'/' :
req.originalUrl;
req.session.returnTo = req.originalUrl.includes('/map')
? '/'
: req.originalUrl;
return next();
};
}

View File

@ -1,7 +1,8 @@
export default function constantHeaders() {
return function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers',
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
next();

View File

@ -3,7 +3,7 @@ import helmet from 'helmet';
import { homeLocation } from '../../../config/env';
let trusted = [
'\'self\'',
"'self'",
'https://search.freecodecamp.org',
homeLocation,
'https://' + process.env.AUTH0_DOMAIN
@ -31,8 +31,8 @@ export default function csp() {
'https://*.algolia.net'
]),
scriptSrc: [
'\'unsafe-eval\'',
'\'unsafe-inline\'',
"'unsafe-eval'",
"'unsafe-inline'",
'*.google-analytics.com',
'*.gstatic.com',
'https://*.cloudflare.com',
@ -48,7 +48,7 @@ export default function csp() {
'*.ytimg.com'
].concat(trusted),
styleSrc: [
'\'unsafe-inline\'',
"'unsafe-inline'",
'*.gstatic.com',
'*.googleapis.com',
'*.bootstrapcdn.com',

View File

@ -1,15 +1,12 @@
import csurf from 'csurf';
export default function() {
const protection = csurf(
{
cookie: {
domain: process.env.COOKIE_DOMAIN || 'localhost'
}
const protection = csurf({
cookie: {
domain: process.env.COOKIE_DOMAIN || 'localhost'
}
);
});
return function csrf(req, res, next) {
const path = req.path.split('/')[1];
if ((/(^api$|^unauthenticated$|^internal$|^p$)/).test(path)) {
return next();

View File

@ -14,7 +14,9 @@ export default function flashCheaters() {
if (
ALLOWED_METHODS.indexOf(req.method) !== -1 &&
EXCLUDED_PATHS.indexOf(req.path) === -1 &&
req.user && req.url !== '/' && req.user.isCheater
req.user &&
req.url !== '/' &&
req.user.isCheater
) {
req.flash(
'danger',

View File

@ -20,11 +20,13 @@ export default function() {
return false;
}
const keys = Object.keys(value);
return !!keys.length &&
return (
!!keys.length &&
// every key is a file
keys.every(key => isObject(value[key])) &&
// every file has contents
keys.map(key => value[key]).every(file => isPoly(file));
keys.map(key => value[key]).every(file => isPoly(file))
);
}
},
customSanitizers: {
@ -32,16 +34,20 @@ export default function() {
trimTags(value) {
const tagBody = '(?:[^"\'>]|"[^"]*"|\'[^\']*\')*';
const tagOrComment = new RegExp(
'<(?:'
// Comment body.
+ '!--(?:(?:-*[^->])*--+|-?)'
// Special "raw text" elements whose content should be elided.
+ '|script\\b' + tagBody + '>[\\s\\S]*?</script\\s*'
+ '|style\\b' + tagBody + '>[\\s\\S]*?</style\\s*'
// Regular name
+ '|/?[a-z]'
+ tagBody
+ ')>',
'<(?:' +
// Comment body.
'!--(?:(?:-*[^->])*--+|-?)' +
// Special "raw text" elements whose content should be elided.
'|script\\b' +
tagBody +
'>[\\s\\S]*?</script\\s*' +
'|style\\b' +
tagBody +
'>[\\s\\S]*?</style\\s*' +
// Regular name
'|/?[a-z]' +
tagBody +
')>',
'gi'
);
let rawValue;

View File

@ -1,6 +1,5 @@
import { createActiveUsers } from '../utils/about.js';
module.exports = function(About) {
const activeUsers = createActiveUsers();
let activeUsersForRendering = 0;
@ -14,17 +13,14 @@ module.exports = function(About) {
About.getActiveUsersForRendering = () => activeUsersForRendering;
About.remoteMethod(
'getActiveUsers',
{
http: {
path: '/get-active-users',
verb: 'get'
},
returns: {
type: 'number',
arg: 'activeUsers'
}
About.remoteMethod('getActiveUsers', {
http: {
path: '/get-active-users',
verb: 'get'
},
returns: {
type: 'number',
arg: 'activeUsers'
}
);
});
};

View File

@ -11,7 +11,6 @@ log.enabled = true;
// this is where server starts booting up
const app = require('./server');
let timeoutHandler;
let killTime = 15;

View File

@ -11,7 +11,6 @@ const fiveMinutes = 1000 * 60 * 5;
class NewsFeed {
constructor() {
this.state = {
readyState: false,
mediumFeed: [],
@ -27,26 +26,23 @@ class NewsFeed {
const newState = stateUpdater(this.state);
this.state = _.merge({}, this.state, newState);
return;
}
};
refreshFeeds = () => {
const currentFeed = this.state.combinedFeed.slice(0);
log('grabbing feeds');
return Promise.all([
getMediumFeed(),
getLybsynFeed()
]).then(
([mediumFeed, lybsynFeed]) => this.setState(
state => ({
return Promise.all([getMediumFeed(), getLybsynFeed()])
.then(([mediumFeed, lybsynFeed]) =>
this.setState(state => ({
...state,
mediumFeed,
lybsynFeed
})
))
}))
)
.then(() => {
log('crossing the streams');
const { mediumFeed, lybsynFeed} = this.state;
const combinedFeed = [ ...mediumFeed, ...lybsynFeed ].sort((a, b) => {
const { mediumFeed, lybsynFeed } = this.state;
const combinedFeed = [...mediumFeed, ...lybsynFeed].sort((a, b) => {
return compareDesc(a.isoDate, b.isoDate);
});
this.setState(state => ({
@ -62,25 +58,24 @@ class NewsFeed {
combinedFeed: currentFeed
}));
});
}
};
getFeed = () => new Promise((resolve) => {
getFeed = () =>
new Promise(resolve => {
let notReadyCount = 0;
function waitForReady() {
log('notReadyCount', notReadyCount);
notReadyCount++;
return this.state.readyState || notReadyCount === 5 ?
resolve(this.state.combinedFeed) :
setTimeout(waitForReady, 100);
return this.state.readyState || notReadyCount === 5
? resolve(this.state.combinedFeed)
: setTimeout(waitForReady, 100);
}
log('are we ready?', this.state.readyState);
return this.state.readyState ?
resolve(this.state.combinedFeed) :
setTimeout(waitForReady, 100);
})
return this.state.readyState
? resolve(this.state.combinedFeed)
: setTimeout(waitForReady, 100);
});
}
export default NewsFeed;

View File

@ -9,7 +9,6 @@ function getExtract(str) {
return str.slice(0, str.indexOf('</p>') + 4);
}
function addResponsiveClass(str) {
return str.replace(/<img/g, '<img class="img-responsive"');
}
@ -22,17 +21,15 @@ export function getMediumFeed() {
}
const items = feed.items
.map(
item => _.pick(item, ['title', 'link', 'isoDate', 'content:encoded'])
)
.map(
(item) => ({
...item,
extract: getExtract(item['content:encoded'])
})
.map(item =>
_.pick(item, ['title', 'link', 'isoDate', 'content:encoded'])
)
.map(item => ({
...item,
extract: getExtract(item['content:encoded'])
}))
.map(item => _.omit(item, ['content:encoded']))
.map(item => ({ ...item, extract: addResponsiveClass(item.extract)}));
.map(item => ({ ...item, extract: addResponsiveClass(item.extract) }));
resolve(items);
});
});

View File

@ -64,7 +64,7 @@ export function createActiveUsers() {
credentials['client_email'],
null,
credentials['private_key'],
[scope],
[scope]
);
const authorize = observeMethod(client, 'authorize');
const options = {
@ -89,7 +89,5 @@ export function createActiveUsers() {
.do(null, err => console.error(err))
// always send a number down
.catch(() => Observable.of(0))
// cache for 2 seconds to prevent hitting our daily request limit
::timeCache(2, 'seconds');
}

View File

@ -1,18 +1,18 @@
const githubRegex = (/github/i);
const githubRegex = /github/i;
const providerHash = {
facebook: ({ id }) => id,
github: ({ username }) => username,
twitter: ({ username }) => username,
linkedin({ _json }) {
return _json && _json.publicProfileUrl || null;
return (_json && _json.publicProfileUrl) || null;
},
google: ({ id }) => id
};
export function getUsernameFromProvider(provider, profile) {
return typeof providerHash[provider] === 'function' ?
providerHash[provider](profile) :
null;
return typeof providerHash[provider] === 'function'
? providerHash[provider](profile)
: null;
}
// createProfileAttributes(provider: String, profile: {}) => Object
@ -32,13 +32,7 @@ function createProfileAttributesFromGithub(profile) {
const {
profileUrl: githubProfile,
username,
_json: {
avatar_url: picture,
blog: website,
location,
bio,
name
} = {}
_json: { avatar_url: picture, blog: website, location, bio, name } = {}
} = profile;
return {
name,

View File

@ -20,36 +20,34 @@ export function completeCommitment$(user) {
isInfosecQaCert
} = user;
return Observable.fromNodeCallback(user.pledge, user)()
.flatMap(pledge => {
if (!pledge) {
return Observable.just('No pledge found');
}
return Observable.fromNodeCallback(user.pledge, user)().flatMap(pledge => {
if (!pledge) {
return Observable.just('No pledge found');
}
const { goal } = pledge;
const { goal } = pledge;
if (
(isFrontEndCert && goal === commitGoals.frontEndCert) ||
(isBackEndCert && goal === commitGoals.backEndCert) ||
(isFullStackCert && goal === commitGoals.fullStackCert) ||
(isRespWebDesignCert && goal === commitGoals.respWebDesignCert) ||
(isFrontEndLibsCert && goal === commitGoals.frontEndLibsCert) ||
(isJsAlgoDataStructCert && goal === commitGoals.jsAlgoDataStructCert) ||
(isDataVisCert && goal === commitGoals.dataVisCert) ||
(isApisMicroservicesCert &&
goal === commitGoals.apisMicroservicesCert) ||
(isInfosecQaCert && goal === commitGoals.infosecQaCert)
) {
debug('marking goal complete');
pledge.isCompleted = true;
pledge.dateEnded = new Date();
pledge.formerUserId = pledge.userId;
pledge.userId = null;
return Observable.fromNodeCallback(pledge.save, pledge)();
}
return Observable.just(dedent`
if (
(isFrontEndCert && goal === commitGoals.frontEndCert) ||
(isBackEndCert && goal === commitGoals.backEndCert) ||
(isFullStackCert && goal === commitGoals.fullStackCert) ||
(isRespWebDesignCert && goal === commitGoals.respWebDesignCert) ||
(isFrontEndLibsCert && goal === commitGoals.frontEndLibsCert) ||
(isJsAlgoDataStructCert && goal === commitGoals.jsAlgoDataStructCert) ||
(isDataVisCert && goal === commitGoals.dataVisCert) ||
(isApisMicroservicesCert && goal === commitGoals.apisMicroservicesCert) ||
(isInfosecQaCert && goal === commitGoals.infosecQaCert)
) {
debug('marking goal complete');
pledge.isCompleted = true;
pledge.dateEnded = new Date();
pledge.formerUserId = pledge.userId;
pledge.userId = null;
return Observable.fromNodeCallback(pledge.save, pledge)();
}
return Observable.just(dedent`
You have not yet reached your goal of completing the ${goal}
Please retry when you have met the requirements.
`);
});
});
}

View File

@ -8,25 +8,20 @@ export function unwrapHandledError(err) {
return err[_handledError] || {};
}
export function wrapHandledError(err, {
type,
message,
redirectTo,
status = 200
}) {
export function wrapHandledError(
err,
{ type, message, redirectTo, status = 200 }
) {
err[_handledError] = { type, message, redirectTo, status };
return err;
}
// for use with express-validator error formatter
export const createValidatorErrorFormatter = (type, redirectTo) =>
({ msg }) => wrapHandledError(
new Error(msg),
{
type,
message: msg,
redirectTo,
// we default to 400 as these are malformed requests
status: 400
}
);
export const createValidatorErrorFormatter = (type, redirectTo) => ({ msg }) =>
wrapHandledError(new Error(msg), {
type,
message: msg,
redirectTo,
// we default to 400 as these are malformed requests
status: 400
});

View File

@ -3,9 +3,16 @@ import moment from 'moment-timezone';
// day count between two epochs (inclusive)
export function dayCount([head, tail], timezone = 'UTC') {
return Math.ceil(
moment(moment(head).tz(timezone).endOf('day')).diff(
moment(tail).tz(timezone).startOf('day'),
moment(
moment(head)
.tz(timezone)
.endOf('day')
).diff(
moment(tail)
.tz(timezone)
.startOf('day'),
'days',
true)
true
)
);
}

View File

@ -1,8 +1,4 @@
export default [
'auth',
'services',
'link'
].reduce((throughs, route) => {
export default ['auth', 'services', 'link'].reduce((throughs, route) => {
throughs[route] = true;
return throughs;
}, {});

View File

@ -32,64 +32,59 @@ const getFirstChallenge = _.once(_getFirstChallenge);
*/
export function _cachedMap({ Block, Challenge }) {
const challenges = Challenge.find$({
order: [ 'order ASC', 'suborder ASC' ],
order: ['order ASC', 'suborder ASC'],
where: { isPrivate: false }
});
const challengeMap = challenges
.map(
challenges => challenges
.map(challenge => challenge.toJSON())
.reduce((hash, challenge) => {
hash[challenge.dashedName] = challenge;
return hash;
}, {})
);
const challengeMap = challenges.map(challenges =>
challenges
.map(challenge => challenge.toJSON())
.reduce((hash, challenge) => {
hash[challenge.dashedName] = challenge;
return hash;
}, {})
);
const blocks = Block.find$({
order: [ 'superOrder ASC', 'order ASC' ],
order: ['superOrder ASC', 'order ASC'],
where: { isPrivate: false }
});
const blockMap = Observable.combineLatest(
blocks.map(
blocks => blocks
.map(block => block.toJSON())
.reduce((hash, block) => {
hash[block.dashedName] = block;
return hash;
}, {})
blocks.map(blocks =>
blocks.map(block => block.toJSON()).reduce((hash, block) => {
hash[block.dashedName] = block;
return hash;
}, {})
),
challenges
)
.map(([ blocksMap, challenges ]) => {
return challenges.reduce((blocksMap, challenge) => {
if (blocksMap[challenge.block].challenges) {
blocksMap[challenge.block].challenges.push(challenge.dashedName);
} else {
blocksMap[challenge.block] = {
...blocksMap[challenge.block],
challenges: [ challenge.dashedName ]
};
}
return blocksMap;
}, blocksMap);
});
const superBlockMap = blocks.map(blocks => blocks.reduce((map, block) => {
if (
map[block.superBlock] &&
map[block.superBlock].blocks
) {
map[block.superBlock].blocks.push(block.dashedName);
} else {
map[block.superBlock] = {
title: _.startCase(block.superBlock),
order: block.superOrder,
name: nameify(_.startCase(block.superBlock)),
dashedName: block.superBlock,
blocks: [block.dashedName],
message: block.superBlockMessage
};
}
return map;
}, {}));
).map(([blocksMap, challenges]) => {
return challenges.reduce((blocksMap, challenge) => {
if (blocksMap[challenge.block].challenges) {
blocksMap[challenge.block].challenges.push(challenge.dashedName);
} else {
blocksMap[challenge.block] = {
...blocksMap[challenge.block],
challenges: [challenge.dashedName]
};
}
return blocksMap;
}, blocksMap);
});
const superBlockMap = blocks.map(blocks =>
blocks.reduce((map, block) => {
if (map[block.superBlock] && map[block.superBlock].blocks) {
map[block.superBlock].blocks.push(block.dashedName);
} else {
map[block.superBlock] = {
title: _.startCase(block.superBlock),
order: block.superOrder,
name: nameify(_.startCase(block.superBlock)),
dashedName: block.superBlock,
blocks: [block.dashedName],
message: block.superBlockMessage
};
}
return map;
}, {})
);
const superBlocks = superBlockMap.map(superBlockMap => {
return Object.keys(superBlockMap)
.map(key => superBlockMap[key])
@ -126,30 +121,25 @@ export function getChallengeById(map, id) {
return Observable.if(
() => !id,
map.map(getFirstChallenge),
map.map(addNameIdMap)
.map(map => {
const {
entities: { challenge: challengeMap, challengeIdToName }
} = map;
let finalChallenge;
const dashedName = challengeIdToName[id];
finalChallenge = challengeMap[dashedName];
if (!finalChallenge) {
finalChallenge = getFirstChallenge(map);
}
return finalChallenge;
})
map.map(addNameIdMap).map(map => {
const {
entities: { challenge: challengeMap, challengeIdToName }
} = map;
let finalChallenge;
const dashedName = challengeIdToName[id];
finalChallenge = challengeMap[dashedName];
if (!finalChallenge) {
finalChallenge = getFirstChallenge(map);
}
return finalChallenge;
})
);
}
export function getChallengeInfo(map) {
return map.map(addNameIdMap)
.map(({
entities: {
challenge: challengeMap,
challengeIdToName
}
}) => ({
return map
.map(addNameIdMap)
.map(({ entities: { challenge: challengeMap, challengeIdToName } }) => ({
challengeMap,
challengeIdToName
}));
@ -168,42 +158,37 @@ function loadComingSoonOrBetaChallenge({
// this is a hard search
// falls back to soft search
export function getChallenge(
challengeDashedName,
blockDashedName,
map) {
return map
.flatMap(({ entities, result: { superBlocks } }) => {
const superBlock = entities.superBlock;
const block = entities.block[blockDashedName];
const challenge = entities.challenge[challengeDashedName];
return Observable.if(
() => (
!blockDashedName ||
!block ||
!challenge ||
!loadComingSoonOrBetaChallenge(challenge)
),
getChallengeByDashedName(challengeDashedName, map),
Observable.just({ block, challenge })
)
.map(({ challenge, block }) => ({
redirect: challenge.block !== blockDashedName ?
`/challenges/${block.dashedName}/${challenge.dashedName}` :
false,
entities: {
superBlock,
challenge: {
[challenge.dashedName]: challenge
}
},
result: {
block: block.dashedName,
challenge: challenge.dashedName,
superBlocks
}
}));
});
export function getChallenge(challengeDashedName, blockDashedName, map) {
return map.flatMap(({ entities, result: { superBlocks } }) => {
const superBlock = entities.superBlock;
const block = entities.block[blockDashedName];
const challenge = entities.challenge[challengeDashedName];
return Observable.if(
() =>
!blockDashedName ||
!block ||
!challenge ||
!loadComingSoonOrBetaChallenge(challenge),
getChallengeByDashedName(challengeDashedName, map),
Observable.just({ block, challenge })
).map(({ challenge, block }) => ({
redirect:
challenge.block !== blockDashedName
? `/challenges/${block.dashedName}/${challenge.dashedName}`
: false,
entities: {
superBlock,
challenge: {
[challenge.dashedName]: challenge
}
},
result: {
block: block.dashedName,
challenge: challenge.dashedName,
superBlocks
}
}));
});
}
export function getBlockForChallenge(map, challenge) {
@ -211,19 +196,21 @@ export function getBlockForChallenge(map, challenge) {
}
export function getChallengeByDashedName(dashedName, map) {
const challengeName = unDasherize(dashedName)
.replace(challengesRegex, '');
const challengeName = unDasherize(dashedName).replace(challengesRegex, '');
const testChallengeName = new RegExp(challengeName, 'i');
return map
.map(({ entities }) => entities.challenge)
.flatMap(challengeMap => {
return Observable.from(Object.keys(challengeMap))
.map(key => challengeMap[key]);
return Observable.from(Object.keys(challengeMap)).map(
key => challengeMap[key]
);
})
.filter(challenge => {
return loadComingSoonOrBetaChallenge(challenge) &&
testChallengeName.test(challenge.name);
return (
loadComingSoonOrBetaChallenge(challenge) &&
testChallengeName.test(challenge.name)
);
})
.last({ defaultValue: null })
.flatMap(challengeOrNull => {
@ -234,8 +221,9 @@ export function getChallengeByDashedName(dashedName, map) {
);
})
.flatMap(challenge => {
return getBlockForChallenge(map, challenge)
.map(block => ({ challenge, block }));
return getBlockForChallenge(map, challenge).map(block => ({
challenge,
block
}));
});
}

View File

@ -57,9 +57,11 @@ export const userPropsForSession = [
export function normaliseUserFields(user) {
const about = user.bio && !user.about ? user.bio : user.about;
const picture = user.picture || addPlaceholderImage(user.username);
const twitter = user.twitter && isURL(user.twitter) ?
user.twitter :
user.twitter && `https://www.twitter.com/${user.twitter.replace(/^@/, '')}`;
const twitter =
user.twitter && isURL(user.twitter)
? user.twitter
: user.twitter &&
`https://www.twitter.com/${user.twitter.replace(/^@/, '')}`;
return { about, picture, twitter };
}

View File

@ -49,7 +49,9 @@ export function timeCache(time, unit) {
// 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();
expireCacheAt = moment()
.add(time, unit)
.valueOf();
cache = new AsyncSubject();
source.subscribe(cache);
}

View File

@ -25,13 +25,7 @@ export function getHost() {
export function getServerFullURL() {
if (!isDev) {
return getProtocol()
+ '://'
+ getHost();
return getProtocol() + '://' + getHost();
}
return getProtocol()
+ '://'
+ getHost()
+ ':'
+ getPort();
return getProtocol() + '://' + getHost() + ':' + getPort();
}

View File

@ -13,7 +13,6 @@ const hoursBetween = 24;
const hoursDay = 24;
export function prepUniqueDaysByHours(cals, tz = 'UTC') {
let prev = null;
// compose goes bottom to top (map > sortBy > transform)
@ -25,27 +24,34 @@ export function prepUniqueDaysByHours(cals, tz = 'UTC') {
} else if (
moment(cur)
.tz(tz)
.diff(moment(prev).tz(tz).startOf('day'), 'hours')
>= hoursDay
.diff(
moment(prev)
.tz(tz)
.startOf('day'),
'hours'
) >= hoursDay
) {
data.push(cur);
prev = cur;
}
}, []),
sortBy(e => e),
map(ts => moment(ts).tz(tz).startOf('hours').valueOf())
map(ts =>
moment(ts)
.tz(tz)
.startOf('hours')
.valueOf()
)
)(cals);
}
export function calcCurrentStreak(cals, tz = 'UTC') {
let prev = last(cals);
if (
moment()
.tz(tz)
.startOf('day')
.diff(moment(prev).tz(tz), 'hours')
> hoursBetween
.diff(moment(prev).tz(tz), 'hours') > hoursBetween
) {
return 0;
}
@ -56,8 +62,7 @@ export function calcCurrentStreak(cals, tz = 'UTC') {
moment(prev)
.tz(tz)
.startOf('day')
.diff(moment(cur).tz(tz), 'hours')
<= hoursBetween
.diff(moment(cur).tz(tz), 'hours') <= hoursBetween
) {
prev = cur;
currentStreak++;
@ -72,20 +77,26 @@ export function calcCurrentStreak(cals, tz = 'UTC') {
}
export function calcLongestStreak(cals, tz = 'UTC') {
let tail = cals[0];
const longest = cals.reduce((longest, head, index) => {
const last = cals[index === 0 ? 0 : index - 1];
// is streak broken
if (moment(head).tz(tz).startOf('day').diff(moment(last).tz(tz), 'hours')
> hoursBetween) {
tail = head;
}
if (dayCount(longest, tz) < dayCount([head, tail], tz)) {
return [head, tail];
}
return longest;
}, [cals[0], cals[0]]);
const longest = cals.reduce(
(longest, head, index) => {
const last = cals[index === 0 ? 0 : index - 1];
// is streak broken
if (
moment(head)
.tz(tz)
.startOf('day')
.diff(moment(last).tz(tz), 'hours') > hoursBetween
) {
tail = head;
}
if (dayCount(longest, tz) < dayCount([head, tail], tz)) {
return [head, tail];
}
return longest;
},
[cals[0], cals[0]]
);
return dayCount(longest, tz);
}