Major refactor. Add error handlers everywhere.
This commit is contained in:
209
app.js
209
app.js
@ -1,63 +1,61 @@
|
|||||||
|
require('newrelic');
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
require('newrelic');
|
var express = require('express'),
|
||||||
var express = require('express');
|
debug = require('debug')('freecc:server'),
|
||||||
var debug = require('debug')('freecc:server');
|
cookieParser = require('cookie-parser'),
|
||||||
var cookieParser = require('cookie-parser');
|
compress = require('compression'),
|
||||||
var compress = require('compression');
|
session = require('express-session'),
|
||||||
var session = require('express-session');
|
bodyParser = require('body-parser'),
|
||||||
var bodyParser = require('body-parser');
|
logger = require('morgan'),
|
||||||
var logger = require('morgan');
|
errorHandler = require('errorhandler'),
|
||||||
var errorHandler = require('errorhandler');
|
methodOverride = require('method-override'),
|
||||||
var methodOverride = require('method-override');
|
bodyParser = require('body-parser'),
|
||||||
var bodyParser = require('body-parser');
|
helmet = require('helmet'),
|
||||||
var helmet = require('helmet');
|
|
||||||
|
|
||||||
var _ = require('lodash');
|
_ = require('lodash'),
|
||||||
var MongoStore = require('connect-mongo')(session);
|
MongoStore = require('connect-mongo')(session),
|
||||||
var flash = require('express-flash');
|
flash = require('express-flash'),
|
||||||
var path = require('path');
|
path = require('path'),
|
||||||
var mongoose = require('mongoose');
|
mongoose = require('mongoose'),
|
||||||
var passport = require('passport');
|
passport = require('passport'),
|
||||||
var expressValidator = require('express-validator');
|
expressValidator = require('express-validator'),
|
||||||
var connectAssets = require('connect-assets');
|
connectAssets = require('connect-assets'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controllers (route handlers).
|
* Controllers (route handlers).
|
||||||
*/
|
*/
|
||||||
|
homeController = require('./controllers/home'),
|
||||||
|
challengesController = require('./controllers/challenges'),
|
||||||
|
resourcesController = require('./controllers/resources'),
|
||||||
|
userController = require('./controllers/user'),
|
||||||
|
contactController = require('./controllers/contact'),
|
||||||
|
|
||||||
var homeController = require('./controllers/home');
|
/**
|
||||||
var challengesController = require('./controllers/challenges');
|
* User model
|
||||||
var resourcesController = require('./controllers/resources');
|
*/
|
||||||
var userController = require('./controllers/user');
|
User = require('./models/User'),
|
||||||
var apiController = require('./controllers/api');
|
|
||||||
var contactController = require('./controllers/contact');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User model
|
* API keys and Passport configuration.
|
||||||
*/
|
*/
|
||||||
var User = require('./models/User');
|
secrets = require('./config/secrets'),
|
||||||
/**
|
passportConf = require('./config/passport');
|
||||||
* API keys and Passport configuration.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var secrets = require('./config/secrets');
|
|
||||||
var passportConf = require('./config/passport');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Express server.
|
* Create Express server.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var app = express();
|
var app = express();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to MongoDB.
|
* Connect to MongoDB.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mongoose.connect(secrets.db);
|
mongoose.connect(secrets.db);
|
||||||
mongoose.connection.on('error', function() {
|
mongoose.connection.on('error', function() {
|
||||||
console.error('MongoDB Connection Error. Please make sure that MongoDB is running.');
|
console.error(
|
||||||
|
'MongoDB Connection Error. Please make sure that MongoDB is running.'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,7 +67,10 @@ app.set('views', path.join(__dirname, 'views'));
|
|||||||
app.set('view engine', 'jade');
|
app.set('view engine', 'jade');
|
||||||
app.use(compress());
|
app.use(compress());
|
||||||
app.use(connectAssets({
|
app.use(connectAssets({
|
||||||
paths: [path.join(__dirname, 'public/css'), path.join(__dirname, 'public/js')],
|
paths: [
|
||||||
|
path.join(__dirname, 'public/css'),
|
||||||
|
path.join(__dirname, 'public/js')
|
||||||
|
],
|
||||||
helperContext: app.locals
|
helperContext: app.locals
|
||||||
}));
|
}));
|
||||||
app.use(logger('dev'));
|
app.use(logger('dev'));
|
||||||
@ -91,38 +92,41 @@ app.use(passport.initialize());
|
|||||||
app.use(passport.session());
|
app.use(passport.session());
|
||||||
app.use(flash());
|
app.use(flash());
|
||||||
app.disable('x-powered-by');
|
app.disable('x-powered-by');
|
||||||
|
|
||||||
app.use(helmet.xssFilter());
|
app.use(helmet.xssFilter());
|
||||||
app.use(helmet.xframe());
|
app.use(helmet.xframe());
|
||||||
|
|
||||||
var trusted = [
|
var trusted = [
|
||||||
"'self'",
|
'"self"',
|
||||||
'*.freecodecamp.com',
|
'*.freecodecamp.com',
|
||||||
"*.google-analytics.com",
|
'*.google-analytics.com',
|
||||||
"*.googleapis.com",
|
'*.googleapis.com',
|
||||||
"*.gstatic.com",
|
'*.gstatic.com',
|
||||||
"*.doubleclick.net",
|
'*.doubleclick.net',
|
||||||
"*.twitter.com",
|
'*.twitter.com',
|
||||||
'*.twimg.com',
|
'*.twimg.com',
|
||||||
"*.githubusercontent.com",
|
'*.githubusercontent.com',
|
||||||
"'unsafe-eval'",
|
'"unsafe-eval"',
|
||||||
"'unsafe-inline'"
|
'"unsafe-inline"'
|
||||||
];
|
];
|
||||||
//var connectSrc;
|
//TODO(Berks): conditionally add localhost domains to csp;
|
||||||
//if (process.env.NODE_ENV === 'development') {
|
/*var connectSrc;
|
||||||
// debug('Pushing');
|
if (process.env.NODE_ENV === 'development') {
|
||||||
// connectSrc = ['"self"', 'ws://localhost:3001/'];
|
debug('Pushing');
|
||||||
//} else {
|
connectSrc = [''self'', 'ws://localhost:3001/'];
|
||||||
// debug('Not');
|
} else {
|
||||||
// connectSrc = [];
|
debug('Not');
|
||||||
//}
|
connectSrc = [];
|
||||||
|
}*/
|
||||||
|
|
||||||
debug(trusted);
|
debug(trusted);
|
||||||
app.use(helmet.contentSecurityPolicy({
|
app.use(helmet.contentSecurityPolicy({
|
||||||
defaultSrc: trusted,
|
defaultSrc: trusted,
|
||||||
scriptSrc: ['*.optimizely.com'].concat(trusted),
|
scriptSrc: ['*.optimizely.com'].concat(trusted),
|
||||||
'connect-src': process.env.NODE_ENV === 'development' ? ['ws://localhost:3001/', 'http://localhost:3001/'] : [],
|
'connect-src': ['ws://localhost:3001/', 'http://localhost:3001/'],
|
||||||
styleSrc: trusted,
|
styleSrc: trusted,
|
||||||
imgSrc: ['*.evernote.com', '*.amazonaws.com', "data:"].concat(trusted),
|
imgSrc: ['*.evernote.com', '*.amazonaws.com', 'data:'].concat(trusted),
|
||||||
fontSrc: ["'self", '*.googleapis.com'].concat(trusted),
|
fontSrc: ['"self"', '*.googleapis.com'].concat(trusted),
|
||||||
mediaSrc: ['*.amazonaws.com', '*.twitter.com'],
|
mediaSrc: ['*.amazonaws.com', '*.twitter.com'],
|
||||||
frameSrc: ['*.gitter.im', '*.vimeo.com', '*.twitter.com'],
|
frameSrc: ['*.gitter.im', '*.vimeo.com', '*.twitter.com'],
|
||||||
// sandbox: ['allow-forms', 'allow-scripts'],
|
// sandbox: ['allow-forms', 'allow-scripts'],
|
||||||
@ -148,7 +152,9 @@ app.use(function(req, res, next) {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(express.static(path.join(__dirname, 'public'), { maxAge: 31557600000 }));
|
app.use(
|
||||||
|
express.static(path.join(__dirname, 'public'), { maxAge: 31557600000 })
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main routes.
|
* Main routes.
|
||||||
@ -164,9 +170,19 @@ app.get('/jquery-exercises', resourcesController.jqueryExercises);
|
|||||||
app.get('/live-pair-programming', resourcesController.livePairProgramming);
|
app.get('/live-pair-programming', resourcesController.livePairProgramming);
|
||||||
app.get('/javascript-in-your-inbox', resourcesController.javaScriptInYourInbox);
|
app.get('/javascript-in-your-inbox', resourcesController.javaScriptInYourInbox);
|
||||||
app.get('/chromebook', resourcesController.chromebook);
|
app.get('/chromebook', resourcesController.chromebook);
|
||||||
app.get('/pair-program-with-team-viewer', resourcesController.pairProgramWithTeamViewer);
|
|
||||||
app.get('/done-with-first-100-hours', resourcesController.doneWithFirst100Hours);
|
app.get(
|
||||||
app.get('/programmer-interview-questions-app', resourcesController.programmerInterviewQuestionsApp);
|
'/pair-program-with-team-viewer',
|
||||||
|
resourcesController.pairProgramWithTeamViewer
|
||||||
|
);
|
||||||
|
app.get(
|
||||||
|
'/done-with-first-100-hours',
|
||||||
|
resourcesController.doneWithFirst100Hours
|
||||||
|
);
|
||||||
|
app.get(
|
||||||
|
'/programmer-interview-questions-app',
|
||||||
|
resourcesController.programmerInterviewQuestionsApp
|
||||||
|
);
|
||||||
|
|
||||||
app.get('/about', resourcesController.about);
|
app.get('/about', resourcesController.about);
|
||||||
app.get('/login', userController.getLogin);
|
app.get('/login', userController.getLogin);
|
||||||
@ -185,14 +201,17 @@ app.post('/nonprofits', contactController.postContact);
|
|||||||
|
|
||||||
// # Protected routes, user must be logged in.
|
// # Protected routes, user must be logged in.
|
||||||
app.post(
|
app.post(
|
||||||
'/update-progress',
|
'/update-progress',
|
||||||
passportConf.isAuthenticated,
|
passportConf.isAuthenticated,
|
||||||
userController.updateProgress);
|
userController.updateProgress
|
||||||
|
);
|
||||||
|
|
||||||
app.get(
|
app.get(
|
||||||
'/challenges/:challengeNumber',
|
'/challenges/:challengeNumber',
|
||||||
passportConf.isAuthenticated,
|
passportConf.isAuthenticated,
|
||||||
challengesController.returnChallenge);
|
challengesController.returnChallenge
|
||||||
|
);
|
||||||
|
|
||||||
app.all('/account', passportConf.isAuthenticated);
|
app.all('/account', passportConf.isAuthenticated);
|
||||||
app.get('/account', userController.getAccount);
|
app.get('/account', userController.getAccount);
|
||||||
app.post('/account/profile', userController.postUpdateProfile);
|
app.post('/account/profile', userController.postUpdateProfile);
|
||||||
@ -207,11 +226,12 @@ app.get('/account/unlink/:provider', userController.getOauthUnlink);
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
app.post('/completed_challenge', function(req, res) {
|
app.post('/completed_challenge', function(req, res) {
|
||||||
req.user.challengesHash[parseInt(req.body.challengeNumber)] = Math.round(+new Date() / 1000);
|
req.user.challengesHash[parseInt(req.body.challengeNumber)] =
|
||||||
|
Math.round(+ new Date() / 1000);
|
||||||
var ch = req.user.challengesHash;
|
var ch = req.user.challengesHash;
|
||||||
var p = 0;
|
var p = 0;
|
||||||
for (k in ch) {
|
for (var k in ch) {
|
||||||
if (ch[k] > 0) { p += 1}
|
if (ch[k] > 0) { p += 1; }
|
||||||
}
|
}
|
||||||
req.user.points = p;
|
req.user.points = p;
|
||||||
req.user.save();
|
req.user.save();
|
||||||
@ -220,7 +240,6 @@ app.post('/completed_challenge', function(req, res) {
|
|||||||
/**
|
/**
|
||||||
* OAuth sign-in routes.
|
* OAuth sign-in routes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.get('/auth/twitter', passport.authenticate('twitter'));
|
app.get('/auth/twitter', passport.authenticate('twitter'));
|
||||||
app.get(
|
app.get(
|
||||||
'/auth/twitter/callback',
|
'/auth/twitter/callback',
|
||||||
@ -246,20 +265,40 @@ app.get(
|
|||||||
res.redirect(req.session.returnTo || '/');
|
res.redirect(req.session.returnTo || '/');
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/auth/facebook', passport.authenticate('facebook', { scope: ['email', 'user_location'] }));
|
app.get(
|
||||||
app.get('/auth/facebook/callback', passport.authenticate('facebook', { successRedirect: '/',failureRedirect: '/login' }), function(req, res) {
|
'/auth/facebook',
|
||||||
|
passport.authenticate('facebook', { scope: ['email', 'user_location'] })
|
||||||
|
);
|
||||||
|
|
||||||
|
var passportOptions = {
|
||||||
|
successRedirect: '/',
|
||||||
|
failureRedirect: '/login'
|
||||||
|
};
|
||||||
|
app.get(
|
||||||
|
'/auth/facebook/callback',
|
||||||
|
passport.authenticate('facebook', passportOptions), function(req, res) {
|
||||||
res.redirect(req.session.returnTo || '/');
|
res.redirect(req.session.returnTo || '/');
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
app.get('/auth/github', passport.authenticate('github'));
|
app.get('/auth/github', passport.authenticate('github'));
|
||||||
app.get('/auth/github/callback', passport.authenticate('github', { successRedirect: '/',failureRedirect: '/login' }), function(req, res) {
|
app.get(
|
||||||
|
'/auth/github/callback',
|
||||||
|
passport.authenticate('github', passportOptions), function(req, res) {
|
||||||
res.redirect(req.session.returnTo || '/');
|
res.redirect(req.session.returnTo || '/');
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
app.get('/auth/google', passport.authenticate('google', { scope: 'profile email' }));
|
app.get(
|
||||||
app.get('/auth/google/callback', passport.authenticate('google', { successRedirect: '/',failureRedirect: '/login' }), function(req, res) {
|
'/auth/google',
|
||||||
|
passport.authenticate('google', { scope: 'profile email' })
|
||||||
|
);
|
||||||
|
app.get(
|
||||||
|
'/auth/google/callback',
|
||||||
|
passport.authenticate('google', passportOptions), function(req, res) {
|
||||||
res.redirect(req.session.returnTo || '/');
|
res.redirect(req.session.returnTo || '/');
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 500 Error Handler.
|
* 500 Error Handler.
|
||||||
|
29
config/bootstrap.js
vendored
29
config/bootstrap.js
vendored
@ -1,22 +1,29 @@
|
|||||||
var mongoose = require('mongoose');
|
var mongoose = require('mongoose'),
|
||||||
var secrets = require('./secrets');
|
debug = require('debug')('freecc:config:boot'),
|
||||||
|
secrets = require('./secrets'),
|
||||||
|
courses = require('../seed_data/courses.json'),
|
||||||
|
Course = require('./../models/Course'),
|
||||||
|
challenges = require('../seed_data/challenges.json'),
|
||||||
|
Challenge = require('./../models/Challenge');
|
||||||
|
|
||||||
mongoose.connect(secrets.db);
|
mongoose.connect(secrets.db);
|
||||||
mongoose.connection.on('error', function() {
|
mongoose.connection.on('error', function() {
|
||||||
console.error('MongoDB Connection Error. Make sure MongoDB is running.');
|
console.error('MongoDB Connection Error. Make sure MongoDB is running.');
|
||||||
});
|
});
|
||||||
|
|
||||||
var courses = require('../seed_data/courses.json');
|
|
||||||
var challenges = require('../seed_data/challenges.json');
|
|
||||||
|
|
||||||
Challenge = require ('./../models/Challenge');
|
|
||||||
Course = require ('./../models/Course');
|
|
||||||
|
|
||||||
Course.create(courses, function(err, data) {
|
Course.create(courses, function(err, data) {
|
||||||
if (err) console.log(err);
|
if (err) {
|
||||||
else console.log('Saved ', data );
|
debug(err);
|
||||||
|
} else {
|
||||||
|
debug('Saved ', data);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Challenge.create(challenges, function(err, data) {
|
Challenge.create(challenges, function(err, data) {
|
||||||
if (err) console.log(err);
|
if (err) {
|
||||||
else console.log('Saved ', data );
|
console.log(err);
|
||||||
|
} else {
|
||||||
|
console.log('Saved ', data);
|
||||||
|
}
|
||||||
});
|
});
|
@ -1,25 +1,31 @@
|
|||||||
var _ = require('lodash');
|
var _ = require('lodash'),
|
||||||
var passport = require('passport');
|
passport = require('passport'),
|
||||||
var InstagramStrategy = require('passport-instagram').Strategy;
|
LocalStrategy = require('passport-local').Strategy,
|
||||||
var LocalStrategy = require('passport-local').Strategy;
|
FacebookStrategy = require('passport-facebook').Strategy,
|
||||||
var FacebookStrategy = require('passport-facebook').Strategy;
|
TwitterStrategy = require('passport-twitter').Strategy,
|
||||||
var TwitterStrategy = require('passport-twitter').Strategy;
|
GitHubStrategy = require('passport-github').Strategy,
|
||||||
var GitHubStrategy = require('passport-github').Strategy;
|
GoogleStrategy = require('passport-google-oauth').OAuth2Strategy,
|
||||||
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
|
LinkedInStrategy = require('passport-linkedin-oauth2').Strategy,
|
||||||
var LinkedInStrategy = require('passport-linkedin-oauth2').Strategy;
|
OAuthStrategy = require('passport-oauth').OAuthStrategy,
|
||||||
var OAuthStrategy = require('passport-oauth').OAuthStrategy;
|
OAuth2Strategy = require('passport-oauth').OAuth2Strategy,
|
||||||
var OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
|
User = require('../models/User'),
|
||||||
var User = require('../models/User');
|
secrets = require('./secrets');
|
||||||
var secrets = require('./secrets');
|
|
||||||
|
// Login Required middleware.
|
||||||
|
module.exports = {
|
||||||
|
isAuthenticated: isAuthenticated,
|
||||||
|
isAuthorized: isAuthorized
|
||||||
|
};
|
||||||
|
|
||||||
passport.serializeUser(function(user, done) {
|
passport.serializeUser(function(user, done) {
|
||||||
done(null, user.id);
|
done(null, user.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
passport.deserializeUser(function(id, done) {
|
passport.deserializeUser(function(id, done) {
|
||||||
User.findById(id, function(err, user) {
|
User.findById(id, function(err, user) {
|
||||||
done(err, user);
|
if (err) { return done(err); }
|
||||||
});
|
done(null, user);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
//function sendWelcomeEmail(u) {
|
//function sendWelcomeEmail(u) {
|
||||||
@ -55,247 +61,452 @@ passport.deserializeUser(function(id, done) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Sign in with Twitter.
|
// Sign in with Twitter.
|
||||||
passport.use(new TwitterStrategy(secrets.twitter, function(req, accessToken, tokenSecret, profile, done) {
|
passport.use(
|
||||||
if (req.user) {
|
new TwitterStrategy(
|
||||||
|
secrets.twitter, function(req, accessToken, tokenSecret, profile, done) {
|
||||||
|
if (req.user) {
|
||||||
User.findOne({ twitter: profile.id }, function(err, existingUser) {
|
User.findOne({ twitter: profile.id }, function(err, existingUser) {
|
||||||
if (existingUser) {
|
if (err) { return done(err); }
|
||||||
req.flash('errors', { msg: 'There is already a Twitter account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
|
|
||||||
done(err);
|
if (existingUser) {
|
||||||
} else {
|
req.flash('errors', {
|
||||||
User.findById(req.user.id, function(err, user) {
|
msg: [
|
||||||
user.twitter = profile.id;
|
'There is already a Twitter account that belongs to you. ',
|
||||||
user.tokens.push({ kind: 'twitter', accessToken: accessToken, tokenSecret: tokenSecret });
|
'Sign in with that account or delete it, then link it with ',
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
'your current account.'
|
||||||
user.profile.location = user.profile.location || profile._json.location;
|
].join('')
|
||||||
user.profile.picture = user.profile.picture || profile._json.profile_image_url_https;
|
});
|
||||||
user.profile.username = profile.username;
|
done();
|
||||||
user.save(function(err) {
|
} else {
|
||||||
req.flash('info', { msg: 'Twitter account has been linked.' });
|
User.findById(req.user.id, function(err, user) {
|
||||||
done(err, user);
|
if (err) { return done(err); }
|
||||||
});
|
|
||||||
});
|
user.twitter = profile.id;
|
||||||
}
|
user.tokens.push({
|
||||||
|
kind: 'twitter',
|
||||||
|
accessToken: accessToken,
|
||||||
|
tokenSecret: tokenSecret
|
||||||
|
});
|
||||||
|
user.profile.name = user.profile.name || profile.displayName;
|
||||||
|
|
||||||
|
user.profile.location =
|
||||||
|
user.profile.location || profile._json.location;
|
||||||
|
|
||||||
|
user.profile.picture =
|
||||||
|
user.profile.picture || profile._json.profile_image_url_https;
|
||||||
|
|
||||||
|
user.profile.username = profile.username;
|
||||||
|
user.save(function(err) {
|
||||||
|
req.flash('info', { msg: 'Twitter account has been linked.' });
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
User.findOne({ twitter: profile.id }, function(err, existingUser) {
|
User.findOne({ twitter: profile.id }, function(err, existingUser) {
|
||||||
//if (existingUser) return done(null, existingUser);
|
if (err) { return done(err); }
|
||||||
// Twitter will not provide an email address. Period.
|
|
||||||
// But a person’s twitter username is guaranteed to be unique
|
//if (existingUser) return done(null, existingUser);
|
||||||
// so we can "fake" a twitter email address as follows:
|
// Twitter will not provide an email address. Period.
|
||||||
//user.email = profile.username + "@twitter.com";
|
// But a person’s twitter username is guaranteed to be unique
|
||||||
var user = existingUser || new User;
|
// so we can "fake" a twitter email address as follows:
|
||||||
user.twitter = profile.id;
|
//user.email = profile.username + "@twitter.com";
|
||||||
user.email = user.email || '';
|
var user = existingUser || new User();
|
||||||
user.tokens.push({ kind: 'twitter', accessToken: accessToken, tokenSecret: tokenSecret });
|
user.twitter = profile.id;
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
user.email = user.email || '';
|
||||||
user.profile.location = user.profile.location || profile._json.location;
|
user.tokens.push({
|
||||||
user.profile.picture = user.profile.picture || profile._json.profile_image_url_https;
|
kind: 'twitter',
|
||||||
user.save(function(err) {
|
accessToken: accessToken,
|
||||||
done(err, user);
|
tokenSecret: tokenSecret
|
||||||
});
|
});
|
||||||
//if (!user.email) {
|
user.profile.name = user.profile.name || profile.displayName;
|
||||||
// req.redirect('/account');
|
|
||||||
// req.flash('errors', { msg: 'OK, you are signed in. Please add your email address to your profile.' });
|
user.profile.location =
|
||||||
//}
|
user.profile.location || profile._json.location;
|
||||||
|
user.profile.picture =
|
||||||
|
user.profile.picture || profile._json.profile_image_url_https;
|
||||||
|
|
||||||
|
user.save(function(err) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
//TODO: Twitter redirect to capture user email.
|
||||||
|
//if (!user.email) {
|
||||||
|
// req.redirect('/account');
|
||||||
|
// req.flash('errors', {
|
||||||
|
// msg:
|
||||||
|
// 'OK, you are signed in. ' +
|
||||||
|
// 'Please add your email address to your profile.'
|
||||||
|
// });
|
||||||
|
//}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
// Sign in with LinkedIn.
|
// Sign in with LinkedIn.
|
||||||
passport.use(new LinkedInStrategy(secrets.linkedin, function(req, accessToken, refreshToken, profile, done) {
|
passport.use(
|
||||||
if (req.user) {
|
new LinkedInStrategy(
|
||||||
|
secrets.linkedin, function(req, accessToken, refreshToken, profile, done) {
|
||||||
|
if (req.user) {
|
||||||
User.findOne({ linkedin: profile.id }, function(err, existingUser) {
|
User.findOne({ linkedin: profile.id }, function(err, existingUser) {
|
||||||
if (existingUser) {
|
if (err) { return done(err); }
|
||||||
req.flash('errors', { msg: 'There is already a LinkedIn account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
|
|
||||||
done(err);
|
if (existingUser) {
|
||||||
} else {
|
req.flash('errors', {
|
||||||
User.findById(req.user.id, function(err, user) {
|
msg: [
|
||||||
user.linkedin = profile.id;
|
'There is already a LinkedIn account that belongs to you.',
|
||||||
user.tokens.push({ kind: 'linkedin', accessToken: accessToken });
|
'Sign in with that account or delete it,',
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
'then link it with your current account.'
|
||||||
user.profile.location = user.profile.location || profile._json.location.name;
|
].join('')
|
||||||
user.profile.picture = user.profile.picture || profile._json.pictureUrl;
|
|
||||||
user.profile.website = user.profile.website || profile._json.publicProfileUrl;
|
|
||||||
user.save(function(err) {
|
|
||||||
req.flash('info', { msg: 'LinkedIn account has been linked.' });
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
User.findOne({ linkedin: profile.id }, function(err, existingUser) {
|
|
||||||
if (existingUser) return done(null, existingUser);
|
|
||||||
User.findOne({ email: profile._json.emailAddress }, function(err, existingEmailUser) {
|
|
||||||
var user = existingEmailUser || new User;
|
|
||||||
user.linkedin = profile.id;
|
|
||||||
user.tokens.push({ kind: 'linkedin', accessToken: accessToken });
|
|
||||||
user.email = user.email || profile._json.emailAddress;
|
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
|
||||||
user.profile.location = user.profile.location || profile._json.location.name;
|
|
||||||
user.profile.picture = user.profile.picture || profile._json.pictureUrl;
|
|
||||||
user.profile.website = user.profile.website || profile._json.publicProfileUrl;
|
|
||||||
user.challengesComplete = user.challengesCompleted || [];
|
|
||||||
user.save(function(err) {
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
User.findById(req.user.id, function(err, user) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
user.linkedin = profile.id;
|
||||||
|
user.tokens.push({
|
||||||
|
kind: 'linkedin',
|
||||||
|
accessToken: accessToken
|
||||||
|
});
|
||||||
|
user.profile.name = user.profile.name || profile.displayName;
|
||||||
|
|
||||||
|
user.profile.location =
|
||||||
|
user.profile.location || profile._json.location.name;
|
||||||
|
|
||||||
|
user.profile.picture =
|
||||||
|
user.profile.picture || profile._json.pictureUrl;
|
||||||
|
|
||||||
|
user.profile.website =
|
||||||
|
user.profile.website || profile._json.publicProfileUrl;
|
||||||
|
|
||||||
|
user.save(function(err, _user) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
req.flash(
|
||||||
|
'info', { msg: 'LinkedIn account has been linked.' }
|
||||||
|
);
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
|
User.findOne({ linkedin: profile.id }, function(err, existingUser) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
if (existingUser) { return done(null, existingUser); }
|
||||||
|
User.findOne(
|
||||||
|
{ email: profile._json.emailAddress },
|
||||||
|
function(err, existingEmailUser) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
var user = existingEmailUser || new User();
|
||||||
|
|
||||||
|
user.linkedin = profile.id;
|
||||||
|
user.tokens.push({
|
||||||
|
kind: 'linkedin',
|
||||||
|
accessToken: accessToken
|
||||||
|
});
|
||||||
|
user.email = user.email || profile._json.emailAddress;
|
||||||
|
user.profile.name = user.profile.name || profile.displayName;
|
||||||
|
|
||||||
|
user.profile.location =
|
||||||
|
user.profile.location || profile._json.location.name;
|
||||||
|
|
||||||
|
user.profile.picture =
|
||||||
|
user.profile.picture || profile._json.pictureUrl;
|
||||||
|
|
||||||
|
user.profile.website =
|
||||||
|
user.profile.website || profile._json.publicProfileUrl;
|
||||||
|
|
||||||
|
user.challengesComplete = user.challengesCompleted || [];
|
||||||
|
user.save(function(err) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Sign in using Email and Password.
|
// Sign in using Email and Password.
|
||||||
passport.use(new LocalStrategy({ usernameField: 'email' }, function(email, password, done) {
|
passport.use(
|
||||||
|
new LocalStrategy(
|
||||||
|
{ usernameField: 'email' }, function(email, password, done) {
|
||||||
User.findOne({ email: email }, function(err, user) {
|
User.findOne({ email: email }, function(err, user) {
|
||||||
if (!user) return done(null, false, { message: 'Email ' + email + ' not found'});
|
if (err) { return done(err); }
|
||||||
user.comparePassword(password, function(err, isMatch) {
|
|
||||||
if (isMatch) {
|
if (!user) {
|
||||||
return done(null, user);
|
return done(null, false, { message: 'Email ' + email + ' not found'});
|
||||||
} else {
|
}
|
||||||
return done(null, false, { message: 'Invalid email or password.' });
|
user.comparePassword(password, function(err, isMatch) {
|
||||||
}
|
if (err) { return done(err); }
|
||||||
});
|
|
||||||
|
if (isMatch) {
|
||||||
|
return done(null, user);
|
||||||
|
} else {
|
||||||
|
return done(null, false, { message: 'Invalid email or password.' });
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
// Sign in with Facebook.
|
// Sign in with Facebook.
|
||||||
|
passport.use(
|
||||||
|
new FacebookStrategy(
|
||||||
|
secrets.facebook, function(req, accessToken, refreshToken, profile, done) {
|
||||||
|
if (req.user) {
|
||||||
|
User.findOne({ facebook: profile.id }, function(err, existingUser) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
passport.use(new FacebookStrategy(secrets.facebook, function(req, accessToken, refreshToken, profile, done) {
|
if (existingUser) {
|
||||||
if (req.user) {
|
req.flash('errors', {
|
||||||
User.findOne({ facebook: profile.id }, function(err, existingUser) {
|
msg: [
|
||||||
if (existingUser) {
|
'There is already a Facebook account that belongs to you.',
|
||||||
req.flash('errors', { msg: 'There is already a Facebook account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
|
'Sign in with that account or delete it, then link it with',
|
||||||
done(err);
|
'your current account.'
|
||||||
} else {
|
].join(' ')
|
||||||
User.findById(req.user.id, function(err, user) {
|
});
|
||||||
user.facebook = profile.id;
|
done();
|
||||||
user.tokens.push({ kind: 'facebook', accessToken: accessToken });
|
} else {
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
User.findById(req.user.id, function(err, user) {
|
||||||
user.profile.gender = user.profile.gender || profile._json.gender;
|
if (err) { return done(err); }
|
||||||
user.profile.picture = user.profile.picture || 'https://graph.facebook.com/' + profile.id + '/picture?type=large';
|
|
||||||
user.save(function(err) {
|
user.facebook = profile.id;
|
||||||
req.flash('info', { msg: 'Facebook account has been linked.' });
|
user.tokens.push({
|
||||||
done(err, user);
|
kind: 'facebook',
|
||||||
});
|
accessToken: accessToken
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
user.profile.name = user.profile.name || profile.displayName;
|
||||||
|
user.profile.gender = user.profile.gender || profile._json.gender;
|
||||||
|
|
||||||
|
user.profile.picture =
|
||||||
|
user.profile.picture ||
|
||||||
|
'https://graph.facebook.com/' +
|
||||||
|
profile.id +
|
||||||
|
'/picture?type=large';
|
||||||
|
|
||||||
|
user.save(function(err) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
req.flash(
|
||||||
|
'info', { msg: 'Facebook account has been linked.' });
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
User.findOne({ facebook: profile.id }, function(err, existingUser) {
|
User.findOne({ facebook: profile.id }, function(err, existingUser) {
|
||||||
if (existingUser) return done(null, existingUser);
|
if (err) { return done(err); }
|
||||||
User.findOne({ email: profile._json.email }, function(err, existingEmailUser) {
|
|
||||||
var user = existingEmailUser || new User;
|
if (existingUser) { return done(null, existingUser); }
|
||||||
user.email = user.email || profile._json.email;
|
|
||||||
user.facebook = profile.id;
|
User.findOne(
|
||||||
user.tokens.push({ kind: 'facebook', accessToken: accessToken });
|
{ email: profile._json.email }, function(err, existingEmailUser) {
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
if (err) { return done(err); }
|
||||||
user.profile.gender = user.profile.gender || profile._json.gender;
|
|
||||||
user.profile.picture = user.profile.picture || 'https://graph.facebook.com/' + profile.id + '/picture?type=large';
|
var user = existingEmailUser || new User();
|
||||||
user.profile.location = user.profile.location || (profile._json.location) ? profile._json.location.name : '';
|
user.email = user.email || profile._json.email;
|
||||||
user.challengesComplete = user.challengesCompleted || [];
|
user.facebook = profile.id;
|
||||||
user.save(function(err) {
|
user.tokens.push({
|
||||||
done(err, user);
|
kind: 'facebook',
|
||||||
});
|
accessToken: accessToken
|
||||||
|
});
|
||||||
|
user.profile.name = user.profile.name || profile.displayName;
|
||||||
|
|
||||||
|
user.profile.gender =
|
||||||
|
user.profile.gender || profile._json.gender;
|
||||||
|
|
||||||
|
user.profile.picture =
|
||||||
|
user.profile.picture ||
|
||||||
|
'https://graph.facebook.com/' +
|
||||||
|
profile.id +
|
||||||
|
'/picture?type=large';
|
||||||
|
|
||||||
|
user.profile.location =
|
||||||
|
user.profile.location ||
|
||||||
|
(profile._json.location) ? profile._json.location.name : '';
|
||||||
|
|
||||||
|
user.challengesComplete = user.challengesCompleted || [];
|
||||||
|
user.save(function(err) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Sign in with GitHub.
|
// Sign in with GitHub.
|
||||||
|
|
||||||
passport.use(new GitHubStrategy(secrets.github, function(req, accessToken, refreshToken, profile, done) {
|
passport.use(
|
||||||
if (req.user) {
|
new GitHubStrategy(
|
||||||
|
secrets.github, function(req, accessToken, refreshToken, profile, done) {
|
||||||
|
if (req.user) {
|
||||||
User.findOne({ github: profile.id }, function(err, existingUser) {
|
User.findOne({ github: profile.id }, function(err, existingUser) {
|
||||||
if (existingUser) {
|
if (err) { return done(err); }
|
||||||
req.flash('errors', { msg: 'There is already a GitHub account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
|
|
||||||
done(err);
|
if (existingUser) {
|
||||||
} else {
|
req.flash('errors', {
|
||||||
User.findById(req.user.id, function(err, user) {
|
msg: [
|
||||||
user.github = profile.id;
|
'There is already a GitHub account that belongs to you.',
|
||||||
user.tokens.push({ kind: 'github', accessToken: accessToken });
|
'Sign in with that account or delete it, then link it with',
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
'your current account.'
|
||||||
user.profile.picture = user.profile.picture || profile._json.avatar_url;
|
].join(' ')
|
||||||
user.profile.location = user.profile.location || profile._json.location;
|
|
||||||
user.profile.website = user.profile.website || profile._json.blog;
|
|
||||||
user.save(function(err) {
|
|
||||||
req.flash('info', { msg: 'GitHub account has been linked.' });
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
User.findOne({ github: profile.id }, function(err, existingUser) {
|
|
||||||
if (existingUser) return done(null, existingUser);
|
|
||||||
User.findOne({ email: profile._json.email }, function(err, existingEmailUser) {
|
|
||||||
var user = existingEmailUser || new User;
|
|
||||||
user.email = user.email || profile._json.email;
|
|
||||||
user.github = profile.id;
|
|
||||||
user.tokens.push({ kind: 'github', accessToken: accessToken });
|
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
|
||||||
user.profile.picture = user.profile.picture || profile._json.avatar_url;
|
|
||||||
user.profile.location = user.profile.location || profile._json.location;
|
|
||||||
user.profile.website = user.profile.website || profile._json.blog;
|
|
||||||
user.save(function(err) {
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
User.findById(req.user.id, function(err, user) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
user.github = profile.id;
|
||||||
|
user.tokens.push({ kind: 'github', accessToken: accessToken });
|
||||||
|
user.profile.name = user.profile.name || profile.displayName;
|
||||||
|
|
||||||
|
user.profile.picture =
|
||||||
|
user.profile.picture || profile._json.avatar_url;
|
||||||
|
|
||||||
|
user.profile.location =
|
||||||
|
user.profile.location || profile._json.location;
|
||||||
|
|
||||||
|
user.profile.website =
|
||||||
|
user.profile.website || profile._json.blog;
|
||||||
|
|
||||||
|
user.save(function(err) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
req.flash('info', { msg: 'GitHub account has been linked.' });
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
|
User.findOne({ github: profile.id }, function(err, existingUser) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
if (existingUser) { return done(null, existingUser); }
|
||||||
|
User.findOne(
|
||||||
|
{ email: profile._json.email }, function(err, existingEmailUser) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
var user = existingEmailUser || new User();
|
||||||
|
user.email = user.email || profile._json.email;
|
||||||
|
user.github = profile.id;
|
||||||
|
user.tokens.push({
|
||||||
|
kind: 'github',
|
||||||
|
accessToken: accessToken
|
||||||
|
});
|
||||||
|
user.profile.name = user.profile.name || profile.displayName;
|
||||||
|
|
||||||
|
user.profile.picture =
|
||||||
|
user.profile.picture || profile._json.avatar_url;
|
||||||
|
|
||||||
|
user.profile.location =
|
||||||
|
user.profile.location || profile._json.location;
|
||||||
|
|
||||||
|
user.profile.website =
|
||||||
|
user.profile.website || profile._json.blog;
|
||||||
|
|
||||||
|
user.save(function(err) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Sign in with Google.
|
// Sign in with Google.
|
||||||
|
|
||||||
passport.use(new GoogleStrategy(secrets.google, function(req, accessToken, refreshToken, profile, done) {
|
passport.use(
|
||||||
if (req.user) {
|
new GoogleStrategy(
|
||||||
|
secrets.google, function(req, accessToken, refreshToken, profile, done) {
|
||||||
|
if (req.user) {
|
||||||
User.findOne({ google: profile.id }, function(err, existingUser) {
|
User.findOne({ google: profile.id }, function(err, existingUser) {
|
||||||
if (existingUser) {
|
if (err) { return done(err); }
|
||||||
req.flash('errors', { msg: 'There is already a Google account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
|
|
||||||
done(err);
|
if (existingUser) {
|
||||||
} else {
|
req.flash('errors', {
|
||||||
User.findById(req.user.id, function(err, user) {
|
msg: [
|
||||||
user.google = profile.id;
|
'There is already a Google account that belongs to you.',
|
||||||
user.tokens.push({ kind: 'google', accessToken: accessToken });
|
'Sign in with that account or delete it,',
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
'then link it with your current account.'
|
||||||
user.profile.gender = user.profile.gender || profile._json.gender;
|
].join(' ')
|
||||||
user.profile.picture = user.profile.picture || profile._json.picture;
|
|
||||||
user.save(function(err) {
|
|
||||||
req.flash('info', { msg: 'Google account has been linked.' });
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
User.findOne({ google: profile.id }, function(err, existingUser) {
|
|
||||||
if (existingUser) return done(null, existingUser);
|
|
||||||
User.findOne({ email: profile._json.email }, function(err, existingEmailUser) {
|
|
||||||
var user = existingEmailUser || new User;
|
|
||||||
user.email = user.email || profile._json.email;
|
|
||||||
user.google = profile.id;
|
|
||||||
user.tokens.push({ kind: 'google', accessToken: accessToken });
|
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
|
||||||
user.profile.gender = user.profile.gender || profile._json.gender;
|
|
||||||
user.profile.picture = user.profile.picture || profile._json.picture;
|
|
||||||
//if (!existingEmailUser) {
|
|
||||||
// sendWelcomeEmail(user);
|
|
||||||
//}
|
|
||||||
user.save(function(err) {
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
User.findById(req.user.id, function(err, user) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
user.google = profile.id;
|
||||||
|
user.tokens.push({
|
||||||
|
kind: 'google',
|
||||||
|
accessToken: accessToken
|
||||||
|
});
|
||||||
|
|
||||||
|
user.profile.name = user.profile.name || profile.displayName;
|
||||||
|
|
||||||
|
user.profile.gender =
|
||||||
|
user.profile.gender || profile._json.gender;
|
||||||
|
|
||||||
|
user.profile.picture =
|
||||||
|
user.profile.picture || profile._json.picture;
|
||||||
|
|
||||||
|
user.save(function(err) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
req.flash('info', { msg: 'Google account has been linked.' });
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
|
User.findOne({ google: profile.id }, function(err, existingUser) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
if (existingUser) { return done(null, existingUser); }
|
||||||
|
User.findOne(
|
||||||
|
{ email: profile._json.email }, function(err, existingEmailUser) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
|
||||||
|
var user = existingEmailUser || new User();
|
||||||
|
user.email = user.email || profile._json.email;
|
||||||
|
user.google = profile.id;
|
||||||
|
user.tokens.push({
|
||||||
|
kind: 'google',
|
||||||
|
accessToken: accessToken
|
||||||
|
});
|
||||||
|
|
||||||
|
user.profile.name =
|
||||||
|
user.profile.name || profile.displayName;
|
||||||
|
|
||||||
|
user.profile.gender =
|
||||||
|
user.profile.gender || profile._json.gender;
|
||||||
|
|
||||||
|
user.profile.picture =
|
||||||
|
user.profile.picture || profile._json.picture;
|
||||||
|
|
||||||
|
//TODO: Greeting email
|
||||||
|
//if (!existingEmailUser) {
|
||||||
|
// sendWelcomeEmail(user);
|
||||||
|
//}
|
||||||
|
user.save(function(err) {
|
||||||
|
if (err) { return done(err); }
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Login Required middleware.
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
isAuthenticated: isAuthenticated,
|
|
||||||
isAuthorized: isAuthorized
|
|
||||||
};
|
|
||||||
|
|
||||||
function isAuthenticated(req, res, next) {
|
function isAuthenticated(req, res, next) {
|
||||||
if (req.isAuthenticated()) return next();
|
if (req.isAuthenticated()) return next();
|
||||||
@ -307,113 +518,8 @@ function isAuthorized(req, res, next) {
|
|||||||
var provider = req.path.split('/').slice(-1)[0];
|
var provider = req.path.split('/').slice(-1)[0];
|
||||||
|
|
||||||
if (_.find(req.user.tokens, { kind: provider })) {
|
if (_.find(req.user.tokens, { kind: provider })) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
res.redirect('/auth/' + provider);
|
res.redirect('/auth/' + provider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
passport.use(new InstagramStrategy(secrets.instagram,function(req, accessToken, refreshToken, profile, done) {
|
|
||||||
if (req.user) {
|
|
||||||
User.findOne({ instagram: profile.id }, function(err, existingUser) {
|
|
||||||
if (existingUser) {
|
|
||||||
req.flash('errors', { msg: 'There is already an Instagram account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
|
|
||||||
done(err);
|
|
||||||
} else {
|
|
||||||
User.findById(req.user.id, function(err, user) {
|
|
||||||
user.instagram = profile.id;
|
|
||||||
user.tokens.push({ kind: 'instagram', accessToken: accessToken });
|
|
||||||
user.profile.name = user.profile.name || profile.displayName;
|
|
||||||
user.profile.picture = user.profile.picture || profile._json.data.profile_picture;
|
|
||||||
user.profile.website = user.profile.website || profile._json.data.website;
|
|
||||||
user.save(function(err) {
|
|
||||||
req.flash('info', { msg: 'Instagram account has been linked.' });
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
User.findOne({ instagram: profile.id }, function(err, existingUser) {
|
|
||||||
if (existingUser) return done(null, existingUser);
|
|
||||||
|
|
||||||
var user = new User();
|
|
||||||
user.instagram = profile.id;
|
|
||||||
user.tokens.push({ kind: 'instagram', accessToken: accessToken });
|
|
||||||
user.profile.name = profile.displayName;
|
|
||||||
// Similar to Twitter API, assigns a temporary e-mail address
|
|
||||||
// to get on with the registration process. It can be changed later
|
|
||||||
// to a valid e-mail address in Profile Management.
|
|
||||||
user.email = profile.username + "@instagram.com";
|
|
||||||
user.profile.website = profile._json.data.website;
|
|
||||||
user.profile.picture = profile._json.data.profile_picture;
|
|
||||||
user.save(function(err) {
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
// Tumblr API setup.
|
|
||||||
|
|
||||||
passport.use('tumblr', new OAuthStrategy({
|
|
||||||
requestTokenURL: 'http://www.tumblr.com/oauth/request_token',
|
|
||||||
accessTokenURL: 'http://www.tumblr.com/oauth/access_token',
|
|
||||||
userAuthorizationURL: 'http://www.tumblr.com/oauth/authorize',
|
|
||||||
consumerKey: secrets.tumblr.consumerKey,
|
|
||||||
consumerSecret: secrets.tumblr.consumerSecret,
|
|
||||||
callbackURL: secrets.tumblr.callbackURL,
|
|
||||||
passReqToCallback: true
|
|
||||||
},
|
|
||||||
function(req, token, tokenSecret, profile, done) {
|
|
||||||
User.findById(req.user._id, function(err, user) {
|
|
||||||
user.tokens.push({ kind: 'tumblr', accessToken: token, tokenSecret: tokenSecret });
|
|
||||||
user.save(function(err) {
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
// Foursquare API setup.
|
|
||||||
|
|
||||||
passport.use('foursquare', new OAuth2Strategy({
|
|
||||||
authorizationURL: 'https://foursquare.com/oauth2/authorize',
|
|
||||||
tokenURL: 'https://foursquare.com/oauth2/access_token',
|
|
||||||
clientID: secrets.foursquare.clientId,
|
|
||||||
clientSecret: secrets.foursquare.clientSecret,
|
|
||||||
callbackURL: secrets.foursquare.redirectUrl,
|
|
||||||
passReqToCallback: true
|
|
||||||
},
|
|
||||||
function(req, accessToken, refreshToken, profile, done) {
|
|
||||||
User.findById(req.user._id, function(err, user) {
|
|
||||||
user.tokens.push({ kind: 'foursquare', accessToken: accessToken });
|
|
||||||
user.save(function(err) {
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
// Venmo API setup.
|
|
||||||
|
|
||||||
passport.use('venmo', new OAuth2Strategy({
|
|
||||||
authorizationURL: 'https://api.venmo.com/v1/oauth/authorize',
|
|
||||||
tokenURL: 'https://api.venmo.com/v1/oauth/access_token',
|
|
||||||
clientID: secrets.venmo.clientId,
|
|
||||||
clientSecret: secrets.venmo.clientSecret,
|
|
||||||
callbackURL: secrets.venmo.redirectUrl,
|
|
||||||
passReqToCallback: true
|
|
||||||
},
|
|
||||||
function(req, accessToken, refreshToken, profile, done) {
|
|
||||||
User.findById(req.user._id, function(err, user) {
|
|
||||||
user.tokens.push({ kind: 'venmo', accessToken: accessToken });
|
|
||||||
user.save(function(err) {
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
));
|
|
||||||
*/
|
|
||||||
|
@ -1,602 +0,0 @@
|
|||||||
var secrets = require('../config/secrets');
|
|
||||||
var User = require('../models/User');
|
|
||||||
var querystring = require('querystring');
|
|
||||||
var validator = require('validator');
|
|
||||||
var async = require('async');
|
|
||||||
var cheerio = require('cheerio');
|
|
||||||
var request = require('request');
|
|
||||||
var graph = require('fbgraph');
|
|
||||||
var LastFmNode = require('lastfm').LastFmNode;
|
|
||||||
var tumblr = require('tumblr.js');
|
|
||||||
var foursquare = require('node-foursquare')({ secrets: secrets.foursquare });
|
|
||||||
var Github = require('github-api');
|
|
||||||
var Twit = require('twit');
|
|
||||||
var stripe = require('stripe')(secrets.stripe.secretKey);
|
|
||||||
var twilio = require('twilio')(secrets.twilio.sid, secrets.twilio.token);
|
|
||||||
var Linkedin = require('node-linkedin')(secrets.linkedin.clientID, secrets.linkedin.clientSecret, secrets.linkedin.callbackURL);
|
|
||||||
var clockwork = require('clockwork')({key: secrets.clockwork.apiKey});
|
|
||||||
var ig = require('instagram-node').instagram();
|
|
||||||
var Y = require('yui/yql');
|
|
||||||
var _ = require('lodash');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api
|
|
||||||
* List of API examples.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getApi = function(req, res) {
|
|
||||||
res.render('api/index', {
|
|
||||||
title: 'API Examples'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/foursquare
|
|
||||||
* Foursquare API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getFoursquare = function(req, res, next) {
|
|
||||||
var token = _.find(req.user.tokens, { kind: 'foursquare' });
|
|
||||||
async.parallel({
|
|
||||||
trendingVenues: function(callback) {
|
|
||||||
foursquare.Venues.getTrending('40.7222756', '-74.0022724', { limit: 50 }, token.accessToken, function(err, results) {
|
|
||||||
callback(err, results);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
venueDetail: function(callback) {
|
|
||||||
foursquare.Venues.getVenue('49da74aef964a5208b5e1fe3', token.accessToken, function(err, results) {
|
|
||||||
callback(err, results);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
userCheckins: function(callback) {
|
|
||||||
foursquare.Users.getCheckins('self', null, token.accessToken, function(err, results) {
|
|
||||||
callback(err, results);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(err, results) {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.render('api/foursquare', {
|
|
||||||
title: 'Foursquare API',
|
|
||||||
trendingVenues: results.trendingVenues,
|
|
||||||
venueDetail: results.venueDetail,
|
|
||||||
userCheckins: results.userCheckins
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/tumblr
|
|
||||||
* Tumblr API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getTumblr = function(req, res, next) {
|
|
||||||
var token = _.find(req.user.tokens, { kind: 'tumblr' });
|
|
||||||
var client = tumblr.createClient({
|
|
||||||
consumer_key: secrets.tumblr.consumerKey,
|
|
||||||
consumer_secret: secrets.tumblr.consumerSecret,
|
|
||||||
token: token.accessToken,
|
|
||||||
token_secret: token.tokenSecret
|
|
||||||
});
|
|
||||||
client.posts('withinthisnightmare.tumblr.com', { type: 'photo' }, function(err, data) {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.render('api/tumblr', {
|
|
||||||
title: 'Tumblr API',
|
|
||||||
blog: data.blog,
|
|
||||||
photoset: data.posts[0].photos
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/facebook
|
|
||||||
* Facebook API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getFacebook = function(req, res, next) {
|
|
||||||
var token = _.find(req.user.tokens, { kind: 'facebook' });
|
|
||||||
graph.setAccessToken(token.accessToken);
|
|
||||||
async.parallel({
|
|
||||||
getMe: function(done) {
|
|
||||||
graph.get(req.user.facebook, function(err, me) {
|
|
||||||
done(err, me);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getMyFriends: function(done) {
|
|
||||||
graph.get(req.user.facebook + '/friends', function(err, friends) {
|
|
||||||
done(err, friends.data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(err, results) {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.render('api/facebook', {
|
|
||||||
title: 'Facebook API',
|
|
||||||
me: results.getMe,
|
|
||||||
friends: results.getMyFriends
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/scraping
|
|
||||||
* Web scraping example using Cheerio library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getScraping = function(req, res, next) {
|
|
||||||
request.get('https://news.ycombinator.com/', function(err, request, body) {
|
|
||||||
if (err) return next(err);
|
|
||||||
var $ = cheerio.load(body);
|
|
||||||
var links = [];
|
|
||||||
$('.title a[href^="http"], a[href^="https"]').each(function() {
|
|
||||||
links.push($(this));
|
|
||||||
});
|
|
||||||
res.render('api/scraping', {
|
|
||||||
title: 'Web Scraping',
|
|
||||||
links: links
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/github
|
|
||||||
* GitHub API Example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getGithub = function(req, res, next) {
|
|
||||||
var token = _.find(req.user.tokens, { kind: 'github' });
|
|
||||||
var github = new Github({ token: token.accessToken });
|
|
||||||
var repo = github.getRepo('sahat', 'requirejs-library');
|
|
||||||
repo.show(function(err, repo) {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.render('api/github', {
|
|
||||||
title: 'GitHub API',
|
|
||||||
repo: repo
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/aviary
|
|
||||||
* Aviary image processing example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getAviary = function(req, res) {
|
|
||||||
res.render('api/aviary', {
|
|
||||||
title: 'Aviary API'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/nyt
|
|
||||||
* New York Times API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getNewYorkTimes = function(req, res, next) {
|
|
||||||
var query = querystring.stringify({ 'api-key': secrets.nyt.key, 'list-name': 'young-adult' });
|
|
||||||
var url = 'http://api.nytimes.com/svc/books/v2/lists?' + query;
|
|
||||||
request.get(url, function(err, request, body) {
|
|
||||||
if (err) return next(err);
|
|
||||||
if (request.statusCode === 403) return next(Error('Missing or Invalid New York Times API Key'));
|
|
||||||
var bestsellers = JSON.parse(body);
|
|
||||||
res.render('api/nyt', {
|
|
||||||
title: 'New York Times API',
|
|
||||||
books: bestsellers.results
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/lastfm
|
|
||||||
* Last.fm API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getLastfm = function(req, res, next) {
|
|
||||||
var lastfm = new LastFmNode(secrets.lastfm);
|
|
||||||
async.parallel({
|
|
||||||
artistInfo: function(done) {
|
|
||||||
lastfm.request('artist.getInfo', {
|
|
||||||
artist: 'The Pierces',
|
|
||||||
handlers: {
|
|
||||||
success: function(data) {
|
|
||||||
done(null, data);
|
|
||||||
},
|
|
||||||
error: function(err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
artistTopTracks: function(done) {
|
|
||||||
lastfm.request('artist.getTopTracks', {
|
|
||||||
artist: 'The Pierces',
|
|
||||||
handlers: {
|
|
||||||
success: function(data) {
|
|
||||||
var tracks = [];
|
|
||||||
_.each(data.toptracks.track, function(track) {
|
|
||||||
tracks.push(track);
|
|
||||||
});
|
|
||||||
done(null, tracks.slice(0,10));
|
|
||||||
},
|
|
||||||
error: function(err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
artistTopAlbums: function(done) {
|
|
||||||
lastfm.request('artist.getTopAlbums', {
|
|
||||||
artist: 'The Pierces',
|
|
||||||
handlers: {
|
|
||||||
success: function(data) {
|
|
||||||
var albums = [];
|
|
||||||
_.each(data.topalbums.album, function(album) {
|
|
||||||
albums.push(album.image.slice(-1)[0]['#text']);
|
|
||||||
});
|
|
||||||
done(null, albums.slice(0, 4));
|
|
||||||
},
|
|
||||||
error: function(err) {
|
|
||||||
done(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(err, results) {
|
|
||||||
if (err) return next(err.message);
|
|
||||||
var artist = {
|
|
||||||
name: results.artistInfo.artist.name,
|
|
||||||
image: results.artistInfo.artist.image.slice(-1)[0]['#text'],
|
|
||||||
tags: results.artistInfo.artist.tags.tag,
|
|
||||||
bio: results.artistInfo.artist.bio.summary,
|
|
||||||
stats: results.artistInfo.artist.stats,
|
|
||||||
similar: results.artistInfo.artist.similar.artist,
|
|
||||||
topAlbums: results.artistTopAlbums,
|
|
||||||
topTracks: results.artistTopTracks
|
|
||||||
};
|
|
||||||
res.render('api/lastfm', {
|
|
||||||
title: 'Last.fm API',
|
|
||||||
artist: artist
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/twitter
|
|
||||||
* Twiter API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getTwitter = function(req, res, next) {
|
|
||||||
var token = _.find(req.user.tokens, { kind: 'twitter' });
|
|
||||||
var T = new Twit({
|
|
||||||
consumer_key: secrets.twitter.consumerKey,
|
|
||||||
consumer_secret: secrets.twitter.consumerSecret,
|
|
||||||
access_token: token.accessToken,
|
|
||||||
access_token_secret: token.tokenSecret
|
|
||||||
});
|
|
||||||
T.get('search/tweets', { q: 'nodejs since:2013-01-01', geocode: '40.71448,-74.00598,5mi', count: 10 }, function(err, reply) {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.render('api/twitter', {
|
|
||||||
title: 'Twitter API',
|
|
||||||
tweets: reply.statuses
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /api/twitter
|
|
||||||
* Post a tweet.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.postTwitter = function(req, res, next) {
|
|
||||||
req.assert('tweet', 'Tweet cannot be empty.').notEmpty();
|
|
||||||
var errors = req.validationErrors();
|
|
||||||
if (errors) {
|
|
||||||
req.flash('errors', errors);
|
|
||||||
return res.redirect('/api/twitter');
|
|
||||||
}
|
|
||||||
var token = _.find(req.user.tokens, { kind: 'twitter' });
|
|
||||||
var T = new Twit({
|
|
||||||
consumer_key: secrets.twitter.consumerKey,
|
|
||||||
consumer_secret: secrets.twitter.consumerSecret,
|
|
||||||
access_token: token.accessToken,
|
|
||||||
access_token_secret: token.tokenSecret
|
|
||||||
});
|
|
||||||
T.post('statuses/update', { status: req.body.tweet }, function(err, data, response) {
|
|
||||||
if (err) return next(err);
|
|
||||||
req.flash('success', { msg: 'Tweet has been posted.'});
|
|
||||||
res.redirect('/api/twitter');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/steam
|
|
||||||
* Steam API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getSteam = function(req, res, next) {
|
|
||||||
var steamId = '76561197982488301';
|
|
||||||
var query = { l: 'english', steamid: steamId, key: secrets.steam.apiKey };
|
|
||||||
async.parallel({
|
|
||||||
playerAchievements: function(done) {
|
|
||||||
query.appid = '49520';
|
|
||||||
var qs = querystring.stringify(query);
|
|
||||||
request.get({ url: 'http://api.steampowered.com/ISteamUserStats/GetPlayerAchievements/v0001/?' + qs, json: true }, function(error, request, body) {
|
|
||||||
if (request.statusCode === 401) return done(new Error('Missing or Invalid Steam API Key'));
|
|
||||||
done(error, body);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
playerSummaries: function(done) {
|
|
||||||
query.steamids = steamId;
|
|
||||||
var qs = querystring.stringify(query);
|
|
||||||
request.get({ url: 'http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?' + qs, json: true }, function(err, request, body) {
|
|
||||||
if (request.statusCode === 401) return done(new Error('Missing or Invalid Steam API Key'));
|
|
||||||
done(err, body);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
ownedGames: function(done) {
|
|
||||||
query.include_appinfo = 1;
|
|
||||||
query.include_played_free_games = 1;
|
|
||||||
var qs = querystring.stringify(query);
|
|
||||||
request.get({ url: 'http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?' + qs, json: true }, function(err, request, body) {
|
|
||||||
if (request.statusCode === 401) return done(new Error('Missing or Invalid Steam API Key'));
|
|
||||||
done(err, body);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(err, results) {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.render('api/steam', {
|
|
||||||
title: 'Steam Web API',
|
|
||||||
ownedGames: results.ownedGames.response.games,
|
|
||||||
playerAchievemments: results.playerAchievements.playerstats,
|
|
||||||
playerSummary: results.playerSummaries.response.players[0]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/stripe
|
|
||||||
* Stripe API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getStripe = function(req, res) {
|
|
||||||
res.render('api/stripe', {
|
|
||||||
title: 'Stripe API',
|
|
||||||
publishableKey: secrets.stripe.publishableKey
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /api/stripe
|
|
||||||
* Make a payment.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.postStripe = function(req, res, next) {
|
|
||||||
var stripeToken = req.body.stripeToken;
|
|
||||||
var stripeEmail = req.body.stripeEmail;
|
|
||||||
stripe.charges.create({
|
|
||||||
amount: 395,
|
|
||||||
currency: 'usd',
|
|
||||||
card: stripeToken,
|
|
||||||
description: stripeEmail
|
|
||||||
}, function(err, charge) {
|
|
||||||
if (err && err.type === 'StripeCardError') {
|
|
||||||
req.flash('errors', { msg: 'Your card has been declined.' });
|
|
||||||
res.redirect('/api/stripe');
|
|
||||||
}
|
|
||||||
req.flash('success', { msg: 'Your card has been charged successfully.' });
|
|
||||||
res.redirect('/api/stripe');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/twilio
|
|
||||||
* Twilio API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getTwilio = function(req, res) {
|
|
||||||
res.render('api/twilio', {
|
|
||||||
title: 'Twilio API'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /api/twilio
|
|
||||||
* Send a text message using Twilio.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.postTwilio = function(req, res, next) {
|
|
||||||
req.assert('number', 'Phone number is required.').notEmpty();
|
|
||||||
req.assert('message', 'Message cannot be blank.').notEmpty();
|
|
||||||
var errors = req.validationErrors();
|
|
||||||
if (errors) {
|
|
||||||
req.flash('errors', errors);
|
|
||||||
return res.redirect('/api/twilio');
|
|
||||||
}
|
|
||||||
var message = {
|
|
||||||
to: req.body.number,
|
|
||||||
from: '+13472235148',
|
|
||||||
body: req.body.message
|
|
||||||
};
|
|
||||||
twilio.sendMessage(message, function(err, responseData) {
|
|
||||||
if (err) return next(err.message);
|
|
||||||
req.flash('success', { msg: 'Text sent to ' + responseData.to + '.'});
|
|
||||||
res.redirect('/api/twilio');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/clockwork
|
|
||||||
* Clockwork SMS API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getClockwork = function(req, res) {
|
|
||||||
res.render('api/clockwork', {
|
|
||||||
title: 'Clockwork SMS API'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /api/clockwork
|
|
||||||
* Send a text message using Clockwork SMS
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.postClockwork = function(req, res, next) {
|
|
||||||
var message = {
|
|
||||||
To: req.body.telephone,
|
|
||||||
From: 'Hackathon',
|
|
||||||
Content: 'Hello from the Hackathon Starter'
|
|
||||||
};
|
|
||||||
clockwork.sendSms(message, function(err, responseData) {
|
|
||||||
if (err) return next(err.errDesc);
|
|
||||||
req.flash('success', { msg: 'Text sent to ' + responseData.responses[0].to });
|
|
||||||
res.redirect('/api/clockwork');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/venmo
|
|
||||||
* Venmo API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getVenmo = function(req, res, next) {
|
|
||||||
var token = _.find(req.user.tokens, { kind: 'venmo' });
|
|
||||||
var query = querystring.stringify({ access_token: token.accessToken });
|
|
||||||
async.parallel({
|
|
||||||
getProfile: function(done) {
|
|
||||||
request.get({ url: 'https://api.venmo.com/v1/me?' + query, json: true }, function(err, request, body) {
|
|
||||||
done(err, body);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getRecentPayments: function(done) {
|
|
||||||
request.get({ url: 'https://api.venmo.com/v1/payments?' + query, json: true }, function(err, request, body) {
|
|
||||||
done(err, body);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(err, results) {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.render('api/venmo', {
|
|
||||||
title: 'Venmo API',
|
|
||||||
profile: results.getProfile.data,
|
|
||||||
recentPayments: results.getRecentPayments.data
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /api/venmo
|
|
||||||
* Send money.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.postVenmo = function(req, res, next) {
|
|
||||||
req.assert('user', 'Phone, Email or Venmo User ID cannot be blank').notEmpty();
|
|
||||||
req.assert('note', 'Please enter a message to accompany the payment').notEmpty();
|
|
||||||
req.assert('amount', 'The amount you want to pay cannot be blank').notEmpty();
|
|
||||||
var errors = req.validationErrors();
|
|
||||||
if (errors) {
|
|
||||||
req.flash('errors', errors);
|
|
||||||
return res.redirect('/api/venmo');
|
|
||||||
}
|
|
||||||
var token = _.find(req.user.tokens, { kind: 'venmo' });
|
|
||||||
var formData = {
|
|
||||||
access_token: token.accessToken,
|
|
||||||
note: req.body.note,
|
|
||||||
amount: req.body.amount
|
|
||||||
};
|
|
||||||
if (validator.isEmail(req.body.user)) {
|
|
||||||
formData.email = req.body.user;
|
|
||||||
} else if (validator.isNumeric(req.body.user) &&
|
|
||||||
validator.isLength(req.body.user, 10, 11)) {
|
|
||||||
formData.phone = req.body.user;
|
|
||||||
} else {
|
|
||||||
formData.user_id = req.body.user;
|
|
||||||
}
|
|
||||||
request.post('https://api.venmo.com/v1/payments', { form: formData }, function(err, request, body) {
|
|
||||||
if (err) return next(err);
|
|
||||||
if (request.statusCode !== 200) {
|
|
||||||
req.flash('errors', { msg: JSON.parse(body).error.message });
|
|
||||||
return res.redirect('/api/venmo');
|
|
||||||
}
|
|
||||||
req.flash('success', { msg: 'Venmo money transfer complete' });
|
|
||||||
res.redirect('/api/venmo');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/linkedin
|
|
||||||
* LinkedIn API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getLinkedin = function(req, res, next) {
|
|
||||||
var token = _.find(req.user.tokens, { kind: 'linkedin' });
|
|
||||||
var linkedin = Linkedin.init(token.accessToken);
|
|
||||||
linkedin.people.me(function(err, $in) {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.render('api/linkedin', {
|
|
||||||
title: 'LinkedIn API',
|
|
||||||
profile: $in
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/instagram
|
|
||||||
* Instagram API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getInstagram = function(req, res, next) {
|
|
||||||
var token = _.find(req.user.tokens, { kind: 'instagram' });
|
|
||||||
ig.use({ client_id: secrets.instagram.clientID, client_secret: secrets.instagram.clientSecret });
|
|
||||||
ig.use({ access_token: token.accessToken });
|
|
||||||
async.parallel({
|
|
||||||
searchByUsername: function(done) {
|
|
||||||
ig.user_search('richellemead', function(err, users, limit) {
|
|
||||||
done(err, users);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
searchByUserId: function(done) {
|
|
||||||
ig.user('175948269', function(err, user) {
|
|
||||||
done(err, user);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
popularImages: function(done) {
|
|
||||||
ig.media_popular(function(err, medias) {
|
|
||||||
done(err, medias);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
myRecentMedia: function(done) {
|
|
||||||
ig.user_self_media_recent(function(err, medias, pagination, limit) {
|
|
||||||
done(err, medias);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, function(err, results) {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.render('api/instagram', {
|
|
||||||
title: 'Instagram API',
|
|
||||||
usernames: results.searchByUsername,
|
|
||||||
userById: results.searchByUserId,
|
|
||||||
popularImages: results.popularImages,
|
|
||||||
myRecentMedia: results.myRecentMedia
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /api/yahoo
|
|
||||||
* Yahoo API example.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.getYahoo = function(req, res) {
|
|
||||||
Y.YQL('SELECT * FROM weather.forecast WHERE (location = 10007)', function(response) {
|
|
||||||
var location = response.query.results.channel.location;
|
|
||||||
var condition = response.query.results.channel.item.condition;
|
|
||||||
res.render('api/yahoo', {
|
|
||||||
title: 'Yahoo API',
|
|
||||||
location: location,
|
|
||||||
condition: condition
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
@ -2,24 +2,29 @@
|
|||||||
* GET /
|
* GET /
|
||||||
* Challenges.
|
* Challenges.
|
||||||
*/
|
*/
|
||||||
var Challenge = require('./../models/Challenge');
|
var _ = require('lodash'),
|
||||||
var _ = require('lodash');
|
debug = require('debug')('freecc:cntr:challenges'),
|
||||||
|
Challenge = require('./../models/Challenge');
|
||||||
|
|
||||||
exports.returnChallenge = function(req, res, next) {
|
exports.returnChallenge = function(req, res, next) {
|
||||||
var challengeNumber = parseInt(req.params.challengeNumber) || 0;
|
var challengeNumber = parseInt(req.params.challengeNumber) || 0;
|
||||||
if (challengeNumber > 59) { challengeNumber = 0; }
|
|
||||||
Challenge.findOne({challengeNumber: challengeNumber}, function (err, c) {
|
if (challengeNumber > 59) {
|
||||||
if (err) {
|
challengeNumber = 0;
|
||||||
console.error('Challenge err: ', err);
|
}
|
||||||
next(err);
|
|
||||||
}
|
Challenge.findOne({ challengeNumber: challengeNumber }, function(err, c) {
|
||||||
res.render('challenges/show', {
|
if (err) {
|
||||||
title: 'Challenge: ' + c.name,
|
debug('Challenge err: ', err);
|
||||||
name: c.name,
|
return next(err);
|
||||||
video: c.video,
|
}
|
||||||
time: c.time,
|
res.render('challenges/show', {
|
||||||
steps: c.steps,
|
title: 'Challenge: ' + c.name,
|
||||||
cc: req.user.challengesHash
|
name: c.name,
|
||||||
});
|
video: c.video,
|
||||||
|
time: c.time,
|
||||||
|
steps: c.steps,
|
||||||
|
cc: req.user.challengesHash
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
@ -1,5 +1,7 @@
|
|||||||
var secrets = require('../config/secrets');
|
var nodemailer = require('nodemailer'),
|
||||||
var nodemailer = require("nodemailer");
|
debug = require('debug')('freecc:cntr:contact'),
|
||||||
|
secrets = require('../config/secrets');
|
||||||
|
|
||||||
var transporter = nodemailer.createTransport({
|
var transporter = nodemailer.createTransport({
|
||||||
service: 'Mandrill',
|
service: 'Mandrill',
|
||||||
auth: {
|
auth: {
|
||||||
@ -22,9 +24,6 @@ exports.getContact = function(req, res) {
|
|||||||
/**
|
/**
|
||||||
* POST /contact
|
* POST /contact
|
||||||
* Send a contact form via Nodemailer.
|
* Send a contact form via Nodemailer.
|
||||||
* @param email
|
|
||||||
* @param name
|
|
||||||
* @param message
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.postContact = function(req, res) {
|
exports.postContact = function(req, res) {
|
||||||
@ -32,24 +31,17 @@ exports.postContact = function(req, res) {
|
|||||||
req.assert('email', 'Email is not valid').isEmail();
|
req.assert('email', 'Email is not valid').isEmail();
|
||||||
req.assert('message', 'Message cannot be blank').notEmpty();
|
req.assert('message', 'Message cannot be blank').notEmpty();
|
||||||
|
|
||||||
var errors = req.validationErrors();
|
if (req.validationErrors()) {
|
||||||
|
|
||||||
if (errors) {
|
|
||||||
req.flash('errors', errors);
|
req.flash('errors', errors);
|
||||||
return res.redirect('/nonprofits');
|
return res.redirect('/nonprofits');
|
||||||
}
|
}
|
||||||
|
|
||||||
var from = req.body.email;
|
|
||||||
var name = req.body.name;
|
|
||||||
var body = req.body.message;
|
|
||||||
var to = 'team@freecodecamp.com';
|
|
||||||
var subject = "CodeNonprofit Project Idea from " + name;
|
|
||||||
|
|
||||||
var mailOptions = {
|
var mailOptions = {
|
||||||
to: to,
|
to: 'team@freecodecamp.com',
|
||||||
from: from,
|
name: req.body.name,
|
||||||
subject: subject,
|
from: req.body.email,
|
||||||
text: body
|
subject: 'CodeNonprofit Project Idea from ' + name,
|
||||||
|
text: req.body.message
|
||||||
};
|
};
|
||||||
|
|
||||||
transporter.sendMail(mailOptions, function(err) {
|
transporter.sendMail(mailOptions, function(err) {
|
||||||
|
@ -5,19 +5,19 @@
|
|||||||
|
|
||||||
exports.index = function(req, res) {
|
exports.index = function(req, res) {
|
||||||
if (req.user) {
|
if (req.user) {
|
||||||
ch = req.user.challengesHash;
|
ch = req.user.challengesHash;
|
||||||
if (req.user.challengesHash[0] > 0) {
|
if (req.user.challengesHash[0] > 0) {
|
||||||
var max = Object.keys(ch).reduce(function(max,key){
|
var max = Object.keys(ch).reduce(function(max, key) {
|
||||||
return (max === undefined || ch[key] > ch[max]) ? +key : max;
|
return (max === undefined || ch[key] > ch[max]) ? +key : max;
|
||||||
});
|
|
||||||
nextChallenge = max + 1;
|
|
||||||
res.redirect("challenges/" + nextChallenge);
|
|
||||||
} else {
|
|
||||||
res.redirect("challenges/0");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.render('home', {
|
|
||||||
title: 'Learn to Code and Become a Software Engineer'
|
|
||||||
});
|
});
|
||||||
|
nextChallenge = max + 1;
|
||||||
|
res.redirect('challenges/' + nextChallenge);
|
||||||
|
} else {
|
||||||
|
res.redirect('challenges/0');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.render('home', {
|
||||||
|
title: 'Learn to Code and Become a Software Engineer'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -1,271 +1,98 @@
|
|||||||
|
var User = require('../models/User'),
|
||||||
|
resources = require('./resources.json'),
|
||||||
|
questions = resources.questions,
|
||||||
|
steps = resources.steps;
|
||||||
|
|
||||||
var User = require('../models/User');
|
//NOTE(BERKS): Async, total users may not available before it is used.
|
||||||
|
var totalUsers = 0;
|
||||||
var totalUsers = User.count({}, function( err, count){
|
User.count({}, function(err, count) {
|
||||||
count;
|
totalUsers = count;
|
||||||
});
|
});
|
||||||
|
|
||||||
//var usersOverTenChallenges = User.where: "this.challengesCompleted && this.challengesCompleted.length >= 10"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET /
|
* GET /
|
||||||
* Resources.
|
* Resources.
|
||||||
*/
|
*/
|
||||||
|
//TODO: Stats view
|
||||||
exports.learnToCode = function(req, res) {
|
module.exports = {
|
||||||
res.render('learn-to-code', {
|
learnToCode: function(req, res) {
|
||||||
title: 'Learn to Code'
|
res.render('learn-to-code', {
|
||||||
|
title: 'Learn to Code'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
exports.privacy = function(req, res) {
|
privacy: function privacy(req, res) {
|
||||||
res.render('privacy', {
|
res.render('privacy', {
|
||||||
title: 'Privacy'
|
title: 'Privacy'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
exports.statistics = function(req, res) {
|
statistics: function statistics(req, res) {
|
||||||
res.render('statistics', {
|
res.render('statistics', {
|
||||||
title: 'Code Camper Statistics',
|
title: 'Code Camper Statistics'
|
||||||
//totalUsers: totalUsers,
|
//totalUsers: totalUsers,
|
||||||
//usersOverTenChallenges: usersOverTenChallenges
|
//usersOverTenChallenges: usersOverTenChallenges
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
exports.chromebook = function(req, res) {
|
chromebook: function chromebook(req, res) {
|
||||||
res.render('chromebook', {
|
res.render('chromebook', {
|
||||||
title: 'Win a Chromebook'
|
title: 'Win a Chromebook'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
exports.jqueryExercises = function(req, res) {
|
jqueryExercises: function jqueryExercises(req, res) {
|
||||||
res.render('jquery-exercises', {
|
res.render('jquery-exercises', {
|
||||||
title: 'jQuery Exercises'
|
title: 'jQuery Exercises'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
exports.livePairProgramming = function(req, res) {
|
livePairProgramming: function(req, res) {
|
||||||
res.render('live-pair-programming', {
|
res.render('live-pair-programming', {
|
||||||
title: 'Live Pair Programming'
|
title: 'Live Pair Programming'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
exports.javaScriptInYourInbox = function(req, res) {
|
javaScriptInYourInbox: function(req, res) {
|
||||||
res.render('javascript-in-your-inbox', {
|
res.render('javascript-in-your-inbox', {
|
||||||
title: 'JavaScript in your Inbox'
|
title: 'JavaScript in your Inbox'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
exports.programmerInterviewQuestionsApp = function(req, res) {
|
programmerInterviewQuestionsApp: function(req, res) {
|
||||||
res.render('programmer-interview-questions-app', {
|
res.render('programmer-interview-questions-app', {
|
||||||
title: 'Programmer Interview Questions App'
|
title: 'Programmer Interview Questions App'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
exports.pairProgramWithTeamViewer = function(req, res) {
|
pairProgramWithTeamViewer: function(req, res) {
|
||||||
res.render('pair-program-with-team-viewer', {
|
res.render('pair-program-with-team-viewer', {
|
||||||
title: 'Challenge: Pair Program with Team Viewer',
|
title: 'Challenge: Pair Program with Team Viewer',
|
||||||
name: "Pair Program with Team Viewer",
|
name: 'Pair Program with Team Viewer',
|
||||||
video: '',
|
video: '',
|
||||||
time: 30,
|
time: 30,
|
||||||
steps: ["In the spirit of keeping Free Code Camp 100% free, we've created directions for using a totally free pair programming tool called Team Viewer. It's not as user-friendly as Screen Hero, but it gets the job done (and works on Linux!).",
|
steps: steps,
|
||||||
"Go to <a href='http://www.teamviewer.com/en/index.aspx' target='_blank'>http://www.teamviewer.com/en/index.aspx</a> and download Team Viewer. Be sure not to download the beta version, which isn't compatible with the current stable version everyone else will be using.",
|
cc: req.user.challengesHash
|
||||||
"Install it and launch it",
|
|
||||||
"Go to the chat room and ask if anyone wants to pair program with you on a CoderByte challenge.",
|
|
||||||
"If someone is interested, they will be your \"pair\" - the person you pair programming with.",
|
|
||||||
"<strong>First, you will pair program on your pair's computer.</strong> Ask your pair for his or her Team Viewer ID and password.",
|
|
||||||
"Enter this id, and then password, to start the session.",
|
|
||||||
"Once the Team Viewer session starts, look at the the top of the screen. You will see 6 buttons. If you hover your cursor over the buttons, they will slide down so that you can read them. Click the audio/video button. This will allow you to turn on Voice Over IP and unmute your microphone, opening up your voice channel.",
|
|
||||||
"Note that you can now control your pair's keyboard and mouse, enabling you to step in and code yourself on your pair's computer when desired",
|
|
||||||
"Now you can click the X to end the pair programming session.",
|
|
||||||
"<strong>Next, you will pair program on your computer.</strong> Copy your Team Viewer ID and paste it into the private chat, so that your pair can use it to connect with you.",
|
|
||||||
"You will need to share your randomly generated password with your pair as well.",
|
|
||||||
"Once your pair connects, you will see a Team Viewer side menu. ",
|
|
||||||
"Click the audio button that drops down.",
|
|
||||||
"Click the headset icon and choose Voice over IP",
|
|
||||||
"Click the microphone button to unmute your microphone. Once your pair does the same, you two will have an open voice channel.",
|
|
||||||
"Now you can click the X to end the pair programming session.",
|
|
||||||
"Now it's time to tackle CoderByte.",
|
|
||||||
"Create a CoderByte account at <a href='http://coderbyte.com/sl/' target='_blank'>http://coderbyte.com/sl/</a>",
|
|
||||||
"Now go to <a href='http://coderbyte.com/CodingArea/Challenges/#easyChals' target='_blank'>http://coderbyte.com/CodingArea/Challenges/#easyChals</a> and start working through Coderbyte's easy algorithm scripting challenges using JavaScript.",
|
|
||||||
"When you are finished pair programming, click the X to end the session.",
|
|
||||||
"Congratulations! You have completed your first pair programming session.",
|
|
||||||
"You should pair program with different Code Campers until you've completed all the Easy, Medium and Hard CoderByte challenges. This is a big time investment, but the JavaScript practice you'll get, along with the scripting and algorithm experience, are well worth it!",
|
|
||||||
"You can complete CoderByte problems while you continue to work through Free Code Camp's challenges.",
|
|
||||||
"Be sure to pair program on these challenges, and remember to apply the RSAP methodology.",
|
|
||||||
"Click the button below to return to the Pair Programming challenge, then mark it complete."],
|
|
||||||
cc: req.user.challengesHash
|
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
exports.about = function(req, res) {
|
|
||||||
|
about: function(req, res) {
|
||||||
res.render('about', {
|
res.render('about', {
|
||||||
title: 'About Free Code Camp and Our Team of Volunteers'
|
title: 'About Free Code Camp and Our Team of Volunteers'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
exports.doneWithFirst100Hours = function(req, res) {
|
doneWithFirst100Hours: function(req, res) {
|
||||||
res.render('done-with-first-100-hours', {
|
res.render('done-with-first-100-hours', {
|
||||||
title: 'Congratulations on finishing the first 100 hours of Free Code Camp!'
|
title:
|
||||||
|
'Congratulations on finishing the first 100 hours of Free Code Camp!'
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
exports.interviewQuestions = function(req, res) {
|
interviewQuestions: function(req, res) {
|
||||||
res.json([
|
res.json(questions);
|
||||||
{
|
}
|
||||||
question: "Time Complexity of Accessing Array Index (int a = ARR[5];)",
|
|
||||||
answer: "O(1)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Inserting a node in Linked List",
|
|
||||||
answer: "O(1)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Pushing and Popping on Stack",
|
|
||||||
answer: "O(1)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Insertion and Removal from Queue",
|
|
||||||
answer: "O(1)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Finding out the parent or left/right child of a node in a tree stored in Array",
|
|
||||||
answer: "O(1)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Jumping to Next/Previous element in Doubly Linked List",
|
|
||||||
answer: "O(1)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Traversing an array",
|
|
||||||
answer: "O(n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Traversing a linked list",
|
|
||||||
answer: "O(n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Linear Search",
|
|
||||||
answer: "O(n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Deletion of a specific element in a Linked List (Not sorted)",
|
|
||||||
answer: "O(n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Comparing two strings",
|
|
||||||
answer: "O(n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Checking for Palindrome",
|
|
||||||
answer: "O(n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Counting/Bucket Sort",
|
|
||||||
answer: "O(n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Binary Search",
|
|
||||||
answer: "O(log n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Finding largest/smallest number in a binary search tree",
|
|
||||||
answer: "O(log n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Certain Divide and Conquer Algorithms based on Linear functionality",
|
|
||||||
answer: "O(log n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Calculating Fibonacci Numbers - Best Method",
|
|
||||||
answer: "O(log n)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Merge Sort",
|
|
||||||
answer: "O(nlogn)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Heap Sort",
|
|
||||||
answer: "O(nlogn)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Quick Sort",
|
|
||||||
answer: "O(nlogn)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Certain Divide and Conquer Algorithms based on optimizing O(n^2) algorithms",
|
|
||||||
answer: "O(nlogn)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Bubble Sort",
|
|
||||||
answer: "O(n^2)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Insertion Sort",
|
|
||||||
answer: "O(n^2)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Selection Sort",
|
|
||||||
answer: "O(n^2)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Time Complexity of Traversing a simple 2D array",
|
|
||||||
answer: "O(n^2)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of L1 cache reference",
|
|
||||||
answer: "0.5 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Branch mispredict",
|
|
||||||
answer: "5 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of L2 cache reference",
|
|
||||||
answer: "7 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Mutex lock/unlock",
|
|
||||||
answer: "25 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Main memory reference",
|
|
||||||
answer: "100 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Compressing 1K bytes with Zippy",
|
|
||||||
answer: "3,000 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Sending 1K bytes over a 1 Gbps network",
|
|
||||||
answer: "10,000 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Reading 4K randomly from SSD",
|
|
||||||
answer: "150,000 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Reading 1 MB sequentially from memory",
|
|
||||||
answer: "250,000 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of a Round trip within the same datacenter",
|
|
||||||
answer: "500,000 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Reading 1 MB sequentially from SSD",
|
|
||||||
answer: "1,000,000 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Disk seek",
|
|
||||||
answer: "10,000,000 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Reading 1 MB sequentially from disk",
|
|
||||||
answer: "20,000,000 nanoseconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
question: "Latency of Sending a packet from California to the Netherlands and back",
|
|
||||||
answer: "150,000,000 nanoseconds"
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
148
controllers/resources.json
Normal file
148
controllers/resources.json
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
{
|
||||||
|
"questions": [{
|
||||||
|
"question": "Time Complexity of Accessing Array Index (int a = ARR[5];)",
|
||||||
|
"answer": "O(1)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Inserting a node in Linked List",
|
||||||
|
"answer": "O(1)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Pushing and Popping on Stack",
|
||||||
|
"answer": "O(1)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Insertion and Removal from Queue",
|
||||||
|
"answer": "O(1)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Finding out the parent or left/right child of a node in a tree stored in Array",
|
||||||
|
"answer": "O(1)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Jumping to Next/Previous element in Doubly Linked List",
|
||||||
|
"answer": "O(1)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Traversing an array",
|
||||||
|
"answer": "O(n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Traversing a linked list",
|
||||||
|
"answer": "O(n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Linear Search",
|
||||||
|
"answer": "O(n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Deletion of a specific element in a Linked List (Not sorted)",
|
||||||
|
"answer": "O(n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Comparing two strings",
|
||||||
|
"answer": "O(n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Checking for Palindrome",
|
||||||
|
"answer": "O(n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Counting/Bucket Sort",
|
||||||
|
"answer": "O(n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Binary Search",
|
||||||
|
"answer": "O(log n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Finding largest/smallest number in a binary search tree",
|
||||||
|
"answer": "O(log n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Certain Divide and Conquer Algorithms based on Linear functionality",
|
||||||
|
"answer": "O(log n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Calculating Fibonacci Numbers - Best Method",
|
||||||
|
"answer": "O(log n)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Merge Sort",
|
||||||
|
"answer": "O(nlogn)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Heap Sort",
|
||||||
|
"answer": "O(nlogn)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Quick Sort",
|
||||||
|
"answer": "O(nlogn)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Certain Divide and Conquer Algorithms based on optimizing O(n^2) algorithms",
|
||||||
|
"answer": "O(nlogn)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Bubble Sort",
|
||||||
|
"answer": "O(n^2)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Insertion Sort",
|
||||||
|
"answer": "O(n^2)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Selection Sort",
|
||||||
|
"answer": "O(n^2)"
|
||||||
|
}, {
|
||||||
|
"question": "Time Complexity of Traversing a simple 2D array",
|
||||||
|
"answer": "O(n^2)"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of L1 cache reference",
|
||||||
|
"answer": "0.5 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Branch mispredict",
|
||||||
|
"answer": "5 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of L2 cache reference",
|
||||||
|
"answer": "7 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Mutex lock/unlock",
|
||||||
|
"answer": "25 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Main memory reference",
|
||||||
|
"answer": "100 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Compressing 1K bytes with Zippy",
|
||||||
|
"answer": "3,000 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Sending 1K bytes over a 1 Gbps network",
|
||||||
|
"answer": "10,000 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Reading 4K randomly from SSD",
|
||||||
|
"answer": "150,000 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Reading 1 MB sequentially from memory",
|
||||||
|
"answer": "250,000 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of a Round trip within the same datacenter",
|
||||||
|
"answer": "500,000 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Reading 1 MB sequentially from SSD",
|
||||||
|
"answer": "1,000,000 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Disk seek",
|
||||||
|
"answer": "10,000,000 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Reading 1 MB sequentially from disk",
|
||||||
|
"answer": "20,000,000 nanoseconds"
|
||||||
|
}, {
|
||||||
|
"question": "Latency of Sending a packet from California to the Netherlands and back",
|
||||||
|
"answer": "150,000,000 nanoseconds"
|
||||||
|
}],
|
||||||
|
"steps": [
|
||||||
|
"In the spirit of keeping Free Code Camp 100% free, we've created directions for using a totally free pair programming tool called Team Viewer. It's not as user-friendly as Screen Hero, but it gets the job done (and works on Linux!).",
|
||||||
|
"Go to <a href='http://www.teamviewer.com/en/index.aspx' target='_blank'>http://www.teamviewer.com/en/index.aspx</a> and download Team Viewer. Be sure not to download the beta version, which isn't compatible with the current stable version everyone else will be using.",
|
||||||
|
"Install it and launch it",
|
||||||
|
"Go to the chat room and ask if anyone wants to pair program with you on a CoderByte challenge.",
|
||||||
|
"If someone is interested, they will be your \"pair\" - the person you pair programming with.",
|
||||||
|
"<strong>First, you will pair program on your pair's computer.</strong> Ask your pair for his or her Team Viewer ID and password.",
|
||||||
|
"Enter this id, and then password, to start the session.",
|
||||||
|
"Once the Team Viewer session starts, look at the the top of the screen. You will see 6 buttons. If you hover your cursor over the buttons, they will slide down so that you can read them. Click the audio/video button. This will allow you to turn on Voice Over IP and unmute your microphone, opening up your voice channel.",
|
||||||
|
"Note that you can now control your pair's keyboard and mouse, enabling you to step in and code yourself on your pair's computer when desired",
|
||||||
|
"Now you can click the X to end the pair programming session.",
|
||||||
|
"<strong>Next, you will pair program on your computer.</strong> Copy your Team Viewer ID and paste it into the private chat, so that your pair can use it to connect with you.",
|
||||||
|
"You will need to share your randomly generated password with your pair as well.",
|
||||||
|
"Once your pair connects, you will see a Team Viewer side menu. ",
|
||||||
|
"Click the audio button that drops down.",
|
||||||
|
"Click the headset icon and choose Voice over IP",
|
||||||
|
"Click the microphone button to unmute your microphone. Once your pair does the same, you two will have an open voice channel.",
|
||||||
|
"Now you can click the X to end the pair programming session.",
|
||||||
|
"Now it's time to tackle CoderByte.",
|
||||||
|
"Create a CoderByte account at <a href='http://coderbyte.com/sl/' target='_blank'>http://coderbyte.com/sl/</a>",
|
||||||
|
"Now go to <a href='http://coderbyte.com/CodingArea/Challenges/#easyChals' target='_blank'>http://coderbyte.com/CodingArea/Challenges/#easyChals</a> and start working through Coderbyte's easy algorithm scripting challenges using JavaScript.",
|
||||||
|
"When you are finished pair programming, click the X to end the session.",
|
||||||
|
"Congratulations! You have completed your first pair programming session.",
|
||||||
|
"You should pair program with different Code Campers until you've completed all the Easy, Medium and Hard CoderByte challenges. This is a big time investment, but the JavaScript practice you'll get, along with the scripting and algorithm experience, are well worth it!",
|
||||||
|
"You can complete CoderByte problems while you continue to work through Free Code Camp's challenges.",
|
||||||
|
"Be sure to pair program on these challenges, and remember to apply the RSAP methodology.",
|
||||||
|
"Click the button below to return to the Pair Programming challenge, then mark it complete."
|
||||||
|
]
|
||||||
|
}
|
@ -7,6 +7,7 @@ var User = require('../models/User');
|
|||||||
var secrets = require('../config/secrets');
|
var secrets = require('../config/secrets');
|
||||||
var moment = require('moment');
|
var moment = require('moment');
|
||||||
|
|
||||||
|
//TODO(Berks): Refactor to use module.exports = {} pattern.
|
||||||
/**
|
/**
|
||||||
* GET /login
|
* GET /login
|
||||||
* Login page.
|
* Login page.
|
||||||
@ -22,8 +23,6 @@ exports.getLogin = function(req, res) {
|
|||||||
/**
|
/**
|
||||||
* POST /login
|
* POST /login
|
||||||
* Sign in using email and password.
|
* Sign in using email and password.
|
||||||
* @param email
|
|
||||||
* @param password
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.postLogin = function(req, res, next) {
|
exports.postLogin = function(req, res, next) {
|
||||||
@ -88,14 +87,13 @@ exports.getEmailSignup = function(req, res) {
|
|||||||
/**
|
/**
|
||||||
* POST /email-signup
|
* POST /email-signup
|
||||||
* Create a new local account.
|
* Create a new local account.
|
||||||
* @param email
|
|
||||||
* @param password
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.postEmailSignup = function(req, res, next) {
|
exports.postEmailSignup = function(req, res, next) {
|
||||||
req.assert('email', 'Email is not valid').isEmail();
|
req.assert('email', 'Email is not valid').isEmail();
|
||||||
req.assert('password', 'Password must be at least 4 characters long').len(4);
|
req.assert('password', 'Password must be at least 4 characters long').len(4);
|
||||||
req.assert('confirmPassword', 'Passwords do not match').equals(req.body.password);
|
req.assert('confirmPassword', 'Passwords do not match')
|
||||||
|
.equals(req.body.password);
|
||||||
|
|
||||||
var errors = req.validationErrors();
|
var errors = req.validationErrors();
|
||||||
|
|
||||||
@ -110,14 +108,19 @@ exports.postEmailSignup = function(req, res, next) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
User.findOne({ email: req.body.email }, function(err, existingUser) {
|
User.findOne({ email: req.body.email }, function(err, existingUser) {
|
||||||
|
if (err) { return next(err); }
|
||||||
|
|
||||||
if (existingUser) {
|
if (existingUser) {
|
||||||
req.flash('errors', { msg: 'Account with that email address already exists.' });
|
req.flash('errors', {
|
||||||
|
msg: 'Account with that email address already exists.'
|
||||||
|
});
|
||||||
return res.redirect('/email-signup');
|
return res.redirect('/email-signup');
|
||||||
}
|
}
|
||||||
user.save(function(err) {
|
user.save(function(err) {
|
||||||
if (err) return next(err);
|
if (err) { return next(err); }
|
||||||
|
|
||||||
req.logIn(user, function(err) {
|
req.logIn(user, function(err) {
|
||||||
if (err) return next(err);
|
if (err) { return next(err); }
|
||||||
res.redirect('/email-signup');
|
res.redirect('/email-signup');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -188,12 +191,12 @@ exports.postUpdateProfile = function(req, res, next) {
|
|||||||
/**
|
/**
|
||||||
* POST /account/password
|
* POST /account/password
|
||||||
* Update current password.
|
* Update current password.
|
||||||
* @param password
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.postUpdatePassword = function(req, res, next) {
|
exports.postUpdatePassword = function(req, res, next) {
|
||||||
req.assert('password', 'Password must be at least 4 characters long').len(4);
|
req.assert('password', 'Password must be at least 4 characters long').len(4);
|
||||||
req.assert('confirmPassword', 'Passwords do not match').equals(req.body.password);
|
req.assert('confirmPassword', 'Passwords do not match')
|
||||||
|
.equals(req.body.password);
|
||||||
|
|
||||||
var errors = req.validationErrors();
|
var errors = req.validationErrors();
|
||||||
|
|
||||||
@ -203,12 +206,13 @@ exports.postUpdatePassword = function(req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
User.findById(req.user.id, function(err, user) {
|
User.findById(req.user.id, function(err, user) {
|
||||||
if (err) return next(err);
|
if (err) { return next(err); }
|
||||||
|
|
||||||
user.password = req.body.password;
|
user.password = req.body.password;
|
||||||
|
|
||||||
user.save(function(err) {
|
user.save(function(err) {
|
||||||
if (err) return next(err);
|
if (err) { return next(err); }
|
||||||
|
|
||||||
req.flash('success', { msg: 'Password has been changed.' });
|
req.flash('success', { msg: 'Password has been changed.' });
|
||||||
res.redirect('/account');
|
res.redirect('/account');
|
||||||
});
|
});
|
||||||
@ -222,7 +226,7 @@ exports.postUpdatePassword = function(req, res, next) {
|
|||||||
|
|
||||||
exports.postDeleteAccount = function(req, res, next) {
|
exports.postDeleteAccount = function(req, res, next) {
|
||||||
User.remove({ _id: req.user.id }, function(err) {
|
User.remove({ _id: req.user.id }, function(err) {
|
||||||
if (err) return next(err);
|
if (err) { return next(err); }
|
||||||
req.logout();
|
req.logout();
|
||||||
req.flash('info', { msg: 'Your account has been deleted.' });
|
req.flash('info', { msg: 'Your account has been deleted.' });
|
||||||
res.redirect('/');
|
res.redirect('/');
|
||||||
@ -232,19 +236,21 @@ exports.postDeleteAccount = function(req, res, next) {
|
|||||||
/**
|
/**
|
||||||
* GET /account/unlink/:provider
|
* GET /account/unlink/:provider
|
||||||
* Unlink OAuth provider.
|
* Unlink OAuth provider.
|
||||||
* @param provider
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.getOauthUnlink = function(req, res, next) {
|
exports.getOauthUnlink = function(req, res, next) {
|
||||||
var provider = req.params.provider;
|
var provider = req.params.provider;
|
||||||
User.findById(req.user.id, function(err, user) {
|
User.findById(req.user.id, function(err, user) {
|
||||||
if (err) return next(err);
|
if (err) { return next(err); }
|
||||||
|
|
||||||
user[provider] = undefined;
|
user[provider] = undefined;
|
||||||
user.tokens = _.reject(user.tokens, function(token) { return token.kind === provider; });
|
user.tokens =
|
||||||
|
_.reject(user.tokens, function(token) {
|
||||||
|
return token.kind === provider;
|
||||||
|
});
|
||||||
|
|
||||||
user.save(function(err) {
|
user.save(function(err) {
|
||||||
if (err) return next(err);
|
if (err) { return next(err); }
|
||||||
req.flash('info', { msg: provider + ' account has been unlinked.' });
|
req.flash('info', { msg: provider + ' account has been unlinked.' });
|
||||||
res.redirect('/account');
|
res.redirect('/account');
|
||||||
});
|
});
|
||||||
@ -264,8 +270,11 @@ exports.getReset = function(req, res) {
|
|||||||
.findOne({ resetPasswordToken: req.params.token })
|
.findOne({ resetPasswordToken: req.params.token })
|
||||||
.where('resetPasswordExpires').gt(Date.now())
|
.where('resetPasswordExpires').gt(Date.now())
|
||||||
.exec(function(err, user) {
|
.exec(function(err, user) {
|
||||||
|
if (err) { return next(err); }
|
||||||
if (!user) {
|
if (!user) {
|
||||||
req.flash('errors', { msg: 'Password reset token is invalid or has expired.' });
|
req.flash('errors', {
|
||||||
|
msg: 'Password reset token is invalid or has expired.'
|
||||||
|
});
|
||||||
return res.redirect('/forgot');
|
return res.redirect('/forgot');
|
||||||
}
|
}
|
||||||
res.render('account/reset', {
|
res.render('account/reset', {
|
||||||
@ -277,7 +286,6 @@ exports.getReset = function(req, res) {
|
|||||||
/**
|
/**
|
||||||
* POST /reset/:token
|
* POST /reset/:token
|
||||||
* Process the reset password request.
|
* Process the reset password request.
|
||||||
* @param token
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.postReset = function(req, res, next) {
|
exports.postReset = function(req, res, next) {
|
||||||
@ -297,8 +305,11 @@ exports.postReset = function(req, res, next) {
|
|||||||
.findOne({ resetPasswordToken: req.params.token })
|
.findOne({ resetPasswordToken: req.params.token })
|
||||||
.where('resetPasswordExpires').gt(Date.now())
|
.where('resetPasswordExpires').gt(Date.now())
|
||||||
.exec(function(err, user) {
|
.exec(function(err, user) {
|
||||||
|
if (err) { return next(err); }
|
||||||
if (!user) {
|
if (!user) {
|
||||||
req.flash('errors', { msg: 'Password reset token is invalid or has expired.' });
|
req.flash('errors', {
|
||||||
|
msg: 'Password reset token is invalid or has expired.'
|
||||||
|
});
|
||||||
return res.redirect('back');
|
return res.redirect('back');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +318,7 @@ exports.postReset = function(req, res, next) {
|
|||||||
user.resetPasswordExpires = undefined;
|
user.resetPasswordExpires = undefined;
|
||||||
|
|
||||||
user.save(function(err) {
|
user.save(function(err) {
|
||||||
if (err) return next(err);
|
if (err) { return done(err); }
|
||||||
req.logIn(user, function(err) {
|
req.logIn(user, function(err) {
|
||||||
done(err, user);
|
done(err, user);
|
||||||
});
|
});
|
||||||
@ -326,16 +337,25 @@ exports.postReset = function(req, res, next) {
|
|||||||
to: user.email,
|
to: user.email,
|
||||||
from: 'Team@freecodecamp.com',
|
from: 'Team@freecodecamp.com',
|
||||||
subject: 'Your Free Code Camp password has been changed',
|
subject: 'Your Free Code Camp password has been changed',
|
||||||
text: 'Hello,\n\n' +
|
text: [
|
||||||
'This email is confirming that you requested to reset your password for your Free Code Camp account. This is your email: ' + user.email + '\n'
|
'Hello,\n\n',
|
||||||
|
'This email is confirming that you requested to',
|
||||||
|
'reset your password for your Free Code Camp account.',
|
||||||
|
'This is your email:',
|
||||||
|
user.email,
|
||||||
|
'\n'
|
||||||
|
].join(' ')
|
||||||
};
|
};
|
||||||
transporter.sendMail(mailOptions, function(err) {
|
transporter.sendMail(mailOptions, function(err) {
|
||||||
req.flash('success', { msg: 'Success! Your password has been changed.' });
|
if (err) { return done(err); }
|
||||||
done(err);
|
req.flash('success', {
|
||||||
|
msg: 'Success! Your password has been changed.'
|
||||||
|
});
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
], function(err) {
|
], function(err) {
|
||||||
if (err) return next(err);
|
if (err) { return next(err); }
|
||||||
res.redirect('/');
|
res.redirect('/');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -357,7 +377,6 @@ exports.getForgot = function(req, res) {
|
|||||||
/**
|
/**
|
||||||
* POST /forgot
|
* POST /forgot
|
||||||
* Create a random token, then the send user an email with a reset link.
|
* Create a random token, then the send user an email with a reset link.
|
||||||
* @param email
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports.postForgot = function(req, res, next) {
|
exports.postForgot = function(req, res, next) {
|
||||||
@ -373,14 +392,20 @@ exports.postForgot = function(req, res, next) {
|
|||||||
async.waterfall([
|
async.waterfall([
|
||||||
function(done) {
|
function(done) {
|
||||||
crypto.randomBytes(16, function(err, buf) {
|
crypto.randomBytes(16, function(err, buf) {
|
||||||
|
if (err) { return done(err); }
|
||||||
var token = buf.toString('hex');
|
var token = buf.toString('hex');
|
||||||
done(err, token);
|
done(null, token);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(token, done) {
|
function(token, done) {
|
||||||
User.findOne({ email: req.body.email.toLowerCase() }, function(err, user) {
|
User.findOne({
|
||||||
|
email: req.body.email.toLowerCase()
|
||||||
|
}, function(err, user) {
|
||||||
|
if (err) { return done(err); }
|
||||||
if (!user) {
|
if (!user) {
|
||||||
req.flash('errors', { msg: 'No account with that email address exists.' });
|
req.flash('errors', {
|
||||||
|
msg: 'No account with that email address exists.'
|
||||||
|
});
|
||||||
return res.redirect('/forgot');
|
return res.redirect('/forgot');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,7 +413,8 @@ exports.postForgot = function(req, res, next) {
|
|||||||
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
|
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
|
||||||
|
|
||||||
user.save(function(err) {
|
user.save(function(err) {
|
||||||
done(err, token, user);
|
if (err) { return done(err); }
|
||||||
|
done(null, token, user);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -404,18 +430,32 @@ exports.postForgot = function(req, res, next) {
|
|||||||
to: user.email,
|
to: user.email,
|
||||||
from: 'Team@freecodecamp.com',
|
from: 'Team@freecodecamp.com',
|
||||||
subject: 'Reset your Free Code Camp password',
|
subject: 'Reset your Free Code Camp password',
|
||||||
text: "You are receiving this email because you (or someone else) requested we reset your Free Code Camp account's password.\n\n" +
|
text: [
|
||||||
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
|
'You are receiving this email because you (or someone else)',
|
||||||
'http://' + req.headers.host + '/reset/' + token + '\n\n' +
|
'requested we reset your Free Code Camp account\'s password.\n\n',
|
||||||
'If you did not request this, please ignore this email and your password will remain unchanged.\n'
|
'Please click on the following link, or paste this into your',
|
||||||
|
'browser to complete the process:\n\n',
|
||||||
|
'http://',
|
||||||
|
req.headers.host,
|
||||||
|
'/reset/',
|
||||||
|
token,
|
||||||
|
'\n\n',
|
||||||
|
'If you did not request this, please ignore this email and',
|
||||||
|
'your password will remain unchanged.\n'
|
||||||
|
].join(' ')
|
||||||
};
|
};
|
||||||
transporter.sendMail(mailOptions, function(err) {
|
transporter.sendMail(mailOptions, function(err) {
|
||||||
req.flash('info', { msg: 'An e-mail has been sent to ' + user.email + ' with further instructions.' });
|
if (err) { return done(err); }
|
||||||
done(err, 'done');
|
req.flash('info', {
|
||||||
|
msg: 'An e-mail has been sent to ' +
|
||||||
|
user.email +
|
||||||
|
' with further instructions.'
|
||||||
|
});
|
||||||
|
done(null, 'done');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
], function(err) {
|
], function(err) {
|
||||||
if (err) return next(err);
|
if (err) { return next(err); }
|
||||||
res.redirect('/forgot');
|
res.redirect('/forgot');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
20
gulpfile.js
20
gulpfile.js
@ -9,8 +9,9 @@ var gulp = require('gulp'),
|
|||||||
|
|
||||||
var paths = {
|
var paths = {
|
||||||
server: './app.js',
|
server: './app.js',
|
||||||
serverIgnore: [],
|
serverIgnore: []
|
||||||
}
|
};
|
||||||
|
|
||||||
gulp.task('inject', function() {
|
gulp.task('inject', function() {
|
||||||
gulp.src('views/home.jade')
|
gulp.src('views/home.jade')
|
||||||
.pipe(inject(gulp.src(bower()), {
|
.pipe(inject(gulp.src(bower()), {
|
||||||
@ -51,15 +52,12 @@ gulp.task('serve', function(cb) {
|
|||||||
|
|
||||||
gulp.task('sync', ['serve'], function() {
|
gulp.task('sync', ['serve'], function() {
|
||||||
sync.init(null, {
|
sync.init(null, {
|
||||||
proxy: 'http://localhost:3000',
|
proxy: 'http://localhost:3000',
|
||||||
logLeval: 'debug',
|
logLeval: 'debug',
|
||||||
files: [
|
files: ['public/**/*'],
|
||||||
'public/**/*',
|
port: 3001,
|
||||||
],
|
open: true,
|
||||||
port: 3001,
|
reloadDelay: reloadDelay
|
||||||
open: true,
|
|
||||||
browser: ['safari', 'google chrome'],
|
|
||||||
reloadDelay: reloadDelay
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,12 +2,15 @@ var mongoose = require('mongoose');
|
|||||||
var secrets = require('../config/secrets');
|
var secrets = require('../config/secrets');
|
||||||
|
|
||||||
var challengeSchema = new mongoose.Schema({
|
var challengeSchema = new mongoose.Schema({
|
||||||
name: { type: String, unique: true },
|
name: {
|
||||||
link: String,
|
type: String,
|
||||||
time: String,
|
unique: true
|
||||||
challengeNumber: Number,
|
},
|
||||||
video: String,
|
link: String,
|
||||||
steps: Array
|
time: String,
|
||||||
|
challengeNumber: Number,
|
||||||
|
video: String,
|
||||||
|
steps: Array
|
||||||
});
|
});
|
||||||
|
|
||||||
var Challenge = module.exports = mongoose.model('Challenge', challengeSchema);
|
module.exports = mongoose.model('Challenge', challengeSchema);
|
||||||
|
347
models/User.js
347
models/User.js
@ -3,7 +3,12 @@ var crypto = require('crypto');
|
|||||||
var mongoose = require('mongoose');
|
var mongoose = require('mongoose');
|
||||||
|
|
||||||
var userSchema = new mongoose.Schema({
|
var userSchema = new mongoose.Schema({
|
||||||
//email: { type: String, unique: true, lowercase: true, match: /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/ },
|
/*email: {
|
||||||
|
type: String,
|
||||||
|
unique: true,
|
||||||
|
lowercase: true,
|
||||||
|
match: /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/
|
||||||
|
},*/
|
||||||
email: String,
|
email: String,
|
||||||
password: String,
|
password: String,
|
||||||
|
|
||||||
@ -14,77 +19,277 @@ var userSchema = new mongoose.Schema({
|
|||||||
instagram: String,
|
instagram: String,
|
||||||
linkedin: String,
|
linkedin: String,
|
||||||
tokens: Array,
|
tokens: Array,
|
||||||
points: { type: Number, default: 0 },
|
points: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
challengesCompleted: { type: Array, default: [] },
|
challengesCompleted: { type: Array, default: [] },
|
||||||
challengesHash: {
|
challengesHash: {
|
||||||
0: { type: Number, default: 0 },
|
0: {
|
||||||
1: { type: Number, default: 0 },
|
type: Number,
|
||||||
2: { type: Number, default: 0 },
|
default: 0
|
||||||
3: { type: Number, default: 0 },
|
},
|
||||||
4: { type: Number, default: 0 },
|
1: {
|
||||||
5: { type: Number, default: 0 },
|
type: Number,
|
||||||
6: { type: Number, default: 0 },
|
default: 0
|
||||||
7: { type: Number, default: 0 },
|
},
|
||||||
8: { type: Number, default: 0 },
|
2: {
|
||||||
9: { type: Number, default: 0 },
|
type: Number,
|
||||||
10: { type: Number, default: 0 },
|
default: 0
|
||||||
11: { type: Number, default: 0 },
|
},
|
||||||
12: { type: Number, default: 0 },
|
3: {
|
||||||
13: { type: Number, default: 0 },
|
type: Number,
|
||||||
14: { type: Number, default: 0 },
|
default: 0
|
||||||
15: { type: Number, default: 0 },
|
},
|
||||||
16: { type: Number, default: 0 },
|
4: {
|
||||||
17: { type: Number, default: 0 },
|
type: Number,
|
||||||
18: { type: Number, default: 0 },
|
default: 0
|
||||||
19: { type: Number, default: 0 },
|
},
|
||||||
20: { type: Number, default: 0 },
|
5: {
|
||||||
21: { type: Number, default: 0 },
|
type: Number,
|
||||||
22: { type: Number, default: 0 },
|
default: 0
|
||||||
23: { type: Number, default: 0 },
|
},
|
||||||
24: { type: Number, default: 0 },
|
6: {
|
||||||
25: { type: Number, default: 0 },
|
type: Number,
|
||||||
26: { type: Number, default: 0 },
|
default: 0
|
||||||
27: { type: Number, default: 0 },
|
},
|
||||||
28: { type: Number, default: 0 },
|
7: {
|
||||||
29: { type: Number, default: 0 },
|
type: Number,
|
||||||
30: { type: Number, default: 0 },
|
default: 0
|
||||||
31: { type: Number, default: 0 },
|
},
|
||||||
32: { type: Number, default: 0 },
|
8: {
|
||||||
33: { type: Number, default: 0 },
|
type: Number,
|
||||||
34: { type: Number, default: 0 },
|
default: 0
|
||||||
35: { type: Number, default: 0 },
|
},
|
||||||
36: { type: Number, default: 0 },
|
9: {
|
||||||
37: { type: Number, default: 0 },
|
type: Number,
|
||||||
38: { type: Number, default: 0 },
|
default: 0
|
||||||
39: { type: Number, default: 0 },
|
},
|
||||||
40: { type: Number, default: 0 },
|
10: {
|
||||||
41: { type: Number, default: 0 },
|
type: Number,
|
||||||
42: { type: Number, default: 0 },
|
default: 0
|
||||||
43: { type: Number, default: 0 },
|
},
|
||||||
44: { type: Number, default: 0 },
|
11: {
|
||||||
45: { type: Number, default: 0 },
|
type: Number,
|
||||||
46: { type: Number, default: 0 },
|
default: 0
|
||||||
47: { type: Number, default: 0 },
|
},
|
||||||
48: { type: Number, default: 0 },
|
12: {
|
||||||
49: { type: Number, default: 0 },
|
type: Number,
|
||||||
50: { type: Number, default: 0 },
|
default: 0
|
||||||
51: { type: Number, default: 0 },
|
},
|
||||||
52: { type: Number, default: 0 },
|
13: {
|
||||||
53: { type: Number, default: 0 },
|
type: Number,
|
||||||
54: { type: Number, default: 0 },
|
default: 0
|
||||||
55: { type: Number, default: 0 },
|
},
|
||||||
56: { type: Number, default: 0 },
|
14: {
|
||||||
57: { type: Number, default: 0 },
|
type: Number,
|
||||||
58: { type: Number, default: 0 },
|
default: 0
|
||||||
59: { type: Number, default: 0 }
|
},
|
||||||
|
15: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
16: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
17: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
18: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
19: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
20: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
21: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
22: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
23: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
24: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
25: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
26: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
27: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
28: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
29: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
30: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
31: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
32: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
33: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
34: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
35: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
36: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
37: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
38: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
39: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
40: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
41: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
42: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
43: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
44: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
45: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
46: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
47: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
48: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
49: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
50: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
51: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
52: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
53: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
54: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
55: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
56: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
57: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
58: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
59: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
},
|
},
|
||||||
profile: {
|
profile: {
|
||||||
name: { type: String, default: '' },
|
name: {
|
||||||
gender: { type: String, default: '' },
|
type: String, default: ''
|
||||||
location: { type: String, default: '' },
|
},
|
||||||
website: { type: String, default: '' },
|
gender: {
|
||||||
picture: { type: String, default: '' }
|
type: String, default: ''
|
||||||
//username: { type: String, default: '', unique: true, match: /^[a-zA-Z0-9_]+$/ }
|
},
|
||||||
|
location: {
|
||||||
|
type: String, default: ''
|
||||||
|
},
|
||||||
|
website: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
picture: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
/*username: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
unique: true,
|
||||||
|
match: /^[a-zA-Z0-9_]+$/
|
||||||
|
}*/
|
||||||
},
|
},
|
||||||
|
|
||||||
resetPasswordToken: String,
|
resetPasswordToken: String,
|
||||||
@ -133,7 +338,11 @@ userSchema.methods.gravatar = function(size) {
|
|||||||
return 'https://gravatar.com/avatar/?s=' + size + '&d=retro';
|
return 'https://gravatar.com/avatar/?s=' + size + '&d=retro';
|
||||||
}
|
}
|
||||||
|
|
||||||
var md5 = crypto.createHash('md5').update(this.email).digest('hex');
|
var md5 = crypto
|
||||||
|
.createHash('md5')
|
||||||
|
.update(this.email)
|
||||||
|
.digest('hex');
|
||||||
|
|
||||||
return 'https://gravatar.com/avatar/' + md5 + '?s=' + size + '&d=retro';
|
return 'https://gravatar.com/avatar/' + md5 + '?s=' + size + '&d=retro';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,40 +1,44 @@
|
|||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
var CSRF_HEADER = 'X-CSRF-Token';
|
var CSRF_HEADER = 'X-CSRF-Token';
|
||||||
|
|
||||||
var setCSRFToken = function(securityToken) {
|
var setCSRFToken = function(securityToken) {
|
||||||
jQuery.ajaxPrefilter(function(options, _, xhr) {
|
jQuery.ajaxPrefilter(function(options, _, xhr) {
|
||||||
if ( !xhr.crossDomain )
|
if (!xhr.crossDomain) {
|
||||||
xhr.setRequestHeader(CSRF_HEADER, securityToken);
|
xhr.setRequestHeader(CSRF_HEADER, securityToken);
|
||||||
});
|
}
|
||||||
};
|
|
||||||
|
|
||||||
setCSRFToken($('meta[name="csrf-token"]').attr('content'));
|
|
||||||
|
|
||||||
$('.start-challenge').on("click", function() {
|
|
||||||
$(this).parent().remove();
|
|
||||||
$('.challenge-content').removeClass('hidden-element').addClass('animated fadeInDown');
|
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$('.completed-challenge').on("click", function() {
|
setCSRFToken($('meta[name="csrf-token"]').attr('content'));
|
||||||
$('#complete-dialog').modal('show');
|
|
||||||
l = location.pathname.split('/');
|
|
||||||
cn = l[l.length - 1]
|
|
||||||
console.log(cn);
|
|
||||||
$.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
data: {challengeNumber: cn},
|
|
||||||
url: '/completed_challenge/'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.skip-challenge').on("click", function() {
|
$('.start-challenge').on('click', function() {
|
||||||
$('#skip-dialog').modal('show');
|
$(this).parent().remove();
|
||||||
});
|
$('.challenge-content')
|
||||||
|
.removeClass('hidden-element')
|
||||||
|
.addClass('animated fadeInDown');
|
||||||
|
});
|
||||||
|
|
||||||
$('.next-button').on("click", function() {
|
$('.completed-challenge').on('click', function() {
|
||||||
l = location.pathname.split('/');
|
$('#complete-dialog').modal('show');
|
||||||
window.location = "/challenges/" + (parseInt(l[l.length-1]) + 1)
|
|
||||||
});
|
l = location.pathname.split('/');
|
||||||
|
cn = l[l.length - 1];
|
||||||
|
console.log(cn);
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
data: {challengeNumber: cn},
|
||||||
|
url: '/completed_challenge/'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.skip-challenge').on('click', function() {
|
||||||
|
$('#skip-dialog').modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.next-button').on('click', function() {
|
||||||
|
l = location.pathname.split('/');
|
||||||
|
window.location = '/challenges/' + (parseInt(l[l.length - 1]) + 1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
var Challenge = require('../models/Challenge.js')
|
var Challenge = require('../models/Challenge.js'),
|
||||||
var mongoose = require('mongoose');
|
mongoose = require('mongoose'),
|
||||||
var secrets = require('../config/secrets');
|
secrets = require('../config/secrets'),
|
||||||
var challenges = require('./challenges.json');
|
challenges = require('./challenges.json');
|
||||||
|
|
||||||
mongoose.connect(secrets.db);
|
mongoose.connect(secrets.db);
|
||||||
Challenge.remove({}, function(err, data){
|
|
||||||
if (err) console.log(err);
|
Challenge.remove({}, function(err, data) {
|
||||||
else console.log('Deleted ', data );
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
} else {
|
||||||
|
console.log('Deleted ', data);
|
||||||
|
}
|
||||||
Challenge.create(challenges, function(err, data) {
|
Challenge.create(challenges, function(err, data) {
|
||||||
if (err) console.log(err);
|
if (err) {
|
||||||
else console.log('Saved ', data );
|
console.log(err);
|
||||||
|
} else {
|
||||||
|
console.log('Saved ', data);
|
||||||
|
}
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
215
setup.js
215
setup.js
@ -50,7 +50,8 @@ var footer = blessed.text({
|
|||||||
fg: 'white',
|
fg: 'white',
|
||||||
bg: 'blue',
|
bg: 'blue',
|
||||||
tags: true,
|
tags: true,
|
||||||
content: ' {cyan-fg}<Up/Down>{/cyan-fg} moves | {cyan-fg}<Enter>{/cyan-fg} selects | {cyan-fg}<q>{/cyan-fg} exits'
|
content: ' {cyan-fg}<Up/Down>{/cyan-fg} moves |' +
|
||||||
|
' {cyan-fg}<Enter>{/cyan-fg} selects | {cyan-fg}<q>{/cyan-fg} exits'
|
||||||
});
|
});
|
||||||
|
|
||||||
var inner = blessed.form({
|
var inner = blessed.form({
|
||||||
@ -97,7 +98,8 @@ var clusterText = blessed.text({
|
|||||||
bg: 'red',
|
bg: 'red',
|
||||||
fg: 'white',
|
fg: 'white',
|
||||||
tags: true,
|
tags: true,
|
||||||
content: 'Take advantage of multi-core systems using built-in {underline}cluster{/underline} module.'
|
content: 'Take advantage of multi-core systems' +
|
||||||
|
' using built-in {underline}cluster{/underline} module.'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -186,38 +188,54 @@ var authForm = blessed.form({
|
|||||||
});
|
});
|
||||||
|
|
||||||
authForm.on('submit', function() {
|
authForm.on('submit', function() {
|
||||||
var passportConfig = fs.readFileSync('config/passport.js').toString().split(os.EOL);
|
var passportConfig = fs.readFileSync('config/passport.js')
|
||||||
var loginTemplate = fs.readFileSync('views/account/login.jade').toString().split(os.EOL);
|
.toString().split(os.EOL);
|
||||||
var profileTemplate = fs.readFileSync('views/account/profile.jade').toString().split(os.EOL);
|
var loginTemplate = fs.readFileSync('views/account/login.jade')
|
||||||
|
.toString().split(os.EOL);
|
||||||
|
var profileTemplate = fs.readFileSync('views/account/profile.jade')
|
||||||
|
.toString().split(os.EOL);
|
||||||
var userModel = fs.readFileSync('models/User.js').toString().split(os.EOL);
|
var userModel = fs.readFileSync('models/User.js').toString().split(os.EOL);
|
||||||
var app = fs.readFileSync('app.js').toString().split(os.EOL);
|
var app = fs.readFileSync('app.js').toString().split(os.EOL);
|
||||||
var secrets = fs.readFileSync('config/secrets.js').toString().split(os.EOL);
|
var secrets = fs.readFileSync('config/secrets.js').toString().split(os.EOL);
|
||||||
|
|
||||||
var index = passportConfig.indexOf("var FacebookStrategy = require('passport-facebook').Strategy;");
|
var index = passportConfig
|
||||||
|
.indexOf('var FacebookStrategy = require("passport-facebook").Strategy;');
|
||||||
if (facebookCheckbox.checked && index !== -1) {
|
if (facebookCheckbox.checked && index !== -1) {
|
||||||
passportConfig.splice(index, 1);
|
passportConfig.splice(index, 1);
|
||||||
index = passportConfig.indexOf('// Sign in with Facebook.');
|
index = passportConfig.indexOf('// Sign in with Facebook.');
|
||||||
passportConfig.splice(index, 47);
|
passportConfig.splice(index, 47);
|
||||||
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
||||||
|
|
||||||
index = loginTemplate.indexOf(" a.btn.btn-block.btn-facebook.btn-social(href='/auth/facebook')");
|
index = loginTemplate.indexOf(
|
||||||
|
' a.btn.btn-block.btn-facebook.btn-social(href="/auth/facebook")'
|
||||||
|
);
|
||||||
loginTemplate.splice(index, 3);
|
loginTemplate.splice(index, 3);
|
||||||
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
||||||
|
|
||||||
index = profileTemplate.indexOf(" if user.facebook");
|
index = profileTemplate.indexOf(' if user.facebook');
|
||||||
profileTemplate.splice(index - 1, 5);
|
profileTemplate.splice(index - 1, 5);
|
||||||
fs.writeFileSync('views/account/profile.jade', profileTemplate.join(os.EOL));
|
fs.writeFileSync(
|
||||||
|
'views/account/profile.jade',
|
||||||
|
profileTemplate.join(os.EOL)
|
||||||
|
);
|
||||||
|
|
||||||
index = userModel.indexOf(' facebook: String,');
|
index = userModel.indexOf(' facebook: String,');
|
||||||
userModel.splice(index, 1);
|
userModel.splice(index, 1);
|
||||||
fs.writeFileSync('models/User.js', userModel.join(os.EOL));
|
fs.writeFileSync('models/User.js', userModel.join(os.EOL));
|
||||||
|
|
||||||
index = app.indexOf("app.get('/auth/facebook', passport.authenticate('facebook', { scope: ['email', 'user_location'] }));");
|
index = app.indexOf([
|
||||||
|
'app.get("/auth/facebook"',
|
||||||
|
'passport.authenticate("facebook",',
|
||||||
|
' { scope: ["email", "user_location"] }));'
|
||||||
|
].join(' '));
|
||||||
|
|
||||||
app.splice(index, 4);
|
app.splice(index, 4);
|
||||||
fs.writeFileSync('app.js', app.join(os.EOL));
|
fs.writeFileSync('app.js', app.join(os.EOL));
|
||||||
}
|
}
|
||||||
|
|
||||||
index = passportConfig.indexOf("var GitHubStrategy = require('passport-github').Strategy;");
|
index = passportConfig.indexOf(
|
||||||
|
"var GitHubStrategy = require('passport-github').Strategy;"
|
||||||
|
);
|
||||||
if (githubCheckbox.checked && index !== -1) {
|
if (githubCheckbox.checked && index !== -1) {
|
||||||
console.log(index);
|
console.log(index);
|
||||||
passportConfig.splice(index, 1);
|
passportConfig.splice(index, 1);
|
||||||
@ -225,111 +243,162 @@ authForm.on('submit', function() {
|
|||||||
passportConfig.splice(index, 48);
|
passportConfig.splice(index, 48);
|
||||||
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
||||||
|
|
||||||
index = loginTemplate.indexOf(" a.btn.btn-block.btn-github.btn-social(href='/auth/github')");
|
index = loginTemplate.indexOf(
|
||||||
|
" a.btn.btn-block.btn-github.btn-social(href='/auth/github')"
|
||||||
|
);
|
||||||
loginTemplate.splice(index, 3);
|
loginTemplate.splice(index, 3);
|
||||||
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
||||||
|
|
||||||
index = profileTemplate.indexOf(' if user.github');
|
index = profileTemplate.indexOf(' if user.github');
|
||||||
profileTemplate.splice(index - 1, 5);
|
profileTemplate.splice(index - 1, 5);
|
||||||
fs.writeFileSync('views/account/profile.jade', profileTemplate.join(os.EOL));
|
fs.writeFileSync(
|
||||||
|
'views/account/profile.jade',
|
||||||
|
profileTemplate.join(os.EOL)
|
||||||
|
);
|
||||||
|
|
||||||
index = userModel.indexOf(' github: String,');
|
index = userModel.indexOf(' github: String,');
|
||||||
userModel.splice(index, 1);
|
userModel.splice(index, 1);
|
||||||
fs.writeFileSync('models/User.js', userModel.join(os.EOL));
|
fs.writeFileSync('models/User.js', userModel.join(os.EOL));
|
||||||
|
|
||||||
index = app.indexOf("app.get('/auth/github', passport.authenticate('github'));");
|
index = app.indexOf(
|
||||||
|
'app.get("/auth/github", passport.authenticate("github"));'
|
||||||
|
);
|
||||||
app.splice(index, 4);
|
app.splice(index, 4);
|
||||||
fs.writeFileSync('app.js', app.join(os.EOL));
|
fs.writeFileSync('app.js', app.join(os.EOL));
|
||||||
}
|
}
|
||||||
|
|
||||||
index = passportConfig.indexOf("var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;");
|
index = passportConfig.indexOf(
|
||||||
|
'var GoogleStrategy = require("passport-google-oauth").OAuth2Strategy;'
|
||||||
|
);
|
||||||
if (googleCheckbox.checked && index !== -1) {
|
if (googleCheckbox.checked && index !== -1) {
|
||||||
passportConfig.splice(index, 1);
|
passportConfig.splice(index, 1);
|
||||||
index = passportConfig.indexOf('// Sign in with Google.');
|
index = passportConfig.indexOf('// Sign in with Google.');
|
||||||
passportConfig.splice(index, 46);
|
passportConfig.splice(index, 46);
|
||||||
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
||||||
|
|
||||||
index = loginTemplate.indexOf(" a.btn.btn-block.btn-google-plus.btn-social(href='/auth/google')");
|
index = loginTemplate.indexOf(
|
||||||
|
" a.btn.btn-block.btn-google-plus.btn-social(href='/auth/google')"
|
||||||
|
);
|
||||||
loginTemplate.splice(index, 3);
|
loginTemplate.splice(index, 3);
|
||||||
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
||||||
|
|
||||||
index = profileTemplate.indexOf(' if user.google');
|
index = profileTemplate.indexOf(' if user.google');
|
||||||
profileTemplate.splice(index - 1, 5);
|
profileTemplate.splice(index - 1, 5);
|
||||||
fs.writeFileSync('views/account/profile.jade', profileTemplate.join(os.EOL));
|
fs.writeFileSync(
|
||||||
|
'views/account/profile.jade',
|
||||||
|
profileTemplate.join(os.EOL)
|
||||||
|
);
|
||||||
|
|
||||||
index = userModel.indexOf(' google: String,');
|
index = userModel.indexOf(' google: String,');
|
||||||
userModel.splice(index, 1);
|
userModel.splice(index, 1);
|
||||||
fs.writeFileSync('models/User.js', userModel.join(os.EOL));
|
fs.writeFileSync('models/User.js', userModel.join(os.EOL));
|
||||||
|
|
||||||
index = app.indexOf("app.get('/auth/google', passport.authenticate('google', { scope: 'profile email' }));");
|
index = app.indexOf(
|
||||||
|
'app.get("/auth/google",' +
|
||||||
|
' passport.authenticate("google", { scope: "profile email" }));'
|
||||||
|
);
|
||||||
app.splice(index, 4);
|
app.splice(index, 4);
|
||||||
fs.writeFileSync('app.js', app.join(os.EOL));
|
fs.writeFileSync('app.js', app.join(os.EOL));
|
||||||
}
|
}
|
||||||
|
|
||||||
index = passportConfig.indexOf("var TwitterStrategy = require('passport-twitter').Strategy;");
|
index = passportConfig.indexOf(
|
||||||
|
'var TwitterStrategy = require("passport-twitter").Strategy;'
|
||||||
|
);
|
||||||
if (twitterCheckbox.checked && index !== -1) {
|
if (twitterCheckbox.checked && index !== -1) {
|
||||||
passportConfig.splice(index, 1);
|
passportConfig.splice(index, 1);
|
||||||
index = passportConfig.indexOf('// Sign in with Twitter.');
|
index = passportConfig.indexOf('// Sign in with Twitter.');
|
||||||
passportConfig.splice(index, 43);
|
passportConfig.splice(index, 43);
|
||||||
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
||||||
|
|
||||||
index = loginTemplate.indexOf(" a.btn.btn-block.btn-twitter.btn-social(href='/auth/twitter')");
|
index = loginTemplate.indexOf(
|
||||||
|
' a.btn.btn-block.btn-twitter.btn-social(href="/auth/twitter")'
|
||||||
|
);
|
||||||
loginTemplate.splice(index, 3);
|
loginTemplate.splice(index, 3);
|
||||||
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
||||||
|
|
||||||
index = profileTemplate.indexOf(' if user.twitter');
|
index = profileTemplate.indexOf(' if user.twitter');
|
||||||
profileTemplate.splice(index - 1, 5);
|
profileTemplate.splice(index - 1, 5);
|
||||||
fs.writeFileSync('views/account/profile.jade', profileTemplate.join(os.EOL));
|
fs.writeFileSync(
|
||||||
|
'views/account/profile.jade', profileTemplate.join(os.EOL)
|
||||||
|
);
|
||||||
|
|
||||||
index = userModel.indexOf(' twitter: String,');
|
index = userModel.indexOf(' twitter: String,');
|
||||||
userModel.splice(index, 1);
|
userModel.splice(index, 1);
|
||||||
fs.writeFileSync('models/User.js', userModel.join(os.EOL));
|
fs.writeFileSync('models/User.js', userModel.join(os.EOL));
|
||||||
|
|
||||||
index = app.indexOf("app.get('/auth/twitter', passport.authenticate('twitter'));");
|
index = app.indexOf(
|
||||||
|
"app.get('/auth/twitter', passport.authenticate('twitter'));"
|
||||||
|
);
|
||||||
app.splice(index, 4);
|
app.splice(index, 4);
|
||||||
fs.writeFileSync('app.js', app.join(os.EOL));
|
fs.writeFileSync('app.js', app.join(os.EOL));
|
||||||
}
|
}
|
||||||
|
|
||||||
index = passportConfig.indexOf("var LinkedInStrategy = require('passport-linkedin-oauth2').Strategy;");
|
index = passportConfig.indexOf(
|
||||||
|
'var LinkedInStrategy = require("passport-linkedin-oauth2").Strategy;'
|
||||||
|
);
|
||||||
if (linkedinCheckbox.checked && index !== -1) {
|
if (linkedinCheckbox.checked && index !== -1) {
|
||||||
passportConfig.splice(index, 1);
|
passportConfig.splice(index, 1);
|
||||||
index = passportConfig.indexOf('// Sign in with LinkedIn.');
|
index = passportConfig.indexOf('// Sign in with LinkedIn.');
|
||||||
passportConfig.splice(index, 47);
|
passportConfig.splice(index, 47);
|
||||||
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
||||||
|
|
||||||
index = loginTemplate.indexOf(" a.btn.btn-block.btn-linkedin.btn-social(href='/auth/linkedin')");
|
index = loginTemplate.indexOf(
|
||||||
|
' a.btn.btn-block.btn-linkedin.btn-social(href="/auth/linkedin")'
|
||||||
|
);
|
||||||
loginTemplate.splice(index, 3);
|
loginTemplate.splice(index, 3);
|
||||||
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
||||||
|
|
||||||
index = profileTemplate.indexOf(' if user.linkedin');
|
index = profileTemplate.indexOf(' if user.linkedin');
|
||||||
profileTemplate.splice(index - 1, 5);
|
profileTemplate.splice(index - 1, 5);
|
||||||
fs.writeFileSync('views/account/profile.jade', profileTemplate.join(os.EOL));
|
fs.writeFileSync(
|
||||||
|
'views/account/profile.jade',
|
||||||
|
profileTemplate.join(os.EOL)
|
||||||
|
);
|
||||||
|
|
||||||
index = userModel.indexOf(' linkedin: String,');
|
index = userModel.indexOf(' linkedin: String,');
|
||||||
userModel.splice(index, 1);
|
userModel.splice(index, 1);
|
||||||
fs.writeFileSync('models/User.js', userModel.join(os.EOL));
|
fs.writeFileSync('models/User.js', userModel.join(os.EOL));
|
||||||
|
|
||||||
index = app.indexOf("app.get('/auth/linkedin', passport.authenticate('linkedin', { state: 'SOME STATE' }));");
|
index = app.indexOf(
|
||||||
|
'app.get("/auth/linkedin",',
|
||||||
|
' passport.authenticate("linkedin", { state: "SOME STATE" }));'
|
||||||
|
);
|
||||||
app.splice(index, 4);
|
app.splice(index, 4);
|
||||||
fs.writeFileSync('app.js', app.join(os.EOL));
|
fs.writeFileSync('app.js', app.join(os.EOL));
|
||||||
}
|
}
|
||||||
|
|
||||||
index = passportConfig.indexOf("var InstagramStrategy = require('passport-instagram').Strategy;");
|
index = passportConfig.indexOf(
|
||||||
|
'var InstagramStrategy = require("passport-instagram").Strategy;'
|
||||||
|
);
|
||||||
if (instagramCheckbox.checked && index !== -1) {
|
if (instagramCheckbox.checked && index !== -1) {
|
||||||
passportConfig.splice(index, 1);
|
passportConfig.splice(index, 1);
|
||||||
index = passportConfig.indexOf('// Sign in with Instagram.');
|
index = passportConfig.indexOf('// Sign in with Instagram.');
|
||||||
passportConfig.splice(index, 43);
|
passportConfig.splice(index, 43);
|
||||||
fs.writeFileSync('config/passport.js', passportConfig.join(os.EOL));
|
fs.writeFileSync(
|
||||||
|
'config/passport.js',
|
||||||
|
passportConfig.join(os.EOL)
|
||||||
|
);
|
||||||
|
|
||||||
index = loginTemplate.indexOf(" a.btn.btn-block.btn-instagram.btn-social(href='/auth/instagram')");
|
index = loginTemplate.indexOf(
|
||||||
|
' a.btn.btn-block.btn-instagram.btn-social(href="/auth/instagram")'
|
||||||
|
);
|
||||||
loginTemplate.splice(index, 3);
|
loginTemplate.splice(index, 3);
|
||||||
fs.writeFileSync('views/account/login.jade', loginTemplate.join(os.EOL));
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
'views/account/login.jade',
|
||||||
|
loginTemplate.join(os.EOL)
|
||||||
|
);
|
||||||
|
|
||||||
index = profileTemplate.indexOf(' if user.instagram');
|
index = profileTemplate.indexOf(' if user.instagram');
|
||||||
profileTemplate.splice(index - 1, 5);
|
profileTemplate.splice(index - 1, 5);
|
||||||
fs.writeFileSync('views/account/profile.jade', profileTemplate.join(os.EOL));
|
fs.writeFileSync(
|
||||||
|
'views/account/profile.jade',
|
||||||
|
profileTemplate.join(os.EOL)
|
||||||
|
);
|
||||||
|
|
||||||
index = app.indexOf("app.get('/auth/instagram', passport.authenticate('instagram'));");
|
index = app.indexOf(
|
||||||
|
'app.get("/auth/instagram", passport.authenticate("instagram"));'
|
||||||
|
);
|
||||||
app.splice(index, 4);
|
app.splice(index, 4);
|
||||||
fs.writeFileSync('app.js', app.join(os.EOL));
|
fs.writeFileSync('app.js', app.join(os.EOL));
|
||||||
|
|
||||||
@ -339,14 +408,18 @@ authForm.on('submit', function() {
|
|||||||
|
|
||||||
home.remove(authForm);
|
home.remove(authForm);
|
||||||
home.append(success);
|
home.append(success);
|
||||||
success.setContent('Selected authentication providers have been removed from passportConfig.js, User.js, app.js, login.jade and profile.jade!');
|
success.setContent(
|
||||||
|
'Selected authentication providers have been removed' +
|
||||||
|
'from passportConfig.js, User.js, app.js, login.jade and profile.jade!'
|
||||||
|
);
|
||||||
success.focus();
|
success.focus();
|
||||||
screen.render();
|
screen.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
var authText = blessed.text({
|
var authText = blessed.text({
|
||||||
parent: authForm,
|
parent: authForm,
|
||||||
content: 'Selecting a checkbox removes an authentication provider. If authentication provider is already removed, no action will be taken.',
|
content: 'Selecting a checkbox removes an authentication provider.' +
|
||||||
|
' If authentication provider is already removed, no action will be taken.',
|
||||||
padding: 1,
|
padding: 1,
|
||||||
bg: 'magenta',
|
bg: 'magenta',
|
||||||
fg: 'white'
|
fg: 'white'
|
||||||
@ -460,8 +533,10 @@ var emailForm = blessed.form({
|
|||||||
});
|
});
|
||||||
|
|
||||||
emailForm.on('submit', function() {
|
emailForm.on('submit', function() {
|
||||||
var contactCtrl = fs.readFileSync('controllers/contact.js').toString().split(os.EOL);
|
var contactCtrl = fs.readFileSync('controllers/contact.js')
|
||||||
var userCtrl = fs.readFileSync('controllers/user.js').toString().split(os.EOL);
|
.toString().split(os.EOL);
|
||||||
|
var userCtrl = fs.readFileSync('controllers/user.js')
|
||||||
|
.toString().split(os.EOL);
|
||||||
var choice = null;
|
var choice = null;
|
||||||
|
|
||||||
if (sendgridRadio.checked) {
|
if (sendgridRadio.checked) {
|
||||||
@ -472,20 +547,57 @@ emailForm.on('submit', function() {
|
|||||||
choice = 'Mandrill';
|
choice = 'Mandrill';
|
||||||
}
|
}
|
||||||
|
|
||||||
var index = contactCtrl.indexOf('var transporter = nodemailer.createTransport({');
|
var index = contactCtrl.indexOf(
|
||||||
|
'var transporter = nodemailer.createTransport({'
|
||||||
|
);
|
||||||
contactCtrl.splice(index + 1, 1, " service: '" + choice + "',");
|
contactCtrl.splice(index + 1, 1, " service: '" + choice + "',");
|
||||||
contactCtrl.splice(index + 3, 1, ' user: secrets.' + choice.toLowerCase() +'.user,');
|
contactCtrl.splice(
|
||||||
contactCtrl.splice(index + 4, 1, ' pass: secrets.' + choice.toLowerCase() + '.password');
|
index + 3,
|
||||||
|
1,
|
||||||
|
' user: secrets.' + choice.toLowerCase() + '.user,'
|
||||||
|
);
|
||||||
|
contactCtrl.splice(
|
||||||
|
index + 4,
|
||||||
|
1,
|
||||||
|
' pass: secrets.' + choice.toLowerCase() + '.password'
|
||||||
|
);
|
||||||
fs.writeFileSync('controllers/contact.js', contactCtrl.join(os.EOL));
|
fs.writeFileSync('controllers/contact.js', contactCtrl.join(os.EOL));
|
||||||
|
|
||||||
index = userCtrl.indexOf(' var transporter = nodemailer.createTransport({');
|
index = userCtrl.indexOf(
|
||||||
|
' var transporter = nodemailer.createTransport({'
|
||||||
|
);
|
||||||
userCtrl.splice(index + 1, 1, " service: '" + choice + "',");
|
userCtrl.splice(index + 1, 1, " service: '" + choice + "',");
|
||||||
userCtrl.splice(index + 3, 1, ' user: secrets.' + choice.toLowerCase() + '.user,');
|
userCtrl.splice(
|
||||||
userCtrl.splice(index + 4, 1, ' pass: secrets.' + choice.toLowerCase() + '.password');
|
index + 3,
|
||||||
index = userCtrl.indexOf(' var transporter = nodemailer.createTransport({', (index + 1));
|
1,
|
||||||
userCtrl.splice(index + 1, 1, " service: '" + choice + "',");
|
' user: secrets.' + choice.toLowerCase() + '.user,'
|
||||||
userCtrl.splice(index + 3, 1, ' user: secrets.' + choice.toLowerCase() + '.user,');
|
);
|
||||||
userCtrl.splice(index + 4, 1, ' pass: secrets.' + choice.toLowerCase() + '.password');
|
userCtrl.splice(
|
||||||
|
index + 4,
|
||||||
|
1,
|
||||||
|
' pass: secrets.' + choice.toLowerCase() + '.password'
|
||||||
|
);
|
||||||
|
|
||||||
|
index = userCtrl.indexOf(
|
||||||
|
' var transporter = nodemailer.createTransport({',
|
||||||
|
(index + 1)
|
||||||
|
);
|
||||||
|
userCtrl.splice(
|
||||||
|
index + 1,
|
||||||
|
1,
|
||||||
|
' service: "' + choice + '",'
|
||||||
|
);
|
||||||
|
|
||||||
|
userCtrl.splice(
|
||||||
|
index + 3,
|
||||||
|
1,
|
||||||
|
' user: secrets.' + choice.toLowerCase() + '.user,'
|
||||||
|
);
|
||||||
|
userCtrl.splice(
|
||||||
|
index + 4,
|
||||||
|
1,
|
||||||
|
' pass: secrets.' + choice.toLowerCase() + '.password'
|
||||||
|
);
|
||||||
fs.writeFileSync('controllers/user.js', userCtrl.join(os.EOL));
|
fs.writeFileSync('controllers/user.js', userCtrl.join(os.EOL));
|
||||||
|
|
||||||
home.remove(emailForm);
|
home.remove(emailForm);
|
||||||
@ -497,7 +609,9 @@ emailForm.on('submit', function() {
|
|||||||
|
|
||||||
var emailText = blessed.text({
|
var emailText = blessed.text({
|
||||||
parent: emailForm,
|
parent: emailForm,
|
||||||
content: 'Select one of the following email service providers for {underline}contact form{/underline} and {underline}password reset{/underline}.',
|
content: 'Select one of the following email service providers ' +
|
||||||
|
'for {underline}contact form{/underline}' +
|
||||||
|
' and {underline}password reset{/underline}.',
|
||||||
padding: 1,
|
padding: 1,
|
||||||
bg: 'red',
|
bg: 'red',
|
||||||
fg: 'white',
|
fg: 'white',
|
||||||
@ -592,7 +706,12 @@ home.on('select', function(child, index) {
|
|||||||
case 2:
|
case 2:
|
||||||
addClusterSupport();
|
addClusterSupport();
|
||||||
home.append(success);
|
home.append(success);
|
||||||
success.setContent('New file {underline}cluster_app.js{/underline} has been created. Your app is now able to use more than 1 CPU by running {underline}node cluster_app.js{/underline}, which in turn spawns multiple instances of {underline}app.js{/underline}');
|
success.setContent([
|
||||||
|
'New file {underline}cluster_app.js{/underline} has been created.',
|
||||||
|
'Your app is now able to use more than 1 CPU by running',
|
||||||
|
'{underline}node cluster_app.js{/underline}, which in turn',
|
||||||
|
'spawns multiple instances of {underline}app.js{/underline}'
|
||||||
|
].join(' '));
|
||||||
success.focus();
|
success.focus();
|
||||||
screen.render();
|
screen.render();
|
||||||
break;
|
break;
|
||||||
|
@ -11,7 +11,7 @@ describe('User Model', function() {
|
|||||||
user.save(function(err) {
|
user.save(function(err) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
done();
|
done();
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not create a user with the unique email', function(done) {
|
it('should not create a user with the unique email', function(done) {
|
||||||
|
Reference in New Issue
Block a user