Skip to content

Commit

Permalink
Merge 5339211 into ab03bef
Browse files Browse the repository at this point in the history
  • Loading branch information
fantastic-genius committed Jul 5, 2019
2 parents ab03bef + 5339211 commit aa99cc0
Show file tree
Hide file tree
Showing 17 changed files with 360 additions and 50 deletions.
11 changes: 11 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ cache:
env:
global:
- NODE_ENV=test
- FACEBOOK_APP_ID=414345019166283
- FACEBOOK_SECRET=42c013c3adb4617c4d231ca11576fd21
- FACEBOOK_CALLBACk=http://localhost:5000/auth/facebook/callback
- TWITTER_KEY=zgwMUevHI3lQy8rHEbLnFZ0Xu
- TWITTER_SECRET=ZjILyBUlWQh6EjcNZdjuPOTiwGPOUHTBp2IJ4TaUrrQmqX4iGB
- TWITTER_CALLBACk=http://localhost:5000/auth/twitter/callback
- SESSION_SECRET=secret
- GOOGLE_CLIENT_ID=437904595396-ktobr2fr8tuhed3f8ojatg6d0f4h7ibp.apps.googleusercontent.com
- GOOGLE_CLIENT_SECRET=mGJz_ZmBNaf6b1gqi95sDVk3
- BASE_URL=http://localhost:5000
- GOOGLE_CALLBACK=auth/google/callback
before_script:
- psql -c 'create database haventest;' -U postgres
services:
Expand Down
6 changes: 5 additions & 1 deletion controllers/users/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,5 +142,9 @@ export default {
message: 'Bad request'
});
}
}
},

home: async (req, res) => res.status(200).send({
user: req.user
})
};
2 changes: 1 addition & 1 deletion db/migrations/20190627191529-create-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module.exports = {
},
password: {
type: Sequelize.STRING,
allowNull: false
allowNull: true
},
username: {
type: Sequelize.STRING,
Expand Down
10 changes: 10 additions & 0 deletions db/migrations/20190703160309-add_social_to_users_table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
up: (queryInterface, Sequelize) => queryInterface.addColumn('Users', 'social', {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false
}),
down: queryInterface => queryInterface
.removeColumn('Users', 'social')
.then(() => queryInterface.removeColumn('Users', 'social'))
};
32 changes: 17 additions & 15 deletions db/models/User.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import bcrypt from 'bcryptjs';
import { getToken, randomString, hashPassword } from '../../utils';
import { getToken, randomString } from '../../utils';
import { sendMail } from '../../utils/mailer';
import { activationMessage } from '../../utils/mailer/mails';

Expand All @@ -14,6 +14,7 @@ module.exports = (sequelize, DataTypes) => {
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
password: DataTypes.STRING,
social: DataTypes.BOOLEAN,
passwordResetToken: DataTypes.STRING,
passwordResetExpire: DataTypes.DATE,
emailVerificationToken: DataTypes.STRING,
Expand All @@ -24,25 +25,26 @@ module.exports = (sequelize, DataTypes) => {
},
{
hooks: {
beforeCreate: async user => {
user.password = await bcrypt.hash(user.password, 10);
user.emailVerificationToken = randomString();
beforeCreate: async (user) => {
user.password = !user.social ? await bcrypt.hash(user.password, 10) : null;
user.emailVerificationToken = !user.social ? randomString() : null;
},
afterCreate: async user => {
await sendMail({
email: user.email,
subject: 'Activate Account',
content: activationMessage(user.email, user.emailVerificationToken)
});
afterCreate: async (user) => {
if (!user.social) {
await sendMail({
email: user.email,
subject: 'Activate Account',
content: activationMessage(user.email, user.emailVerificationToken)
});
}
}
}
}
);
User.associate = models =>
User.hasMany(models.Article, {
foreignKey: 'userId',
cascade: true
});
User.associate = models => User.hasMany(models.Article, {
foreignKey: 'userId',
cascade: true
});

User.prototype.passwordsMatch = function match(password) {
return bcrypt.compare(password, this.password);
Expand Down
16 changes: 16 additions & 0 deletions env-sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
PORT=
DATABASE_URL=
TEST_DATABASE_URL=
NODE_ENV=
SECRET=
FACEBOOK_APP_ID=
FACEBOOK_SECRET=
FACEBOOK_CALLBACk=
TWITTER_KEY=
TWITTER_SECRET=
TWITTER_CALLBACk=
SESSION_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
BASE_URL=
GOOGLE_CALLBACK=
110 changes: 110 additions & 0 deletions middlewares/passport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import passport from 'passport';
import googleStrategy from 'passport-google-oauth';
import dotenv from 'dotenv';
import { Strategy as FacebookStrategy } from 'passport-facebook';
import { Strategy as TwitterStrategy } from 'passport-twitter';
import { createUserFromSocials } from '../utils';

dotenv.config();
const GoogleStrategy = googleStrategy.OAuth2Strategy;

passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: `${process.env.BASE_URL}/${process.env.GOOGLE_CALLBACK}`
},
async (accessToken, refreshToken, profile, done) => {
const firstName = profile.name.givenName;
const lastName = profile.name.familyName;
const username = profile.displayName.replace(/ /g, '_').toLowerCase();
const email = profile.emails[0].value;
const image = profile.photos[0].value;

const data = {
email,
firstName,
lastName,
username,
image
};

const result = await createUserFromSocials(data);

return done(null, result);
}
)
);

