Search for existing user account using Github emails (#337)
* Tries to match user account from list of emails in Github API Requests the 'user:email' scope from Github which returns the private emails associated with the user's account. * Centres GitHub button in layout
This commit is contained in:
parent
4f531c14f4
commit
7be45ce875
4 changed files with 42 additions and 9 deletions
|
@ -7,6 +7,7 @@ import axios from 'axios';
|
||||||
import { updateSettings } from '../actions';
|
import { updateSettings } from '../actions';
|
||||||
import AccountForm from '../components/AccountForm';
|
import AccountForm from '../components/AccountForm';
|
||||||
import { validateSettings } from '../../../utils/reduxFormUtils';
|
import { validateSettings } from '../../../utils/reduxFormUtils';
|
||||||
|
import GithubButton from '../components/GithubButton';
|
||||||
|
|
||||||
const exitUrl = require('../../../images/exit.svg');
|
const exitUrl = require('../../../images/exit.svg');
|
||||||
const logoUrl = require('../../../images/p5js-logo.svg');
|
const logoUrl = require('../../../images/p5js-logo.svg');
|
||||||
|
@ -41,8 +42,8 @@ class AccountView extends React.Component {
|
||||||
<div className="form-container__content">
|
<div className="form-container__content">
|
||||||
<h2 className="form-container__title">My Account</h2>
|
<h2 className="form-container__title">My Account</h2>
|
||||||
<AccountForm {...this.props} />
|
<AccountForm {...this.props} />
|
||||||
{/* <h2 className="form-container__divider">Or</h2>
|
<h2 className="form-container__divider">Or</h2>
|
||||||
<GithubButton buttonText="Login with Github" /> */}
|
<GithubButton buttonText="Login with Github" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,7 +5,8 @@ import InlineSVG from 'react-inlinesvg';
|
||||||
import { validateAndLoginUser } from '../actions';
|
import { validateAndLoginUser } from '../actions';
|
||||||
import LoginForm from '../components/LoginForm';
|
import LoginForm from '../components/LoginForm';
|
||||||
import { validateLogin } from '../../../utils/reduxFormUtils';
|
import { validateLogin } from '../../../utils/reduxFormUtils';
|
||||||
// import GithubButton from '../components/GithubButton';
|
import GithubButton from '../components/GithubButton';
|
||||||
|
|
||||||
const exitUrl = require('../../../images/exit.svg');
|
const exitUrl = require('../../../images/exit.svg');
|
||||||
const logoUrl = require('../../../images/p5js-logo.svg');
|
const logoUrl = require('../../../images/p5js-logo.svg');
|
||||||
|
|
||||||
|
@ -39,8 +40,8 @@ class LoginView extends React.Component {
|
||||||
<div className="form-container__content">
|
<div className="form-container__content">
|
||||||
<h2 className="form-container__title">Log In</h2>
|
<h2 className="form-container__title">Log In</h2>
|
||||||
<LoginForm {...this.props} />
|
<LoginForm {...this.props} />
|
||||||
{/* <h2 className="form-container__divider">Or</h2>
|
<h2 className="form-container__divider">Or</h2>
|
||||||
<GithubButton buttonText="Login with Github" /> */}
|
<GithubButton buttonText="Login with Github" />
|
||||||
<p className="form__navigation-options">
|
<p className="form__navigation-options">
|
||||||
Don't have an account?
|
Don't have an account?
|
||||||
<Link className="form__signup-button" to="/signup">Sign Up</Link>
|
<Link className="form__signup-button" to="/signup">Sign Up</Link>
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-container__title {
|
.form-container__title {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import User from '../models/user';
|
import User from '../models/user';
|
||||||
|
|
||||||
|
const lodash = require('lodash');
|
||||||
const passport = require('passport');
|
const passport = require('passport');
|
||||||
const GitHubStrategy = require('passport-github').Strategy;
|
const GitHubStrategy = require('passport-github').Strategy;
|
||||||
const LocalStrategy = require('passport-local').Strategy;
|
const LocalStrategy = require('passport-local').Strategy;
|
||||||
|
@ -33,6 +34,28 @@ passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, don
|
||||||
.catch(err => done(null, false, { msg: err }));
|
.catch(err => done(null, false, { msg: err }));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Input:
|
||||||
|
[
|
||||||
|
{ value: 'email@example.com', primary: false, verified: true },
|
||||||
|
{ value: 'unverified@example.com', primary: false, verified: false }
|
||||||
|
]
|
||||||
|
|
||||||
|
Output:
|
||||||
|
['email@example.com']
|
||||||
|
*/
|
||||||
|
const getVerifiedEmails = githubEmails => (
|
||||||
|
(githubEmails || [])
|
||||||
|
.filter(item => item.verified === true)
|
||||||
|
.map(item => item.value)
|
||||||
|
);
|
||||||
|
|
||||||
|
const getPrimaryEmail = githubEmails => (
|
||||||
|
(
|
||||||
|
lodash.find(githubEmails, { primary: true }) || {}
|
||||||
|
).value
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign in with GitHub.
|
* Sign in with GitHub.
|
||||||
*/
|
*/
|
||||||
|
@ -40,16 +63,23 @@ passport.use(new GitHubStrategy({
|
||||||
clientID: process.env.GITHUB_ID,
|
clientID: process.env.GITHUB_ID,
|
||||||
clientSecret: process.env.GITHUB_SECRET,
|
clientSecret: process.env.GITHUB_SECRET,
|
||||||
callbackURL: '/auth/github/callback',
|
callbackURL: '/auth/github/callback',
|
||||||
passReqToCallback: true
|
passReqToCallback: true,
|
||||||
|
scope: ['user:email'],
|
||||||
}, (req, accessToken, refreshToken, profile, done) => {
|
}, (req, accessToken, refreshToken, profile, done) => {
|
||||||
User.findOne({ github: profile.id }, (findByGithubErr, existingUser) => {
|
User.findOne({ github: profile.id }, (findByGithubErr, existingUser) => {
|
||||||
if (existingUser) {
|
if (existingUser) {
|
||||||
done(null, existingUser);
|
done(null, existingUser);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
User.findOne({ email: profile._json.email }, (findByEmailErr, existingEmailUser) => {
|
|
||||||
|
const emails = getVerifiedEmails(profile.emails);
|
||||||
|
const primaryEmail = getPrimaryEmail(profile.emails);
|
||||||
|
|
||||||
|
User.findOne({
|
||||||
|
email: { $in: emails },
|
||||||
|
}, (findByEmailErr, existingEmailUser) => {
|
||||||
if (existingEmailUser) {
|
if (existingEmailUser) {
|
||||||
existingEmailUser.email = existingEmailUser.email || profile._json.email;
|
existingEmailUser.email = existingEmailUser.email || primaryEmail;
|
||||||
existingEmailUser.github = profile.id;
|
existingEmailUser.github = profile.id;
|
||||||
existingEmailUser.username = existingEmailUser.username || profile.username;
|
existingEmailUser.username = existingEmailUser.username || profile.username;
|
||||||
existingEmailUser.tokens.push({ kind: 'github', accessToken });
|
existingEmailUser.tokens.push({ kind: 'github', accessToken });
|
||||||
|
@ -57,7 +87,7 @@ passport.use(new GitHubStrategy({
|
||||||
existingEmailUser.save(saveErr => done(null, existingEmailUser));
|
existingEmailUser.save(saveErr => done(null, existingEmailUser));
|
||||||
} else {
|
} else {
|
||||||
const user = new User();
|
const user = new User();
|
||||||
user.email = profile._json.email;
|
user.email = primaryEmail;
|
||||||
user.github = profile.id;
|
user.github = profile.id;
|
||||||
user.username = profile.username;
|
user.username = profile.username;
|
||||||
user.tokens.push({ kind: 'github', accessToken });
|
user.tokens.push({ kind: 'github', accessToken });
|
||||||
|
|
Loading…
Reference in a new issue