Merge branch 'staging' of github.com:FreeCodeCamp/freecodecamp into staging
This commit is contained in:
@@ -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) {
|
||||
|
60
server/boot/a-extendUserIdent.js
Normal file
60
server/boot/a-extendUserIdent.js
Normal 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);
|
||||
}
|
@@ -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) {
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
};
|
||||
|
@@ -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
46
server/utils/auth.js
Normal 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];
|
||||
}
|
@@ -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);
|
||||
};
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user