passport.use(
new FacebookStrategy(
{
clientID: process.env.FACEBOOK_APP_ID,
clientSecret: process.env.FACEBOOK_SECRET,
callbackURL: process.env.FACEBOOK_CALLBACk,
profileFields: ['id', 'displayName', 'photos', 'emails', 'name']
},
async (accessToken, refreshToken, profile, done) => {
const email = profile.emails[0].value;
const lastName = profile.name.familyName.toLocaleLowerCase();
const firstName = profile.name.givenName.toLocaleLowerCase();
const username = profile.displayName.replace(/ /g, '_').toLocaleLowerCase();
const image = profile.photos[0].value;

const data = {
email,
firstName,
lastName,
username,
image
};

const result = await createUserFromSocials(data);

return done(null, result);
}
)
);

passport.use(
new TwitterStrategy(
{
consumerKey: process.env.TWITTER_KEY,
consumerSecret: process.env.TWITTER_SECRET,
callbackURL: process.env.TWITTER_CALLBACk,
includeEmail: true
},
async (token, tokenSecret, profile, done) => {
const { username } = profile;
let { displayName } = profile;
const image = profile.photos[0].value;
const email = profile.emails[0].value.toLocaleLowerCase();
displayName = displayName.split(' ');
const firstName = displayName[0].toLocaleLowerCase();
const lastName = displayName[1].toLocaleLowerCase();

const data = {
email,
firstName,
lastName,
username,
image
};

const result = await createUserFromSocials(data);

return done(null, result);
}
)
);

passport.serializeUser((user, done) => {
done(null, user);
});

passport.deserializeUser((user, done) => {
done(null, user);
});

export default passport;
13 changes: 10 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,25 @@
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.0",
"consola": "^2.9.0",
"cookie-parser": "^1.4.4",
"dotenv": "^8.0.0",
"express": "^4.17.1",
"express-session": "^1.16.2",
"indicative": "^5.0.8",
"jsonwebtoken": "^8.5.1",
"nock": "^10.0.6",
"nodemailer": "^6.2.1",
"parse-database-url": "^0.3.0",
"passport": "^0.4.0",
"passport-facebook": "^3.0.0",
"passport-google-oauth": "^2.0.0",
"passport-twitter": "^1.0.4",
"pg": "^7.11.0",
"pg-hstore": "^2.3.3",
"sequelize": "^5.8.12",
"swagger-ui-express": "^4.0.6",
"parse-database-url": "^0.3.0",
"sinon": "^7.3.2",
"sequelize-slugify": "^0.7.0",
"sinon": "^7.3.2",
"swagger-ui-express": "^4.0.6",
"yamljs": "^0.3.0"
}
}
2 changes: 2 additions & 0 deletions routes/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import v1 from './v1';
import oauth from './oauth';

export default (app) => {
app.use('/api/v1', v1);
app.use('/auth', oauth);
};
36 changes: 36 additions & 0 deletions routes/oauth/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import express from 'express';
import passport from '../../middlewares/passport';

const router = express.Router();

// google login
router.get('/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
router.get(
'/google/callback',
passport.authenticate('google', {
failureRedirect: '/api/v1/error'
}),
(req, res) => res.redirect('/api/v1/users/home')
);

// facebook login
router.get('/facebook', passport.authenticate('facebook', { scope: 'email' }));
router.get(
'/facebook/callback',
passport.authenticate('facebook', {
failureRedirect: '/api/v1/error'
}),
(req, res) => res.redirect('/api/v1/users/home')
);

// twiiter login
router.get('/twitter', passport.authenticate('twitter', { scope: ['include_email=true'] }));
router.get(
'/twitter/callback',
passport.authenticate('twitter', {
failureRedirect: '/api/v1/error'
}),
(req, res) => res.redirect('/api/v1/users/home')
);

export default router;
3 changes: 3 additions & 0 deletions routes/v1/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ import auth from './users';
const router = express.Router();

router.use('/users', auth);
router.use('/error', (req, res) => res.status(500).send({
message: 'failed oauth'
}));

export default router;
1 change: 1 addition & 0 deletions routes/v1/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ router.post('/signout', Middleware.authenticate, Middleware.isblackListedToken,
router.post('/reset-password', Validation.resetPassword, User.resetPassword);
router.put('/change-password', Validation.changePassword, User.changePassword);
router.put('/activate/:token', User.activate);
router.get('/home', User.home);

export default router;
45 changes: 28 additions & 17 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import bodyParser from 'body-parser';
import swaggerUi from 'swagger-ui-express';
import YAML from 'yamljs';
import consola from 'consola';
import passport from 'passport';
import session from 'express-session';
import cookieParser from 'cookie-parser';
import Routes from '../routes';
import db from '../db/models';

Expand All @@ -12,29 +15,37 @@ const app = express();
dotenv.config();

const swaggerDocument = YAML.load(`${__dirname}/../swagger.yaml`);

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
Routes(app);
app.use(cookieParser(process.env.SESSION_SECRET));

app.get('/', (req, res) =>
res.status(200).json({
message: "welcome to Author's Haven"
})
);
app.use((req, res) =>
res.status(404).json({
status: 404,
error: `Route ${req.url} Not found`
app.use(
session({
resave: false,
saveUninitialized: false,
secret: process.env.SESSION_SECRET
})
);
app.use(passport.initialize());
app.use(passport.session());
Routes(app);

app.use((error, req, res) =>
res.status(500).json({
status: 500,
error
})
);
app.get('/', (req, res) => res.status(200).json({
message: "welcome to Author's Haven"
}));

app.use((req, res) => res.status(404).json({
status: 404,
error: `Route ${req.url} Not found`
}));

app.use((error, req, res) => res.status(500).json({
status: 500,
error
}));

const dbconnection = db.sequelize;
dbconnection
Expand All @@ -45,7 +56,7 @@ dbconnection
consola.success(`server start at port ${process.env.PORT}`);
});
})
.catch(e => {
.catch((e) => {
throw e.message;
});

Expand Down
Loading

0 comments on commit aa99cc0

Please sign in to comment.