Skip to content

Commit

Permalink
Merge pull request #29 from andela/ft-soial-auth-#167727629
Browse files Browse the repository at this point in the history
feature(social Oauth):add social media login route
  • Loading branch information
Daymorelah committed Sep 5, 2019
2 parents 91152a5 + f59c47c commit d6a0ceb
Show file tree
Hide file tree
Showing 18 changed files with 714 additions and 100 deletions.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
"mongoose": "^5.2.2",
"morgan": "^1.9.1",
"passport": "^0.4.0",
"passport-facebook": "^3.0.0",
"passport-google-oauth20": "^2.0.0",
"passport-local": "^1.0.0",
"passport-mocked": "^1.4.0",
"pg": "^7.12.1",
"pg-hstore": "^2.3.3",
"random-string": "^0.2.0",
Expand Down Expand Up @@ -65,4 +68,4 @@
"nyc": "^14.1.1",
"sinon": "^7.4.1"
}
}
}
59 changes: 59 additions & 0 deletions src/config/passport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import passport from 'passport';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
import dotenv from 'dotenv';

dotenv.config();

const FacebookStrategy = require('passport-facebook').Strategy;

const {
GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET,
FACEBOOK_CLIENT_ID,
FACEBOOK_CLIENT_SECRET,
FACEBOOK_AUTH_CALLBACK_URL,
GOOGLE_AUTH_CALLBACK_URL,
} = process.env;

/**
* creates a user token
* @param {string} accessToken - contains id, role email
* @param {string} requestToken -
* @param {string} profile - user profile
* @param {string} done - user profile
* @return {object} - user profile
*/
export const passportCb = (accessToken, requestToken, profile, done) => done(
null, profile
);

const setupPassport = () => {
passport.use(
new GoogleStrategy({
callbackURL: GOOGLE_AUTH_CALLBACK_URL,
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET
}, passportCb)
);
passport.use(
new FacebookStrategy({
callbackURL: FACEBOOK_AUTH_CALLBACK_URL,
clientID: FACEBOOK_CLIENT_ID,
clientSecret: FACEBOOK_CLIENT_SECRET,
profileFields: [
'id', 'email', 'gender', 'link', 'locale',
'name', 'timezone', 'updated_time', 'verified'
],
}, passportCb)
);
};

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

passport.deserializeUser((obj, cb) => {
cb(null, obj);
});

export default setupPassport;
160 changes: 102 additions & 58 deletions src/controllers/UserController.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import models from '../models';
import { Authentication, SendEmail, HelperMethods } from '../utils';
import {
Authentication,
SendEmail,
HelperMethods
} from '../utils';

const { User } = models;
const {
User
} = models;

