I used the bcrypt, cookie-parser, jsonwebtoken, validator... librarys.
And I am using express, jwt, and sequelize.
The situation I am in is that when I sign up as a member, it is first added to the DB.
If you create an account again, it will be duplicated.
const bcrypt = require("bcrypt");
const { User } = require("../../models");
const jwt = require("jsonwebtoken");
const {
registerValidator,
loginValidator,
} = require("../../validation/authValidation");
require("dotenv").config();
exports.register = async (req, res) => {
const { errors, isValid } = registerValidator(req.body);
let { email, username, password } = req.body;
if (!isValid) {
return res.status(400).json(errors);
}
const emailExists = await User.findOne({ Where: { email: email } });
console.log(emailExists);
if (emailExists) {
return res.status(400).json({ message: "이미 사용중인 이메일입니다." });
}
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
const newUser = {
username: username,
email: email,
password: hashedPassword,
};
User.create(newUser)
.then((save) => {
res.status(200).json({ status: "Success", new_user_id: save.id });
})
.catch((err) => res.status(500).json({ message: err + "잘안됩니다." }));
As in the postman image, the token was initially stored in a cookie and when the DB was checked, it was confirmed that a record was added.
The validation was written as follows through the validator library.
const Validator = require("validator");
const isEmpty = (value) =>
value === undefined ||
value === null ||
(typeof value === "object" && Object.keys(value).length === 0) ||
(typeof value === "string" && value.trim().length === 0);
const registerValidator = (data) => {
let errors = {};
data.username = !isEmpty(data.username) ? data.username : "";
data.email = !isEmpty(data.email) ? data.email : "";
data.password = !isEmpty(data.password) ? data.password : "";
if (Validator.isEmpty(data.username)) {
errors.username = "유저네임을 입력해주세요.";
}
if (Validator.isEmpty(data.email)) {
errors.email = "이메일을 입력해주세요.";
}
if (Validator.isEmpty(data.password)) {
errors.password = "비밀번호를 입력해주세요.";
}
if (!Validator.isLength(data.password, { min: 6, max: 30 })) {
errors.password = "비밀번호는 6자 이상 30자 미만으로 작성해야합니다.";
}
return {
errors,
isValid: isEmpty(errors),
};
};
const loginValidator = (data) => {
let errors = {};
data.email = !isEmpty(data.email) ? data.email : "";
data.password = !isEmpty(data.password) ? data.password : "";
if (!Validator.isEmail(data.email)) {
errors.email = "Email is invalid";
}
if (Validator.isEmpty(data.email)) {
errors.email = "Email is required";
}
if (Validator.isEmpty(data.password)) {
errors.password = "Password is required";
}
return {
errors,
isValid: isEmpty(errors),
};
};
module.exports.registerValidator = registerValidator;
module.exports.loginValidator = loginValidator;
How do I fix it? Help.
As I understood your question you want to put validation for uniqueness of email in database. If so you can add some code in your Users model:
// inside attributes definition of your model
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true // throws validation error if creating instance is already stored
} ...
So in your code you can omit parts of finding User and checking whether emails match with requested one. You just write
await User.create(newUser) // if uniqueness validation fails it will throw error and no dublication would be in database
Related
How can I make a method in which if a user sign up that user get a 4 digit id? And that id increases whenever new user signup?
In NodeJS that id should be random but it should be at least 4 digit and it move on & on whenever a new user sign up but the minimum value should be 4 digit only so how can I built that method? if its a large process than please explain me I will get a idea or if its easy and it can be done in less lines of code than please provide snippets of that example you can check my code
user.controller:
const user_module = require('./user.modules');
class user_controller extends user_module {
static create_user = async (req, res) =>{
try {
console.log("controller response",req.body)
let response = await this.save_user_details(req)
let message = 'Success';
res.send({
sucess: true,
message: message,
data: response
})
} catch (error) {
let status_code = error.status.code != undefined ? error.status_code: 500;
let type = error.type != undefined ? err.type: 'Bad Request';
let message = err.custom_msg != undefined ? error.custom_msg: "Something went wrong"
res.status(status_code).send({
sucess: false,
error:type,
message: message
})
}
}
static get_users = async (req, res) =>{
try {
console.log("controller response",req.body)
let response = await this.retrieve_user(req)
let message = 'Success';
res.send({
sucess: true,
message: message,
data: response
})
} catch (error) {
let status_code = error.status.code != undefined ? error.status_code: 500;
let type = error.type != undefined ? err.type: 'Bad Request';
let message = err.custom_msg != undefined ? error.custom_msg: "Something went wrong"
res.status(status_code).send({
sucess: false,
error:type,
message: message
})
}
}
static otp_verify = async (req, res) =>{
try {
console.log("controller response",req.body)
let response = await this.verify_user(req)
if(response.status){
res.send({
success: true,
message: response.message,
data: response.user
})
}else{
res.status(400).send({
success: false,
error: false,
message: response.message
})
}
} catch (error) {
let status_code = error.status_code != undefined ? error.status_code: 500;
let type = error.type != undefined ? err.type: 'Bad Request';
let message = error.custom_msg != undefined ? error.custom_msg: "Something went wrong"
res.status(status_code).send({
sucess: false,
error:type,
message:message
})
res.end();
}
}
}
module.exports = user_controller
user.modules:
const models = require('../models');
class user_module {
static save_user_details = async (req) => {
try {
console.log("req body", req.body)
const { profileImage } = req.body
let set_data = req.body
if (!!profileImage) {
set_data.profileImage = profileImage
}
return await models.users.create(set_data)
} catch (error) {
throw error
}
}
static retrieve_user = async (req) => {
try {
let {limit, pagination} = req.query
let query = {}
let projection ={__v: 0}
let options = {
lean: true,
sort: {_id: -1},
skip: !Number(pagination) ? 0: Number(pagination) * !Number(limit) ? 10: Number(limit),
limit: !Number(limit) ? 10: Number(limit)
}
let users = await models.users.find(query, projection, options)
let count = await models.users.count(query)
return {users, count}
} catch (error) {
throw error
}
}
static verify_user = async (req) => {
try {
console.log("req body", req.body)
const { otp, user_id } = req.body
if(otp == '123456'){
let user = await models.users.findById(user_id)
return {user: user, status: true, message: 'success'}
}else{
return {user: null, status: false, message: 'Otp Invalid'}
}
} catch (error) {
throw error
}
}
}
module.exports = user_module
Schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Users = new Schema({
name: String,
phoneNumber: String,
userid: String,
profileImage: {
type: String,
default: 'https://www.pngitem.com/pimgs/m/146-1468479_my-profile-icon-blank-profile-picture-circle-hd.png'
},
about: String,
selectedCountry: {
type: Object
}
})
module.exports = mongoose.model("users", Users)
I am writing some server side login code for aws cognito and I want to verify the user who is logging in exists in the identity pool and to get the attributes assigned to them.
For email login I have this working well using the following code - using the aws-sdk:
let cognitoVerifyUser = null
try {
const cognitoIdProvider = new AWS.CognitoIdentityServiceProvider()
cognitoVerifyUser = await cognitoIdProvider.adminGetUser({
UserPoolId: pool.userPoolId,
Username: username,
}).promise()
} catch (e) {
throwError(e, e.message)
}
if (!cognitoVerifyUser) {
throwError(error.unauthorized, e)
}
const emailAttrib = cognitoVerifyUser.UserAttributes.find(a => a.Name == 'email')
if (!cognitoVerifyUser.Enabled || cognitoVerifyUser.UserStatus != 'CONFIRMED' || username != cognitoVerifyUser.Username || email != emailAttrib.Value) {
throwError(error.unauthorized, e)
}
But I am stuck trying to do something similar for federated users (login via google for example).
Can someone help me out?
import generateResponse from "../../../Utils/generateResponse";
import {
CognitoUserPool,
CognitoUser,
AuthenticationDetails
} from "amazon-cognito-identity-js";
import { APIGatewayEvent } from "aws-lambda";
type LoginType = {
email: string;
password: string;
};
export const handler = async (event: APIGatewayEvent) => {
try {
const body = JSON.parse(event.body as string) as LoginType;
const userPool = new CognitoUserPool({
UserPoolId: process.env.COGNITO_USERPOOLID as string,
ClientId: process.env.COGNITO_CLIENTID as string
});
const user = new CognitoUser({ Username: body.email, Pool: userPool });
const authenticationData = {
Username: body.email,
Password: body.password
};
const authenticationDetails = new AuthenticationDetails(authenticationData);
return new Promise(resolve =>
user.authenticateUser(authenticationDetails, {
//#ts-ignore
onSuccess: result => {
resolve({ body: JSON.stringify(result) });
},
onFailure: err => {
resolve({ body: JSON.stringify(err) });
}
})
);
} catch (err) {
return generateResponse({
statusCode: 400,
body: JSON.stringify(err, Object.getOwnPropertyNames(err))
});
}
};
i have a login endpoint. try that.
I am working on a proyect developing a REST API and would like some feedback on this simple user creation middleware. How would you optimize it in order to not have this much "if" statements?
This is the code:
function middlewareUserCreation(req, res, next) {
const conditionUserName = req.body.userName != null && req.body.userName != undefined;
const conditionFullName = req.body.fullName != null && req.body.fullName != undefined;
const conditionEmail = req.body.email != null && req.body.email != undefined;
const conditionTelephone = req.body.telephone != null && req.body.telephone != undefined;
const conditionAddress = req.body.address != null && req.body.address != undefined;
const conditionPassword = req.body.password != null && req.body.password != undefined;
if (conditionUserName) {
if (conditionFullName) {
if (conditionEmail) {
if (conditionTelephone) {
if (conditionAddress) {
if (conditionPassword) {
const newUserName = req.body.userName;
const newEmail = req.body.email;
const checkAdmin = req.body.isAdmin;
for (user of validUsersArray) {
if (newUserName != user.userName) {
if (newEmail != user.email) {
return next();
}
res.send("Email taken, please use another one");
}
}
res.send("Username taken, please try another one");
}
res.send("A password is required");
}
res.send("Please provide a delivery address");
}
res.send("A contact telephone is required");
}
res.send("An email is required");
}
res.send("Please provide your full name");
}
res.send("Choose an username");
};
There could be a number of smaller ideas, like using !!:
// this:
const conditionUserName = req.body.userName != null && req.body.userName != undefined;
// is the same as this:
const conditionUserName = !!req.body.userName;
Snippet to show this:
const long = (data) => {
return data != null && data != undefined
}
const short = (data) => {
return !!data
}
const arr = [
null,
undefined,
'has value',
]
arr.forEach(e => {
console.log("long:", long(e))
console.log("short:", short(e))
})
Then you could extract the rules, create a validation function based on the rules and res.send according to the validation results:
const validationMessages = {
userName: "Choose a username",
fullName: "Please provide your full name",
email: "An email is required",
telephone: "A contact telephone is required",
address: "Please provide a delivery address",
password: "A password is required",
}
const validate = (messages, data) => {
// return the message if any of the keys are null or undefined (truthy)
// return false otherwise (falsy)
const msg = Object.keys(messages).find(key => !(!!data[key]))
return msg ? messages[msg] : false
}
function middlewareUserCreation(req, res, next) {
// if invalid it will be a message; if valid it will be undefined
const isInvalid = validate(validationMessages, req.body)
if (isInvalid) {
res.send(isInvalid)
} else {
const newUserName = req.body.userName;
const newEmail = req.body.email;
const checkAdmin = req.body.isAdmin;
for (user of validUsersArray) {
if (newUserName != user.userName) {
if (newEmail != user.email) {
return next();
}
res.send("Email taken, please use another one");
}
}
res.send("Username taken, please try another one");
}
}
I'm trying to update a transaction, but instead its updating that one and at the same time deleting the other ones. My focus is to just update one transaction. Can someone check my backend logic please.
My Schema:
const mongoose = require('mongoose')
mongoose.Schema.Types.String.set('trim', true)
const transactionSchema = mongoose.Schema(
{
note: { type: String, required: true },
amount: { type: Number, default: 0 },
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User',
},
},
{
timestamps: true,
}
)
const WalletSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true,
},
name: {
type: String,
trim: true,
required: [true, 'Please enter a name'],
},
balance: {
type: Number,
default: 0,
},
transactions: [transactionSchema],
createdAt: {
type: Date,
default: Date.now,
},
})
module.exports = mongoose.model('Wallet', WalletSchema)
My backend controller logic:
exports.updateWalletTransactions = asyncHandler(async (req, res, next) => {
const { amount, note } = req.body
const foundWallet = await Wallet.findOne({ user: req.user.id })
foundWallet.transactions = foundWallet.transactions.filter(
(trans) => trans._id.toString() === req.params.id
)
if (foundWallet.transactions) {
foundWallet.transactions[0].amount =
amount || foundWallet.transactions[0].amount
foundWallet.transactions[0].note = note || foundWallet.transactions[0]
const updatedTransaction = await foundWallet.save()
return res.status(200).json(updatedTransaction)
} else {
return next(new ErrorResponse('Transaction not found', 404))
}
})
The problem is that you're using the filter method of Array that will only return the specified transaction.
the better approach is to write your code using the map method like this:
exports.updateWalletTransactions = asyncHandler(async (req, res, next) => {
const { amount, note } = req.body;
const foundWallet = await Wallet.findOne({ user: req.user.id });
if (!foundWallet) return next(new ErrorResponse("no wallet found", 404));
const transIndex = foundWallet.transactions.findIndex(
(trans) => trans._id.toString() === req.params.id
);
if (!transIndex) return next(new ErrorResponse("Transaction not found", 404));
foundWallet.transactions = foundWallet.transactions.map((trans) => {
if (trans._id.toString() === req.params.id) {
trans.amount = amount || trans.amount;
trans.note = note || trans.note;
}
return trans;
});
const updatedWallet = await foundWallet.save();
const updatedTransactions = updatedWallet.transactions;
return res.status(200).json(updatedTransactions);
});
or you can do it like this:
exports.updateWalletTransactions = asyncHandler(async (req, res, next) => {
const { amount, note } = req.body;
const foundWallet = await Wallet.findOne({ user: req.user.id });
if (!foundWallet) return next(new ErrorResponse("no wallet found", 404));
const transIndex = foundWallet.transactions.findIndex(
(trans) => trans._id.toString() === req.params.id
);
const trans = foundWallet.transactions[transIndex];
if (trans) {
trans.amount = amount || trans.amount;
trans.note = note || trans.note;
} else {
return next(new ErrorResponse("Transaction not found", 404));
}
const updatedWallet = await foundWallet.save();
const updatedTransactions = updatedWallet.transactions;
return res.status(200).json(updatedTransactions);
});
You are overwriting the transaction. Better to iterate over each transaction and update on matching transaction id.
exports.updateWalletTransactions = asyncHandler(async(req, res, next) => {
const {
amount,
note
} = req.body;
const foundWallet = await Wallet.findOne({
user: req.user.id
})
let transFound = false;
if (foundWallet) {
foundWallet.transactions.forEach(trans => {
if (trans._id.toString() === req.params.id) {
transFound = true;
trans.amount = amount || trans.amount
trans.note = note || trans.note
}
})
if(transFound){
const updatedTransaction = await foundWallet.save()
return res.status(200).json(updatedTransaction)
} else {
return next(new ErrorResponse('Transaction not found', 404))
}
} else {
return next(new ErrorResponse('User Id not found', 404))
}
})
I am working on a school project with a team of developers. We have created a page where the users have a profile and that profile can be updated. We have come across a bug when a user updates its information. If I update my city for example, then all other information about my user disappears. I have to update the other fields as well, otherwise the database will only store the city that I recently updated.
What I want is that the information I filled in when I created my user is saved, besides from the information I change when I update my user.
Before update: {"username":"bobox","email":"bobox#hotmail.com","password":"test234","gender":"Man","age":"17","city":"Jönköping","games":"Battlefield V","usernameDiscord":"bigbox","usernameSteam":"bigbox","usernameOrigin":"bobox","_id":"wTs8IyRmcA40f3VN"}
After update: {"username":"bobox","email":"bobox#hotmail.com","password":"test234","gender":"","age":"","city":"New York","games":"","usernameDiscord":"","usernameSteam":"","usernameOrigin":"","_id":"wTs8IyRmcA40f3VN"}
Here is the code. I am thankful for all help. If there is anything else you need to know, just let me know.
Updating a user:
script.js
async function updateUser(age, city, gender, games, discord, steam, origin) {
const id = localStorage.getItem("userId")
const response = await fetch('http://localhost:8080/users/' + id, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
age: age,
city: city,
gender: gender,
games: games,
usernameDiscord: discord,
usernameSteam: steam,
usernameOrigin: origin
})
})
console.log(response)
const data = await response.json()
console.log(data)
}
function updateUsersIndex() {
let updateProfileBtn = document.querySelector(".Profile-Right__Update")
console.log(updateProfileBtn)
updateProfileBtn.addEventListener("click", async(event) => {
console.log("hej")
event.preventDefault()
const age = document.querySelector(".Age__Input").value
const city = document.querySelector(".City__Input").value
const gender = document.querySelector(".Gender__Input").value
const discord = document.querySelector(".Discord__Input").value
const steam = document.querySelector(".Steam__Input").value
const origin = document.querySelector(".Origin__Input").value
const games = document.querySelector(".Profile-Right__Select-Game").value
const hidden = document.querySelector(".hidden")
const updateUsers = await updateUser(age, city, gender, games, discord, steam, origin)
})
}
updateUsersIndex()
let profileUpdateBackBtn = document.querySelector(".Profile-Right__Back")
profileUpdateBackBtn.addEventListener("click", async(event) => {
event.preventDefault()
let updateProfile = document.querySelector(".Update-Profile")
let profile = document.querySelector(".Profile__Wrappe")
profile.classList.toggle("Hidden")
updateProfile.classList.toggle("Hidden")
})
app.js:
app.patch('/users/:id', async(req, res) => {
const result = await collectionsNEDB.users.update({ _id: req.params.id }, {
$set: {
"age": req.body.age,
"city": req.body.city,
"gender": req.body.gender,
"games": req.body.games,
"usernameDiscord": req.body.usernameDiscord,
"usernameSteam": req.body.usernameSteam,
"usernameOrigin": req.body.usernameOrigin
}
})
console.log(req.params.id)
res.json(result)
})
Creating a user:
script.js
async function createUser(username, email, password, repeatPassword, games, usernameDiscord, usernameSteam, usernameOrigin) {
const response = await fetch('http://localhost:8080/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: username,
email: email,
password: password,
repeatPassword,
games: games,
usernameDiscord: usernameDiscord,
usernameSteam: usernameSteam,
usernameOrigin: usernameOrigin
})
})
console.log(response)
const data = await response.json()
if (response.status == 200) {
console.log(data.message)
if (data.message == "SUCCESS") {
console.log("Great")
let Success = document.querySelector(".Success")
Success.innerHTML = "Användare skapad!"
alert("Användare skapad!")
}
} else {
const data = await response.json()
const p = document.querySelector("p")
p.innerHTML = ""
for (let i = 0; i < data.errors.length; i++) {
const error = data.errors[i]
console.log(data.errors)
switch (error) {
case "ERROR_USER_ALREADY_EXISTS":
const hidden = document.querySelector(".Error")
hidden.classList.toggle("Hidden")
hidden.innerHTML = "Användarnamnet existerar redan!"
break;
case "ERROR_EMAIL_ALREADY_EXISTS":
const hiddenEmail = document.querySelector(".Error__Email")
hiddenEmail.classList.toggle("Hidden__Email")
hiddenEmail.innerHTML = "E-mail existerar redan!"
break;
case "ERROR_PASSWORD_MISMATCH":
const hiddenPassword = document.querySelector(".Error__Password")
hiddenPassword.classList.toggle("Hidden__Password")
hiddenPassword.innerHTML = "Lösenordet matchar inte"
break;
}
}
}
}
function init() {
let form = document.querySelector("#Reg-Form-1")
form.addEventListener("submit", async(event) => {
event.preventDefault()
const username = form.querySelector(".username").value
const email = form.querySelector(".email").value
const password = form.querySelector(".password").value
const repeatPassword = form.querySelector(".repeat-password").value
const games = form.querySelector(".gejms").value
const usernameDiscord = form.querySelector(".usernameDiscord").value
const usernameSteam = form.querySelector(".usernameSteam").value
const usernameOrigin = form.querySelector(".usernameOrigin").value
const hidden = document.querySelector(".hidden")
const createUsers = await createUser(username, email, password, repeatPassword, games, usernameDiscord, usernameSteam, usernameOrigin)
})
}
init()
app.js:
app.post("/register", async(req, res) => {
let user, email
if (process.env.NODE_ENV == "development") {
user = await collectionsNEDB.users.find({ username: req.body.username })
email = await collectionsNEDB.users.find({ email: req.body.email })
} else {
dataUser = await Database.collections.users.find({ username: req.body.username })
dataEmail = await Database.collections.users.find({ email: req.body.email })
user = await dataUser.toArray()
email = await dataEmail.toArray()
}
let errors = []
if (req.body.password !== req.body.repeatPassword) {
errors.push("ERROR_PASSWORD_MISMATCH")
} else if (user == false) {
if (email == false) {
let newUser = {
username: req.body.username,
email: req.body.email,
password: req.body.password,
gender: "",
age: "",
city: "",
games: req.body.games,
usernameDiscord: req.body.usernameDiscord,
usernameSteam: req.body.usernameSteam,
usernameOrigin: req.body.usernameOrigin
}
if (process.env.NODE_ENV == "development") {
const result = await collectionsNEDB.users.insert(newUser)
res.status(200).json({ message: "SUCCESS" })
} else {
let db = await Database.connect()
let users = db.collection("users")
const result = await users.insert(newUser)
res.status(200).json({ message: "SUCCESS" })
console.log(result)
}
} else {
errors.push("ERROR_EMAIL_ALREADY_EXISTS")
}
} else {
errors.push("ERROR_USER_ALREADY_EXISTS")
}
if (errors.length > 0) {
res.status(400).json({ errors: errors })
}
})