Fail to save user to mongodb - mongodb

If I remain this code, the program still working, my image will upload backend to frontend normally
router.post('/admin/register', upload.single('avatar'), async (req, res) => {
// Handle add image by multer
... handel file upload from front-end
return res.json({ avatar: newFullPath });
}
);
I started save user to mongoDB and error occur
router.post('/admin/register', upload.single('avatar'), async (req, res) => {
// Handle add image by multer
... handel file upload from front-end
//Handle add user to database
const user = {
...JSON.parse(req.body.user),
avatar: newFullPath
}; // { first_name: 'John', last_name: 'Wick', avatar: .... }
const { error } = Validation.adminRegisterValidation(user);
if (error) {
return res.json({ error: error.details[0].message });
} // working as I expected
const emailExist = await User.findOne({ email: user.email });
if (emailExist) {
return res.json({ error: 'Email already exist!' });
} // working as I expected
// If I commented this block of code, program still run as I expected, but if I don't do
// that, the program crashed ( Error: Below images )
const hashedPassword = bcrypt.hashSync(user.password, 10);
const addUser = new User({
first_name: user.first_name,
last_name: user.last_name,
avatar: user.avatar
});
await addUser.save();
return res.json({ avatar: newFullPath });
}
);
This project in my Github repository: This project in Github
Error shows in console
Error in Network

Related

NEXT JS AND MONGODB JWT integration

