Unable to update customer data in postgreSQL - javascript

Im trying to do crud operation using pg-promises and store procedure in postgreSQL. below is my code.
controller.js:
const db = require("./../index.js");
exports.getAllData = async (req, res, next) => {
try {
const data = await db.any("SELECT * FROM customers");
res.json({ data });
} catch (error) {
console.log(error);
}
next();
};
GET method
exports.getData = async (req, res, next) => {
try {
const id = req.params.id;
const data = await db.any("SELECT * FROM customers where id=$1", [id]);
res.json({ data });
} catch (error) {
console.error(error);
res.status(400).json({
status: "failed",
msg: error.message,
});
}
next();
};
POST method
exports.createData = async (req, res, next) => {
try {
const name = req.body.name;
const email = req.body.email;
const data = await db.one("SELECT create_user($1, $2)", [name, email]);
res.json({
status: "success",
data: data,
});
} catch (error) {
console.error(error);
res.status(400).json({
status: "failed",
msg: error.message,
});
}
next();
};
PATCH method :
exports.updateData = async (req, res, next) => {
try {
const id = req.params.id;
const name = req.body.name;
const email = req.body.email;
// const data = await db.one('SELECT update_user($1, $2, $3) FROM customers WHERE id = $1', [id,name,email]);
// const data = await db.none('SELECT update_user($1, $2, $3) FROM customers WHERE id = $4', [id, name, email, id]);
const data = await db.any("SELECT update_user($1, $2, $3) FROM customers c WHERE c.id = $1", [
id,
name,
email,
]);
res.json({
message: "success",
data: data,
});
} catch (error) {
console.error(error);
res.status(400).json({
status: "failed",
msg: error.message,
});
}
next();
};
DELETE method
exports.deleteData = async (req, res, next) => {
try {
const id = req.params.id;
// const data = await db.none('DELETE FROM customers WHERE id = $1', [id]);
const data = await db.none("SELECT delete_user($1)", [id]);
res.json({ data });
} catch (error) {
console.error(error);
res.status(400).json({
status: "failed",
msg: error.message,
});
}
next();
};
routes.js
const express = require("express");
const viewController = require("./../controllers/controller");
const router = express.Router();
router.get("/", viewController.getAllData);
router.get("/:id", viewController.getData);
router.post("/create", viewController.createData);
router.patch("/update/:id", viewController.updateData);
router.delete("/delete/:id", viewController.deleteData);
module.exports = router;
This is a function I have created in postgreSQL:
CREATE OR REPLACE FUNCTION create_user(name VARCHAR(50), email VARCHAR(50))
RETURNS VOID AS $$
BEGIN
INSERT INTO customers (name, email)
VALUES (name, email);
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION update_user(id INTEGER, name VARCHAR(50), email VARCHAR(50))
RETURNS VOID AS $$
BEGIN
UPDATE customers SET name = name, email = email
WHERE id = id;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION delete_user(id INTEGER)
RETURNS VOID AS $$
BEGIN
DELETE FROM customers
WHERE id = id;
END;
$$ LANGUAGE plpgsql;
I Am trying to update some data using this endpoint localhost:3000/update/:id in postman. but in response im getting this error:
{
"status": "failed",
"msg": "column reference \"id\" is ambiguous"
}
I know this question related "id is ambiguos" has been ask many times. I tried to solve this, but unable to solve this issue.

Well the id name in id = id is ambiguous - and you should be glad that it is, because if it wasn't, that condition is a tautology and would have updated/deleted all your rows. There are three approaches to disambiguate it:
Just rename the function parameter:
CREATE OR REPLACE FUNCTION update_user(customer_id INTEGER, new_name VARCHAR(50), new_email VARCHAR(50))
RETURNS VOID AS $$
BEGIN
UPDATE customers
SET name = new_name, email = new_email
WHERE customer.id = customer_id;
END;
$$ LANGUAGE plpgsql;
Use parameter numbers:
CREATE OR REPLACE FUNCTION update_user(id INTEGER, name VARCHAR(50), email VARCHAR(50))
RETURNS VOID AS $$
BEGIN
UPDATE customers
SET name = $2, email = $3
WHERE id = $1;
END;
$$ LANGUAGE plpgsql;
Use the name of the function to qualify:
CREATE OR REPLACE FUNCTION update_user(id INTEGER, name VARCHAR(50), email VARCHAR(50))
RETURNS VOID AS $$
BEGIN
UPDATE customers
SET name = update_user.name, email = update_user.email
WHERE customers.id = update_user.id;
END;
$$ LANGUAGE plpgsql;

Related

How to catch error using Postgres, PG, Express?

