Merge branch 'staging' of github.com:FreeCodeCamp/freecodecamp into staging

This commit is contained in:
Quincy Larson
2015-08-12 21:25:11 -07:00
249 changed files with 318 additions and 42024 deletions

View File

@@ -1,8 +1,10 @@
var Rx = require('rx');
var debug = require('debug')('freecc:user:remote');
import { Observable } from 'rx';
import debugFactory from 'debug';
const debug = debugFactory('freecc:user:remote');
function destroyAllRelated(id, Model) {
return Rx.Observable.fromNodeCallback(
return Observable.fromNodeCallback(
Model.destroyAll,
Model
)({ userId: id });
@@ -19,7 +21,7 @@ module.exports = function(app) {
if (!id) {
return next();
}
Rx.Observable.combineLatest(
Observable.combineLatest(
destroyAllRelated(id, UserIdentity),
destroyAllRelated(id, UserCredential),
function(identData, credData) {

View File

@@ -0,0 +1,60 @@
import { observeMethod, observeQuery } from '../utils/rx';
import { getSocialProvider } from '../utils/auth';
export default function({ models }) {
const { User, UserIdentity, UserCredential } = models;
const findUserById = observeMethod(User, 'findById');
const findIdent = observeMethod(UserIdentity, 'findOne');
UserIdentity.link = function(
userId,
provider,
authScheme,
profile,
credentials,
options = {},
cb
) {
if (typeof options === 'function' && !cb) {
cb = options;
options = {};
}
const user$ = findUserById(userId);
console.log('provider', provider);
console.log('id', profile.id);
findIdent({
provider: getSocialProvider(provider),
externalId: profile.id
})
.flatMap(identity => {
const modified = new Date();
if (!identity || identity.externalId !== profile.id) {
return observeQuery(UserIdentity, 'create', {
provider: getSocialProvider(provider),
externalId: profile.id,
authScheme,
profile,
credentials,
userId,
created: modified,
modified
});
}
identity.credentials = credentials;
return observeQuery(identity, 'updateAttributes', {
profile: getSocialProvider(provider),
credentials,
modified
});
})
.withLatestFrom(user$, (identity, user) => ({ identity, user }))
.subscribe(
({ identity, user }) => {
cb(null, user, identity);
},
cb
);
};
UserCredential.link = UserIdentity.link.bind(UserIdentity);
}

View File

@@ -11,9 +11,9 @@ const debug = debugFactory('freecc:react-server');
// add routes here as they slowly get reactified
// remove their individual controllers
const routes = [
'/hikes',
'/hikes/*',
'/jobs'
// '/hikes',
// '/hikes/*',
// '/jobs'
];
export default function reactSubRouter(app) {

View File

@@ -77,7 +77,11 @@ module.exports = function(app) {
name: blockArray[0].block,
dashedName: dasherize(blockArray[0].block),
challenges: blockArray
}));
}))
.filter(({ name })=> {
return name !== 'Hikes';
})
.shareReplay();
const User = app.models.User;
const userCount$ = observeMethod(User, 'count');
@@ -135,6 +139,7 @@ module.exports = function(app) {
const challengeId = req.user.currentChallenge.challengeId;
// find challenge
return challenge$
.filter(({ block }) => block !== 'Hikes')
.filter(({ id }) => id === challengeId)
// now lets find the block it belongs to
.flatMap(challenge => {
@@ -537,6 +542,7 @@ module.exports = function(app) {
completed: completedCount / blockArray.length * 100
};
})
.filter(({ name }) => name !== 'Hikes')
// turn stream of blocks into a stream of an array
.toArray();

View File

@@ -92,6 +92,7 @@ module.exports = {
failureRedirect: failureRedirect,
consumerKey: process.env.TWITTER_KEY,
consumerSecret: process.env.TWITTER_SECRET,
link: true,
failureFlash: true
},
'linkedin-login': {
@@ -126,6 +127,7 @@ module.exports = {
authOptions: {
state: process.env.LINKEDIN_STATE
},
link: true,
failureFlash: true
},
'github-login': {
@@ -154,6 +156,7 @@ module.exports = {
clientID: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
scope: ['email'],
link: true,
failureFlash: true
}
};

View File

@@ -10,11 +10,11 @@ var uuid = require('node-uuid'),
path = require('path'),
passportProviders = require('./passport-providers');
var setProfileFromGithub = require('./utils/auth').setProfileFromGithub;
var getSocialProvider = require('./utils/auth').getSocialProvider;
var generateKey =
require('loopback-component-passport/lib/models/utils').generateKey;
/**
* Create Express server.
*/
var app = loopback();
expressState.extend(app);
@@ -44,41 +44,6 @@ passportConfigurator.setupModels({
userCredentialModel: app.models.userCredential
});
// using es6 argument destructing
function setProfileFromGithub(
user,
{
profileUrl: githubURL,
username
},
{
id: githubId,
'avatar_url': picture,
email: githubEmail,
'created_at': joinedGithubOn,
blog: website,
location,
name
}
) {
return assign(
user,
{ isGithubCool: true, isMigrationGrandfathered: false },
{
name,
username: username.toLowerCase(),
location,
joinedGithubOn,
website,
picture,
githubId,
githubURL,
githubEmail,
githubProfile: githubURL
}
);
}
var passportOptions = {
emailOptional: true,
profileToUser: function(provider, profile) {
@@ -102,6 +67,10 @@ var passportOptions = {
userObj.email = email;
}
if (!(/github/).test(provider)) {
userObj[getSocialProvider(provider)] = profile.username;
}
if (/github/.test(provider)) {
setProfileFromGithub(userObj, profile, profile._json);
}

46
server/utils/auth.js Normal file
View File

@@ -0,0 +1,46 @@
import assign from 'object.assign';
// using es6 argument destructing
export function setProfileFromGithub(
user,
{
profileUrl: githubURL,
username
},
{
id: githubId,
'avatar_url': picture,
email: githubEmail,
'created_at': joinedGithubOn,
blog: website,
location,
name
}
) {
return assign(
user,
{ isGithubCool: true, isMigrationGrandfathered: false },
{
name,
username: username.toLowerCase(),
location,
joinedGithubOn,
website,
picture,
githubId,
githubURL,
githubEmail,
githubProfile: githubURL
}
);
}
export function getFirstImageFromProfile(profile) {
return profile && profile.photos && profile.photos[0] ?
profile.photos[0].value :
null;
}
export function getSocialProvider(provider) {
return provider.split('-')[0];
}

View File

@@ -22,7 +22,7 @@ exports.saveInstance = function saveInstance(instance) {
// alias saveInstance
exports.saveUser = exports.saveInstance;
exports.observableQueryFromModel =
exports.observeQuery = exports.observableQueryFromModel =
function observableQueryFromModel(Model, method, query) {
return Rx.Observable.fromNodeCallback(Model[method], Model)(query);
};

View File

@@ -8,7 +8,7 @@ block content
.row
.col-xs-12
if (!user.isGithubCool)
a.btn.btn-lg.btn-block.btn-github.btn-link-social(href='/auth/github')
a.btn.btn-lg.btn-block.btn-github.btn-link-social(href='/link/github')
i.fa.fa-github
| Link my GitHub to unlock this profile
else