/**
* Class representing the user controller
Expand All @@ -26,25 +32,32 @@ class UserController {
}

/**
* Login a user
* Route: POST: /auth/login
* @param {object} req - HTTP Request object
* @param {object} res - HTTP Response object
* @return {res} res - HTTP Response object
* @memberof UserController
*/
* Login a user
* Route: POST: /auth/login
* @param {object} req - HTTP Request object
* @param {object} res - HTTP Response object
* @return {res} res - HTTP Response object
* @memberof UserController
*/
static async login(req, res) {
try {
const { email, password } = req.body;
const userFound = await User.findOne({ where: { email } });
const {
email,
password
} = req.body;
const userFound = await User.findOne({
where: {
email
}
});
if (!userFound) {
return HelperMethods.clientError(res, 'Email or password does not exist', 400);
}
if (!userFound.dataValues.isVerified) {
return HelperMethods.clientError(res, {
success: false,
message: 'You had started the registration process already. '
+ 'Please check your email to complete your registration.'
+ 'Please check your email to complete your registration.'
}, 400);
}
const isPasswordValid = await userFound.verifyPassword(password);
Expand Down Expand Up @@ -77,19 +90,27 @@ class UserController {
}

/**
* Sign up a user
* Route: POST: /auth/signup
* @param {object} req - HTTP Request object
* @param {object} res - HTTP Response object
* @return {res} res - HTTP Response object
* @memberof UserController
*/
* Sign up a user
* Route: POST: /auth/signup
* @param {object} req - HTTP Request object
* @param {object} res - HTTP Response object
* @return {res} res - HTTP Response object
* @memberof UserController
*/
static async signUp(req, res) {
const {
email, firstName, lastName, password, username,
email,
firstName,
lastName,
password,
username,
} = req.body;
try {
const userExist = await User.findOne({ where: { email } });
const userExist = await User.findOne({
where: {
email
}
});
if (userExist && userExist.dataValues.id) {
if (userExist.dataValues.isVerified === false) {
const isEmailSent = await
Expand All @@ -98,20 +119,20 @@ class UserController {
return HelperMethods
.requestSuccessful(res, {
message: 'You had started the registration '
+ 'process earlier. '
+ 'An email has been sent to your email address. '
+ 'Please check your email to complete your registration.'
+ 'process earlier. '
+ 'An email has been sent to your email address. '
+ 'Please check your email to complete your registration.'
}, 200);
}
return HelperMethods
.serverError(res, 'Your registration could not be completed.'
+ ' Please try again');
+ ' Please try again');
}
if (userExist.dataValues.isVerified === true) {
return HelperMethods
.requestSuccessful(res, {
message: 'You are a registered user on '
+ 'this platform. Please proceed to login'
+ 'this platform. Please proceed to login'
}, 200);
}
}
Expand All @@ -130,13 +151,13 @@ class UserController {
.requestSuccessful(res, {
success: true,
message: 'An email has been sent to your '
+ 'email address. Please check your email to complete '
+ 'your registration'
+ 'email address. Please check your email to complete '
+ 'your registration'
}, 200);
}
return HelperMethods
.serverError(res, 'Your registration could not be completed.'
+ 'Please try again');
+ 'Please try again');
}
} catch (error) {
if (error.errors) return HelperMethods.sequelizeValidationError(res, error);
Expand All @@ -162,7 +183,10 @@ class UserController {
res, 'You cannot perform this action. You are not a verified user.', 400
);
}
await userExist.update(req.body, { returning: true, hooks: false });
await userExist.update(req.body, {
returning: true,
hooks: false
});
return HelperMethods
.requestSuccessful(res, {
success: true,
Expand All @@ -188,7 +212,9 @@ class UserController {
static async getProfile(req, res) {
try {
const user = await User.findByPk(req.decoded.id, {
attributes: { exclude: ['password', 'isVerified'] }
attributes: {
exclude: ['password', 'isVerified']
}
});
if (user) {
return HelperMethods.requestSuccessful(res, {
Expand All @@ -204,20 +230,22 @@ class UserController {
}

/**
* Verify a user's email
* Route: POST: /auth/verify_email
* @param {object} req - HTTP Request object
* @param {object} res - HTTP Response object
* @return {res} res - HTTP Response object
* @memberof UserController
*/
* Verify a user's email
* Route: POST: /auth/verify_email
* @param {object} req - HTTP Request object
* @param {object} res - HTTP Response object
* @return {res} res - HTTP Response object
* @memberof UserController
*/
static async verifyEmail(req, res) {
try {
const foundUser = await User.findByPk(req.decoded.id);
if (foundUser.dataValues.id) {
const userUpdated = await foundUser.update({
isVerified: true || foundUser.isVerified,
}, { hooks: false });
}, {
hooks: false
});
if (userUpdated.dataValues.id) {
const isEmailSent = await
SendEmail.confirmRegistrationComplete(userUpdated.dataValues.email);
Expand All @@ -235,37 +263,46 @@ class UserController {
}
return HelperMethods
.serverError(res, 'Could not complete your registration. '
+ 'Please re-register.');
+ 'Please re-register.');
} catch (error) {
return HelperMethods.serverError(res);
}
}

/**
* Verify a user's email
* Route: POST: /update_user
* @param {object} req - HTTP Request object
* @param {object} res - HTTP Response object
* @return {res} res - HTTP Response object
* @memberof UserController
*/
* Verify a user's email
* Route: POST: /update_user
* @param {object} req - HTTP Request object
* @param {object} res - HTTP Response object
* @return {res} res - HTTP Response object
* @memberof UserController
*/
static async updateUserRole(req, res) {
const payload = req.decoded;
const { role, email } = req.body;
const {
role,
email
} = req.body;
try {
if (payload.role !== 'Super Administrator') {
return HelperMethods.clientError(res, 'Only a super admin'
+ ' can update user role', 401);
+ ' can update user role', 401);
}
const userToUpdate = await models.User.findOne({ where: { email } });
const userToUpdate = await models.User.findOne({
where: {
email
}
});
if (!userToUpdate) {
return HelperMethods.clientError(res,
'User not found', 404);
}
if (userToUpdate.role === role) {
return HelperMethods.clientError(res, `user is already a ${role}`, 409);
}
await userToUpdate.update({ role });
await userToUpdate.update({
role
});
return HelperMethods
.requestSuccessful(res, {
success: true,
Expand All @@ -286,12 +323,20 @@ class UserController {
*/
static async rememberUserDetails(req, res) {
try {
const { id } = req.decoded;
const { rememberDetails } = req.body;
const [, [update]] = await User.update(
{ rememberDetails },
{ where: { id }, returning: true }
);
const {
id
} = req.decoded;
const {
rememberDetails
} = req.body;
const [, [update]] = await User.update({
rememberDetails
}, {
where: {
id
},
returning: true
});

if (!update) {
return HelperMethods.clientError(
Expand All @@ -316,4 +361,3 @@ class UserController {
}
}
export default UserController;

Loading

0 comments on commit d6a0ceb

Please sign in to comment.