const pool = require('../db')
const asyncHandler = require('express-async-handler')
const { generateToken } = require('../middleware/userAuth')
// #desc Register New User
// #route POST /api/users/register
// #public Public
const registerUser = asyncHandler(async(req, res) => {
const { email, name, password } = req.body
const newUser = {
name,
email,
password
}
const existingUser = ''
if (existingUser) {
res.status(400)
throw new Error('User Already Exists')
} else {
try {
const result = await pool.query(
'INSERT INTO users (name, email, password) VALUES ($1, $2, $3) RETURNING *',
[name, email, password],
(err, res) => {
if (err) {
console.log(err)
}
}
)
res.status(201)
res.json(result.rows)
} catch (error) {
console.log(error)
res.status(400)
throw new Error('Unable to create user')
}
}
})
I'm trying to figure out how to console.log the errors that come from the postgresql database errors when I make a query.
So far, the try/catch is only catching main errors in express. The console.log(error) will say "Type Error, cannot return rows of undefined" which means "result" variable is undefined because the query failed, and "Unable to create user" from the new Error thrown. (I purposefully made it fail)
The "err" callback doesn't seem to console.log anything.
I'd like to be able to see what specifically in postgresql was the problem, such as in this case the columns do not exist.
Any ideas?

Login Authentication with bcrypt and SQLite3

i am currently building a React application with Nodejs/Express Backend and try to implement a Login Authentication.
i register Users with Name, email, password and hash the password with bcrypt:
router.post('/register', async (req, res) => {
// Hashing
const salt = await bcrypt.genSalt(10)
const hashedPassword = await bcrypt.hash(req.body.regpassword, salt)
// Validate
const {error} = Joi.validate(req.body, schema)
var data = {
regname: req.body.regname,
regemail: req.body.regemail,
regpassword : hashedPassword
}
var sql ='INSERT INTO Users (regname, regemail, regpassword) VALUES (?,?,?)'
var params =[data.regname, data.regemail, data.regpassword]
db.run(sql, params, function (err, result) {
if (error){
res.status(400).send(error.details[0].message);
return;
}
res.json({
"answer": "Success",
})
res.status(200)
});
})
this works fine. But my /login route doesnt work:
router.post('/login', (req, res, next) => {
let sql = `SELECT * FROM Users WHERE regname = "${req.body.regname}" AND regpassword = "${req.body.regpassword}"`;
var x;
db.all(sql, (err, rows) => {
if (err) {
next(err);
return;
}
if (!rows) {
res.status(400);
res.send('Invalid username or password');
return
}
rows.forEach( async (row) => {
if (row.regname === req.body.regname && await bcrypt.compare(req.body.regpassword, row.regpassword) ) {
x = 1;
}
else {
x = 2;
db.close();
}
})
if (x === 1) {
res.json({
"answer":"Success",
})
}
else {
res.json(
{"answer":"Denied",
})
}
})
})
The salt needs to be stored in the database as well.
The /login route must then retrieve the regpassword and the salt from the database based on the req.body.regname. It then needs to run a await bcrypt.hash(req.body.regpassword, salt) exactly identical to the /register route and then compare the result of that hashing operation with the regpassword from the database. If the two hashes match then the user provided the correct password and you can display some confirmation / issue some session token / ...
i share my solution here, if someone needs it:
router.post('/login', (req, res) => {
const regname = req.body.regname;
const regpassword = req.body.regpassword;
const findUserByName = (regname, cb) => {
return db.get(`SELECT * FROM Users WHERE regname = ?`,[regname], (err, row) => {
cb(err, row)
});
}
findUserByName(regname, (err, user)=>{
if (err) return res.status(500).send('Server error!');
if (!user) return res.status(404).send('User not found!');
const result = bcrypt.compareSync(regpassword, user.regpassword);
if(!result) return res.status(401).send('Password not valid!');
res.status(200)
res.json({
"answer":"Success",
})
});
});

cannot compare password with bcrypt compare

Im trying to build a node api for change password,
User must type the currentPassword and the new password
when bcrypt.compare the new currentPassword with the stored on db, i got always false, whatever it's wrong or correct
const changePass = async (req, res, next) => {
//email and password
const CurrentPassword = req.body.currPassword
let password1 = ''+req.body.password1
let password2 = ''+req.body.password2
const hashedPassword = await bcrypt.hash(password1, 10);
let id = "" + req.body.id
User.findById( id )
.then(user => {
bcrypt.compare(CurrentPassword, user.password, (err, data) => {
if (err) throw err
if (data) {
User.findByIdAndUpdate(id, {password : hashedPassword }, {new: false}, (err) => {
if (err) throw err
})
} else {
return res.status(401).json({ msg: "Invalid" })
}
})
})
}
If you want to learn bcrypt I recommend you to visit bcrypt NPM because it will save you too much time later,
in your case I made some modification on your code in order to check for the current password OLD and then compare between the newPassword1 and the confirmation passwordConfirmation
feel free to use console.log('') when you have doubts about anything it will give you a good vision about your code status
const changePassword = async (req, res, next) => {
let id = req.body.nid;
if(id){
console.log('Im here')
const old = req.body.old;
const newP = req.body.newP;
const newP2 = req.body.newP2;
User.findById(id,(err,user)=>{
if(user){
console.log(user)
const hash = user.password;
bcrypt.compare(old,hash,function (err,res){
if(res){
if(newP === newP2){
bcrypt.hash(newP,10, (err,hash)=>{
user.password = hash;
user.save( (err,user) =>{
if(err) return console.error(err);
console.log(user.userName +' your password has been changed');
});
});
};
};
});
}
})
}
}

