Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bac 17 unit test login endpoint #45

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .env.example

This file was deleted.

10 changes: 10 additions & 0 deletions .env.example.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
PORT=8000
MONGODB_URI="mongodb://localhost:27017/events"
JWT_EXPIRES_IN="90d"
JWT_SECRET="ejgesgfyjehfvsyukaffrg"
NODE_ENV=development
GOOGLE_CLIENT_ID="enter client id here"
GOOGLE_CLIENT_SECRET="enter client secret here"
SERVER_ROOT_URI='http://localhost:8000/api/v1/auth/google'
UI_ROOT_URI='http://localhost:8000/auth/google'
COOKIE_NAME='auth_token'
16,057 changes: 16,057 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"main": "index.js",
"scripts": {
"lint:fix": "eslint --fix .",
"test": "jest --watchAll --detectOpenHandles --runInBand",
"test": "jest --watchAll --detectOpenHandles --runInBand" ,
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"populate": "node src/utilities/populateDB.js",
Expand All @@ -26,6 +26,7 @@
"homepage": "https://github.com/workshopapps/dinnerwithfriends.api#readme",
"dependencies": {
"@imranbarbhuiya/mongoose-fuzzy-searching": "^3.0.5",
"axios": "^1.1.3",
"bcrypt": "^5.0.1",
"cors": "^2.8.5",
"dotenv": "^16.0.0",
Expand Down
122 changes: 113 additions & 9 deletions src/controllers/auth.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
const {User} = require("./../models");
const {createUserSchema} = require("../validators")
const asyncHandler = require("express-async-handler")
const services = require("../services")
const {User, googleUser} = require("./../models");
const bcrypt = require("bcrypt");
const {createUserSchema, userSchema} = require("../validators");
const asyncHandler = require("express-async-handler");
const services = require("../services");
const queryString = require('node:querystring');
const axios = require('axios');

// Signup Controller
const signup = asyncHandler(async (req, res, next) => {
const { name, email, password } = req.body;

const validateUserInput = createUserSchema.validate({ name, email, password });

if (validateUserInput.error) {
let message = '';
if (validateUserInput.error.details[0].path[0] === 'name') message = 'Name has to start with a letter, can contain spaces, must be at least 3 characters, and no more than 30 characters. No special characters allowed';
Expand All @@ -34,10 +35,113 @@ const signup = asyncHandler(async (req, res, next) => {
return services.createSendToken(user, 'success', message, res);
});


// Signin Controller
const signin = asyncHandler( async( req, res, next) => {
const {email, password} = req.body
const validateUserInput = userSchema.validate({ email, password });
if (validateUserInput.error) {
let message = '';
if (validateUserInput.error.details[0].path[0] === 'email') message = 'Email has to start with a letter, can contain numbers and underscores, must be at least 3 characters, must have @com or @net. No spaces and no other special characters allowed';
if (validateUserInput.error.details[0].path[0] === 'password') message = 'Password has to start with a letter, can contain numbers, must be at least 8 characters, and no more than 30 characters. No spaces and special characters allowed';
return services.createSendToken({}, 'error', message, res);
}
const userExists = await User.findOne({ email });
if (!userExists) {
const message = 'Email or password incorrect';
return services.createSendToken({}, 'error', message, res);
}
const result = await bcrypt.compare( password, userExists.password);
if(!result){
const message = 'Email or password incorrect';
return services.createSendToken({}, 'error', message, res);
}
const message = 'Signed in successfully';
return services.createSendToken(userExists, 'success', message, res);
});

module.exports = {
signup
// Get Google login URL
const getGAuthURL = asyncHandler( async( req, res, next) => {
function getGoogleAuthURL() {
const rootURL = 'https://accounts.google.com/o/oauth2/auth'
const options = {
redirect_uri:`${process.env.SERVER_ROOT_URI}`,
client_id: `${process.env.GOOGLE_CLIENT_ID}`,
access_type: 'offline',
response_type: 'code',
prompt: 'consent',
scope: [
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email'
]
.join(' ')
}
return(`${rootURL}?${queryString.stringify(options)}`)
}
return res.send(getGoogleAuthURL())
})
// Get User from Google
const googleUserX = asyncHandler( async( req, res, next) => {
const url = "https://oauth2.googleapis.com/token";
const code = req.query.code
const values = {
code,
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
redirectUri: process.env.SERVER_ROOT_URI,
grant_type: "authorization_code",
}
axios.post( url, queryString.stringify(values),{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
}
})
.then( async(resD) => {
const { id_token, access_token } = resD.data
// Fetch the user's profile with the access token and bearer
await axios
.get(
`https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=${access_token}`,
{
headers: {
Authorization: `Bearer ${id_token}`,
},
}
)
.then(async (resK) => {
const name = resK.data.name,
email = resK.data.email,
verifiedEmail = resK.data.verified_email
userData = {
name,
email,
verifiedEmail
};
try {
await new googleUser(userData).save()
let message = "success"
return services.googleSendToken(resK.data, 'success', message, res);
} catch (error) {
let message = "registered"
return services.googleSendToken(resK.data, 'registered', message, res);
}
})
.catch((error) => {
console.error(`Failed to fetch user`);
throw new Error(error.message);
});
})
.catch((error) => {
console.error(`Failed to fetch auth tokens`);
throw new Error(error.message);
});

})

//Get current user

module.exports = {
signup,
signin,
getGAuthURL,
googleUserX
}
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const asyncHandler = require('express-async-handler');
const app = require('./app');
const connect = require('./db');



// configure dotenv and port
dotenv.config();
const port = process.env.PORT || 8800;
Expand Down
36 changes: 36 additions & 0 deletions src/models/googleUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema(
{
name: {
type: String,
trim: true,
required:[true,"A user must have a name"]
},
email: {
type: String,
trim: true,
unique: true,
required: [true, 'A user must have an email'],
lowercase: true,
},
refreshToken:{
type:String,
trim:true,
default:null
},
verifiedEmail: {
type: Boolean,
default: false,
},
},
{
timestamps: true,
toJSON: { virtuals: true },
toObject: { virtuals: true }
},
);

const GoogleUser = mongoose.model("GoogleUser", userSchema);

module.exports = GoogleUser;
4 changes: 3 additions & 1 deletion src/models/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const User = require("./user")
const googleUser = require('./googleUser')


module.exports ={
User
User,
googleUser
}
2 changes: 1 addition & 1 deletion src/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const userSchema = new mongoose.Schema(
type: String,
required: [true, 'Enter a user password'],
minLength: 8,
select: false,
select: true,
},
refreshToken:{
type:String,
Expand Down
3 changes: 3 additions & 0 deletions src/routes/v1/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ const { authControllers } = require('../../controllers');
const router = express.Router();

router.post('/signup', authControllers.signup);
router.post('/signin', authControllers.signin);
router.get('/google/url', authControllers.getGAuthURL);
router.get('/google', authControllers.googleUserX)

module.exports = router;
20 changes: 19 additions & 1 deletion src/services/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ const createSendToken = (data, status, message, res) => {
});
};

const googleSendToken = (data, status, message, res) => {
let token = '';

// remove password from output
if (data && data.id) {
token = signToken(data.id);
data.id = null;
}

return res.json({
status,
token,
message,
data,
});
};

module.exports = {
createSendToken
createSendToken,
googleSendToken
}
5 changes: 3 additions & 2 deletions src/services/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const {createSendToken} = require("./auth")
const {createSendToken, googleSendToken} = require("./auth")


module.exports = {
createSendToken
createSendToken,
googleSendToken
}
Loading