Looking for a backend dev that can simply help me implement MONGODB with nextJS and the current model I have now. I have bought https://www.devias.io admin dashboard, and just want to implement auth and database reading with it.
Just want the basic auth setup. It's already setup in the FILES just wanting to know how to configure it properly based on the devias guides
Has anyone done this before I can't find any documentation on it
It's setup with mock data at the moment
SRC/API/AUTH/index.js
import { createResourceId } from '../../utils/create-resource-id';
import { decode, JWT_EXPIRES_IN, JWT_SECRET, sign } from '../../utils/jwt';
import { wait } from '../../utils/wait';
import { users } from './data';
class AuthApi {
async signIn(request) {
const { email, password } = request;
await wait(500);
return new Promise((resolve, reject) => {
try {
// Find the user
const user = users.find((user) => user.email === email);
if (!user || (user.password !== password)) {
reject(new Error('Please check your email and password'));
return;
}
// Create the access token
const accessToken = sign({ userId: user.id }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
resolve({ accessToken });
} catch (err) {
console.error('[Auth Api]: ', err);
reject(new Error('Internal server error'));
}
});
}
async signUp(request) {
const { email, name, password } = request;
await wait(1000);
return new Promise((resolve, reject) => {
try {
// Check if a user already exists
let user = users.find((user) => user.email === email);
if (user) {
reject(new Error('User already exists'));
return;
}
user = {
id: createResourceId(),
avatar: undefined,
email,
name,
password,
plan: 'Standard'
};
users.push(user);
const accessToken = sign({ userId: user.id }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
resolve({ accessToken });
} catch (err) {
console.error('[Auth Api]: ', err);
reject(new Error('Internal server error'));
}
});
}
me(request) {
const { accessToken } = request;
return new Promise((resolve, reject) => {
try {
// Decode access token
const { userId } = decode(accessToken);
// Find the user
const user = users.find((user) => user.id === userId);
if (!user) {
reject(new Error('Invalid authorization token'));
return;
}
resolve({
id: user.id,
avatar: user.avatar,
email: user.email,
name: user.name,
plan: user.plan
});
} catch (err) {
console.error('[Auth Api]: ', err);
reject(new Error('Internal server error'));
}
});
}
}
export const authApi = new AuthApi();
then /SRC/API/AUTH/data.js
export const users = [
{
id: '5e86809283e28b96d2d38537',
avatar: '/assets/avatars/avatar-anika-visser.png',
email: 'demo#devias.io',
name: 'Anika Visser',
password: 'Password123!',
plan: 'Premium'
}
];
This is the documentation on it
JSON Web Token (JWT)
Most auth providers use this strategy under the hood to provide access tokens. Currently, the app doesn't cover the backend service, and this service is mocked (faked) using http client interceptors. The implementation is basic, but enough to give you a starting point.
How it was implemented
Since tokens are meant to be created on the backend server, they are built with encrypt, encode and decode utility methods because they are not meant to be used on the client. These utilities can be found in src/utils/jwt. These are for development purposes only, and you must remove (or avoid using) them.
How to use JWT Provider
The app is delivered with JWT Provider as default auth strategy. If you changed or removed it, and you want it back, simply follow these steps:
Step 1: Import the provider
Open src/pages/_app.js file, import the provider and wrap the App component with it.
// src/pages/_app.js
import { AuthConsumer, AuthProvider } from '../contexts/auth/jwt-context';
const App = (props) => {
const { Component, pageProps } = props;
return (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
);
};
Step 2: Set the hook context
Open src/hooks/use-auth.js file and replace the current context the following line:
import { AuthContext } from '../contexts/auth/jwt-context';
How to use auth
Retrieve user profile
In the example below, you can find how it can be used in any component not just the App. Should you want to use it in any other component, you'll have to import the useAuth hook and use it as needed.
// src/pages/index.js
import { useAuth } from '../hooks/use-auth';
const Page = () => {
const { user } = useAuth();
return (
<div>
Email: {user.email}
</div>
);
};
Auth methods / actions
For simplicity and space limitations, the code below is used only to exemplify, actual code can be found in the components.
// src/pages/index.js
import { useAuth } from '../hooks/use-auth';
const Page = () => {
const { login } = useAuth();
const handleLogin = () => {
// Email/username and password
login('demo#devias.io', 'Password123!');
};
s
return (
<div>
<button onClick={handleLogin}>
Login
</button>
</div>
);
};
Implemented flows
Currently, the app only covers the main flows:
Register
Login
Logout
const mongoose = require('mongoose');
const jwt = require("jsonwebtoken");
// Connect to MongoDB
mongoose.connect('mongodb://localhost/yourdbname', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const userSchema = new mongoose.Schema({
id: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true
},
name: {
type: String,
required: true
},
password: {
type: String,
required: true
},
plan: {
type: String,
default:
'Standard'
},
avatar: {
type: String,
default:
null
},
});
const User = mongoose.model('User', userSchema);
const JWT_SECRET = process.env.JWT_SECRET;
const JWT_EXPIRES_IN = '7d';
class AuthApi {
async signIn(request) {
const {
email,
password
} = request;
const user = await User.findOne({
email
});
if (!user || (user.password !== password)) {
throw new Error('Please check your email and password');
}
const accessToken = jwt.sign({
userId: user.id
}, JWT_SECRET, {
expiresIn: JWT_EXPIRES_IN
});
return {
accessToken
};
}
async signUp(request) {
const {
email,
name,
password
} = request;
const existingUser = await User.findOne({
email
});
if (existingUser) {
throw new Error('User already exists');
}
const newUser = new User({
id: mongoose.Types.ObjectId(),
email,
name,
password,
plan: 'Standard',
avatar: null,
});
await newUser.save();
const accessToken = jwt.sign({
userId: newUser.id
}, JWT_SECRET, {
expiresIn: JWT_EXPIRES_IN
});
return {
accessToken
};
}
async me(request) {
const {
accessToken
} = request;
const decoded = jwt.verify(accessToken, JWT_SECRET);
const {
userId
} = decoded;
const user = await User.findById(userId);
if (!user) {
throw new Error('Invalid authorization token');
}
return {
id: user.id,
avatar: user.avatar,
email: user.email,
name: user.name,
plan: user.plan
};
}
}
export const authApi = new AuthApi();

option to manually flush/write body to browser when done

I have so far been unable to sort out this issue. I have a code that uses the MongoDb driver and whenever a do a fetch operation, i can no longer write to .response.body, e.g:
Once I call - await users.findOne({ email: req.email }) , I get an error when I do ctx.response.body.
As a workaround, is there a way i can force write the response, or a flag i can use to force oak not to close the response until i explicitly tell it to?
The error I get: The response is not writable.
Here is a sample snipped of my code:
private async create(context: Context, next: Function){
try {
interface UserSchema { email: string; password: string;}
const body = context.request.body()
assertEquals(body.type, 'json', 'app sent data in wrong format')
const req = await body.value
assertExists(req.email, 'email not provided')
assertExists(req.password, 'password not provided')
assertMatch(req.email, /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")#(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/, 'this does not look like a valid email address')
assertMatch(req.password, /(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/, 'password must contain: capital letter, small letter, number and must be 8 characters long')
const conn = context.state.db
const db = await conn.database('users')
const users = await db.collection<UserSchema>("users")
const user_id = await users.findOne({ email: req.email }) //bug *wont write to body
assert(!(user_id), 'email already exists')
const insertId = await users.insertOne({ email: req.email, password: req.password })
console.log('user added'); context.response.body = { 'error': false, 'msg': 'account created' }
} catch (e) { console.log({ 'error': e.name, 'msg': e.message })
//context.response.status = 500; context.response.body = { 'error': e.name, 'msg': e.message }
}
}

Route.get() requires a callback issue when using passport trying to authenticate with Facebook

I am trying to authenticate users to my app using Facebook. I made sure that the configuration on https://developers.facebook.com/apps/1137899716785088/settings/basic/ is as it should ie: I added http://localhost:3000 as an app domain (after clicking save it still got converted to "localhost" only, but I guess that is okay. The error I get when loading my website is:
throw new Error(msg);
^
Error: Route.get() requires a callback function but got a [object Object]
I have already checked these threads: 1, 2, 3 but none of them solved my issue. Below is my code
passport/facebook.js
const passport = require('passport');
const facebookStrategy = require('passport-facebook').Strategy;
const User = require('../models/user');
const keys = require('../config/keys');
// fetch user ID and generate cookied ID for browser
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
passport.use(new facebookStrategy({
clientID: keys.FBAppID,
clientSecret: keys.FBAppSECRET,
callbackURL: 'http://localhost:3000/auth/facebook/callback',
profileFields: ['email', 'name', 'displayName', 'photos']
// profileFields: ['id', 'email', 'gender', 'link', 'locale', 'name', 'timezone', 'updated_time', 'verified'],
}, (accessToken, refreshToken, profile, done) => {
console.log(profile);
// save user data
User.findOne({facebook: profile.id}, (err, user) => {
if (err) {
return done(err);
}
if (user) {
return done(null, user);
} else {
const newUser = {
facebook: profile.id,
firstname: profile.name.givenName,
lastname: profile.name.familyName,
image: `https://graph.facebook.com/${profile.id}/picture?type=large`,
email: profile.emails[0].value
}
new User(newUser).save((err, user) => {
if (err) {
return done(err);
}
if (user) {
return done(null, user);
}
})
}
})
}));
app.js
// load modules
const express = require('express');
const passport = require('passport');
// init app
const app = express();
app.use(passport.initialize())
app.use(passport.session());
// load passports
require('./passport/local');
require('./passport/facebook');
//passport authentication
app.get('/auth/facebook', passport.authenticate('facebook'), {
scope: ['email']
});
app.get('/auth/facebook/callback', passport.authenticate('facebook', {
successRedirect: '/profile',
failureRedirect: '/'
}));
The mistake was a syntactical one. I accidentally closed the round brackets immediately after the 'facebook' part, when in fact I shouldn't have done that.
Before fix:
app.get('/auth/facebook', passport.authenticate('facebook'), {scope: ['email']});
After fix:
app.get('/auth/facebook', passport.authenticate('facebook', {scope: ['email']}));

Why is MongoDB not saving my user (issues with async/await?) - Express, mongoDB, Oauth

I'm using Oauth to allow my users to sign in with their google account. I have successfully created a function which checks if the email is verified and then, depending on if the user is already saved in the data base, just send back the user - or if the user doesn't exsist create a new user.
My console displays the message "Email is verified" and "User not found" so I know it makes it to that part of the code - but it doesn't proceed to create a new user. My suspicions is that is has to do with the async await and that things are perhaps happening in the wrong order. Any thoughts would be much appreciated!
app.post("/googlelogin", (req, res) => {
const { tokenId } = req.body
client.verifyIdToken({
idToken: tokenId,
audience: 'XXXX' // removed for demo
})
.then(async (response) => {
const { email_verified, name, email } = response.payload
console.log(response.payload)
if (email_verified) {
console.log('email is verified')
try {
const user = await User.findOne({ name, email })
if (user) {
console.log('User found!')
return res.json({
success: true,
name: user.name,
email: user.email,
token: user.token,
userID: user._id
})
} else {
console.log('User not found!')
let newUser = await new User({
name,
email
}).save()
return res.json({
success: true,
name: newUser.name,
email: newUser.email,
token: newUser.token,
userID: newUser._id
})
}
} catch (error) {
res.status(400).json({
success: false,
message: "Something went wrong",
error
})
}
} else {
return res.status(400).json({
success: false,
error: "Email not verified",
})
}
})
})
SOLVED.
Found this thread and followed the tip to drop my collection and after this it worked!
MongoError: E11000 duplicate key error collection: tracker-db.users index: username_1 dup key: { username: null }"

findByIdAndUpdate not updating document on MongoDB

I am trying to create an Api that updates my MongoDB before sending a password reset email to the user using nodemailer. Everything works fine except the database update for some reason. I am using findByIdAndUpdate to do the update.
My api starts with
router.put('/forgot',[auth, [check('email', 'Please include a valid email').isEmail()]],async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email } = req.body;
try {
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({
errors: [
{
msg:
'That email addrss is not recognized. Please try again or register for a new account ',
},
],
});
}
var email_token = crypto.randomBytes(64).toString('hex');
const payload = {
id: user.id,
resetPasswordToken: email_token,
resetPasswordExpires: Date.now() + 3600000,
};
user = await User.findByIdAndUpdate(
user.id,
{ $set: payload },
{ new: true }
);
console.log(user);
res.json(user);
Thank you Joe and Mohammed, Well from Mohammed question i realized i did not define resetPasswordToken and resetPasswordExpires in the User Model. As soon as i did that every thing worked as magic. Thank you so much!