Getting single message from Graph

I'm trying to get a single email from an Office 365 Mailbox.
I'm sending the email id to my app via a POST (req.body.id) and then calling this code in order to get some email properties:
router.post('/id', async function(req, res, next) {
console.log("email with ID -> ", req.body.id)
let parms = { title: 'Inbox', active: { inbox: true } };
const accessToken = await authHelper.getAccessToken(req.cookies, res);
const userName = req.cookies.graph_user_name;
if (accessToken && userName) {
parms.user = userName;
// Initialize Graph client
const client = graph.Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
try {
const result = await client
.api('/me/messages/', req.body.id)
.select('id,subject,from,toRecipients,ccRecipients,body,sentDateTime,receivedDateTime')
.get();
parms.messages = result.value;
console.log("email -> ", result.value);
res.render('message', parms);
} catch (err) {
parms.message = 'Error retrieving messages';
parms.error = { status: `${err.code}: ${err.message}` };
parms.debug = JSON.stringify(err.body, null, 2);
res.render('error', parms);
}
} else {
// Redirect to home
res.redirect('/');
}
});
At the moment, result.value contains all of the messages in the mailbox instead of just the message with provided id.
Could someone tell me where my error is, please?
The api method has a single path parameter. Calling it like .api('/me/messages/', req.body.id) is effectivly sending it a path ("/me/messages/") along with an additional parameter it ignores.
You need to send it a single string so you'll need to append the req.body.id to the path ({path} + {id}):
const result = await client
.api('/me/messages/' + req.body.id)
.select('id,subject,from,toRecipients,ccRecipients,body,sentDateTime,receivedDateTime')
.get();

Node js returning values from function

I live in the PHP world but I am attempting to build out a REST Api using Node.
I have been stuck all day of trying to return an array of results from a for loop. Basically I am passing an array of field_name:field_value. I want to push the result from the update into an array to return. I can get it to log in the console but no further.
Here is a sample post json data
{
"first_name":"Jeff",
"phone":"4855555555"
}
Here is the function and loop
function UpdateKey(user_id, key, value, cb) {
connection.query('UPDATE users SET ' + key + ' = ? WHERE id = ? LIMIT 1', [value, user_id], function(err, results) {
if (err) {
callback = key + " update failed.";
} else {
callback = key + " was updated.";
}
cb(callback);
});
}
for (myKey in post_data) {
UpdateKey(user_id, myKey, post_data[myKey], function(id) {
console.log(id);
});
}
res.send(JSON.stringify({ "status": 200, "error": "", "response": my_results_here }));
I have been researching async but not sure the best route here. Any help would be great!
You could collect all results in an array and send that when the arrays size equals the keys size:
const keys = Object.keys(post_data);
const response = [];
for(const myKey of keys) {
UpdateKey(user_id, myKey, post_data[myKey], function(id) {
response.push(id);
if(keys.length === response.length) {
res.send(JSON.stringify({
status: 200,
error: "",
response
}));
}
});
}
The solution You want:
const updateUserField = (userId, field, value) => {
return Promise((resolve) => {
const query = 'UPDATE users SET ' + field + ' = ? WHERE id = ?';
const data = [value, userId];
connection.query(query, data, (error) => {
if (error) return resolve(field + ' update failed');
resolve(field + ' was updated');
});
});
};
router.post('/user/:id', async (req, res) => {
const userId = req.params.id;
const data = req.body;
const response = [];
for (const field in data) {
response.push(
await updateUserField(userId, field, data[field])
);
}
res.status(200).send({
response
});
});
or in parallel:
router.post('/user/:id', async (req, res) => {
const userId = req.params.id;
const data = req.body;
const response = await Promise.all(
Object
.keys(data)
.map(field => updateUserField(userId, field, data[field]))
);
res.status(200).send({
response
});
});
Correct solution
As I understand You want to get post data and update record in users table.
So why not just do it in one query?
Try this way:
const updateUser = (userId, data) => {
return Promise((resolve, reject) => {
const query = 'UPDATE users SET ? WHERE id = ?';
connection.query(query, [data, userId], (error) => {
if (error) return reject(error);
resolve();
});
});
};
router.post('/user/:id', async (req, res) => {
try {
const userId = req.params.id;
const data = req.body;
await updateUser(userId, data);
res.status(200).send({
message: 'User account successfully updated'
})
}
catch (error) {
console.error(error);
res.status(500).send({
message: 'Failed update user account'
});
}
});
But better think about using ORM i.e. Sequelize for security, validation and etc features that eases dev's life.

Categories

Resources