Invalid prisma.user.findUnique() invocation - javascript

I can't seem to find what the error in the invocation is
function findUser(req, res) {
const username = req.body.username;
prisma.user.findUnique({
where: { username: username },
select: { username: true }
})
.then(data => {
res.send({
'userExists': data ? true : false
})
})
.catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while retrieving user."
})
})
.finally(async () => { await prisma.$disconnect()});
// schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id Int #default(autoincrement()) #id
username String #unique
password String
salt String
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}

From Prisma side everything is OK. The problem is probably req.body.username, if it's undefined you receive Invalid 'prisma.user.findUnique()' invocation.
You have to add validation for username, i.e.
if {typeof username !== string} return res.status(404).send('invalid username')

It might be the late response. I was also running into the same problem. But documentation saved my day. https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#findunique
You just have to add #unique attribute to your username field in schema.prisma, like below —
username String #unique #db.VarChar(255)

After looking at your code it seems that the username is missing from your req.body. I would suggest always verify the params you want to extract from req.body. I refactor your code to es6.
Here is the updated code you can try,
function findUser(req, res) {
// Destructure username from req.body
const { username } = req.body;
if(username == null) throw new Error('Username undefined');
// when property and value is same, you can write 'username' like below
prisma.user.findUnique({
where: { username },
select: { username: true }
})
.then(data => {
res.send({
'userExists': data ? true : false
})
})
.catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while retrieving user."
})
})
.finally(async () => { await prisma.$disconnect()});

Related

Why find() using models won't work in signup route?

It's a simple signup route to store credentials in a mongoDB database but I miss something because the 2 else if won't work properly. I suspect it is my find().
The first else if returns me in Postman "error": "E11000 duplicate key error collection: vinted.users index: email_1 dup key: { email: \"jean#dpont.com\" }" and the second give me "email already exists".
Thanks in advance for your help
const express = require("express");
const router = express.Router();
const SHA256 = require("crypto-js/sha256");
const encBase64 = require("crypto-js/enc-base64");
const uid2 = require("uid2");
const User = require("../models/User");
router.post("/user/signup", async (req, res) => {
try {
const email = req.fields.email;
const username = req.fields.username;
const phone = req.fields.phone;
const password = req.fields.password;
const token = uid2(64);
const salt = uid2(16);
const hash = SHA256(password + salt).toString(encBase64);
const emailSearch = await User.find({ email: email });
if (!emailSearch || username !== null) {
const newUser = new User({
email: email,
account: {
username: username,
phone: phone,
},
password: password,
token: token,
hash: hash,
salt: salt,
});
await newUser.save();
res.status(200).json({
_id: newUser._id,
token: newUser.token,
account: newUser.account,
});
}
//problem under
else if (emailSearch) {
res.status(404).json({ message: "email already exists" });
} else if (username === null) {
res.status(404).json({ message: "please type a username" });
}
} catch (error) {
res.status(404).json({
error: error.message,
});
}
});
It looks like the issue is that if the username in the request body is not null, it's going to attempt to create a new User with that username regardless of whether a User exists with the same email - if (!emailSearch || username !== null).
It's generally best-practice to do as much input validation as you can before you start looking for records or creating new ones, as you will be able to avoid more Mongo errors and database actions if you can stop invalid actions before they're attempted. So in this case, check that the username is valid before looking for existing Users.
To solve this problem, I would move that last else-if to before you check whether a User exists with the same email. That way, once you determine whether the username is valid, then the only thing that you need to consider is existing Users before creating a new one. Something like this:
if (username === null) {
res.status(400).send({ message: "Error: Please provide a 'username'." });
}
const existingUserWithEmail = await User.find({ email: email });
if (!existingUserWithEmail) {
// Create the new User
} else {
res.status(400).send({ message: "Error: An account already exists with this email." });
}

What's the proper way to select certain fields in a query when you use Mongoose?

I read the documentation that describes how to solve the issue with extracting certain fields of an object found by id. I've tried to write a similar code, but the output assigned to the user variable includes all fields of a single element.
export const getUser = async (
req: Request,
res: Response,
next: NextFunction
) => {
try {
const { id } = req.params;
const userFetchesOwnData = req.app.locals.userId === id;
let user: any;
if (req.app.locals.isAuth && userFetchesOwnData) {
user = await User.findById(
id,
"email username age sex location summary"
).exec();
} else {
user = await User.findById(
id,
" username age sex location summary"
).exec();
}
console.log(user);
res.status(200).json({
message: "User fetched",
user,
});
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};
You can specifically query fields in a Mongoose object by comma separated values.
User.findById(id).select("_id, email, username, age, sex, location, summary").then(...)

How do I add an object to a database in Knex where the object is the child of two parents?

I have the code below. Its a standard blog type of setup with users which have posts and comments. Comments are the child of both users and post . Posts belong just to users. Im having a problem posting to comments table. IM not getting any errors when using the insert function , however, when I post a comment to the database nothing gets saved to the comments table . If i do a request to retrieve the comments table , the table still shows empty. What am i doing wrong here .
server.post("/users/:id/posts/:id2/comments", async (req, res) => {
const userID = req.params.id;
const postID = req.params.id2;
db("users")
.where({ id: Number(userID)})
.then((user) => {
db('posts') .where({ id: Number(postID)})
.then((post) => {
//verify if post and user exists
if (post && user) {
req.body.content ? insertComment({
content: req.body.content,
user: userID,
post: postID
})
.then(
res.status(201).json(req.body)
)
.catch((err) => {
console.log(err);
})
: res.status(400).json({
errorMessage: "Please insert text .",
});
} else {
res.status(404).json({
message: "user not found",
});
}
})
})
.catch((err) => {
res.status(500).json({
err,
message: "Error processing request",
});
});
});
function insertComment(comment) {
return db("comments").insert(comment).where({
user: comment.user,
post: comment.post
});
}
since you're already using async function i'd first recommend to use async/await, second notice is that knex returns an array and not an object for example
db("users")
.where({ id: Number(userID)})
.then((user) => {
// user is an array
});
you can chain a query with .first() to retrieve the first object and not an array
Reference from knex documentation
using async/await could save you from callback hell
server.post("/users/:id/posts/:id2/comments", async (req, res) => {
const userID = req.params.id;
const postID = req.params.id2;
try {
const user = await db("users").where("id", Number(userID)).first();
const post = await db("posts").where("id", Number(postID)).first();
if (post && user) {
if (req.body.content) {
await insertComment({
content: req.body.content,
user: userID,
post: postID,
});
return res.status(201).json(req.body);
} else {
return res.status(400).json({
errorMessage: "Please insert text .",
});
}
} else {
return res.status(404).json({
message: "user or post not found",
});
}
} catch (err) {
return res.status(500).json({
err,
message: "Error processing request",
});
}
});
async function insertComment(comment) {
return db("comments").insert(comment).where({
user: comment.user,
post: comment.post,
});
}
and if you have lots of relationships in your application you might find it useful if you want to use an ORM like Objection as it is built on knex.

Unable to login after creating a post

So, I've been scratching my head for over a day about this problem. My app supports signup, signin, creating a post. What I have noticed is that the user who doesn't have a post can login successfully any time. But those who have posts cannot login after.
Here's how it looks.
case 1
I register with Jim -> jim is stored in the db -> login with jim(success) -> logout(works fine) and again login(works fine)
case 2
I register with Jim -> jim is stored in the db -> login with jim(success) -> makes a post -> post shows in his feed(success) -> logout(works fine) and again try to login(failed)
The error is->
POST http://localhost:3000/api/v1/users/login 402 (Payment Required)
It's not even entering the login controller when a user who has post(s) try to login. It's working successfully for the user who has no post(s). It's confusing me.
Here's the code:
registerUser: (req, res) => {
console.log("inside register user")
const { username, email, password } = req.body
User.create(req.body, (err, createdUser) => {
if (err) {
return res.status(500).json({ error: "Server error occurred" })
} else if (!username || !email || !password) {
return res.status(400).json({ message: "Username, email and password are must" })
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invaid email" })
} else if (password.length < 6) {
return res.status(400).json({ message: "Password should be of at least 6 characters" })
}
else {
return res.status(200).json({ user: createdUser })
}
})
},
loginUser: async (req, res, next) => {
console.log("inside login controller")
const { email, password } = req.body
if (!email || !password) {
return res.status(400).json({ message: "Email and password are must" })
}
await User.findOne({ email }, (err, user) => {
if (err) {
return next(err)
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invalid email" })
} else if (!user) {
return res.status(402).json({ error: "User not found" })
} else if (!user.confirmPassword(password)) {
return res.status(402).json({ error: "incorrect password" })
}
// generate token here
const token = auth.signToken({ userId: user._id })
// const token = auth.signToken({ email })
res.status(200).json({ user, token })
// next()
})
}
newPost controller
newPost: (req, res) => {
const data = {
title: req.body.title,
content: req.body.content,
user: req.user.userId
}
Post.create(data, (err, newPost) => {
if (err) {
return res.status(500).json({ error: err })
} else if (!newPost) {
return res.status(400).json({ message: "No Post found" })
} else if (newPost) {
User.findById(req.user.userId, (err, user) => {
user.posts.push(newPost._id) //pushing posts documnet objectid to the post array of the user document
user
.save()
.then(() => {
return res.json(200).json({ user })
})
.catch(err => {
return res.status(500).json({ error: err })
})
})
}
})
}
I also checked in postman by going to the route /users/login and entering the email and password, but it's saying incorrect password. It's returning the return from
else if (!user.confirmPassword(password)) {
return res.status(402).json({ error: "incorrect password" })
}
If I change the above to ({ error: err}), it's returning in the response:
{
"error": null
}
Update
User.findById(req.user.userId, (err, user) => {
console.log("user before save", user)
user.gratitudes.push(newGratitude._id) //pushing posts documnet objectid to the post array of the user document
user
.save()
.then(() => {
// return res.json(200).json({ user })
console.log("user after saving", user)
})
.catch(err => {
return res.status(500).json({ error: err })
})
)
So, I did this and consoles
user before saving => { posts: [],
_id: 5e78c76381327761329b8dc6,
username: 'king123',
email: 'king123#gmail.com',
password: '$2b$10$CnWib5AMxw1qv5RnBdEisOXUq9X3lqqOMH3HWO3DlWf.iB2Ke8GLS',
createdAt: 2020-03-23T14:27:47.820Z,
updatedAt: 2020-03-23T14:27:47.820Z,
__v: 0 }
user after saving => { posts: [ 5e78c77a81327761329b8dc7 ],
_id: 5e78c76381327761329b8dc6,
username: 'king123',
email: 'king123#gmail.com',
password: '$2b$10$ro4FIO40.3Nwe52RFq/leepH906HvIHYW5A3XrTGfNXcUSIfsx0Bq',
createdAt: 2020-03-23T14:27:47.820Z,
updatedAt: 2020-03-23T14:28:10.290Z,
__v: 1 }
It looks like the hashed password has changed.
It sounds like your blog post method is effecting your user record somehow.
Try making a new user, logging in, checking the user record looks normal.
Then make a post as that user and rather than checking for the post, check the user record for differences before you made the post. I'd expect that something from the post update is changing something in the user record by mistake.

how to add data to my firebase upon email and password registration using angularfire2

So after creating a user in my firebase with the (createUser) firebase method.
How do i then immediately add data into my firebase database. Here is a code below.
createUser(email: string, password: string, username:string) {
this.af.auth.createUser({ email, password })
**so instead of the console log below**
.then((user) => console.log(`Create User Success:`, user))
** i will rather add the username string into my firebase like this**
const adddatatobase = this.af.database().ref('usernamestore').push({
userdetails:username
});
.catch(e => console.error(`Create User Failure:`, e));
}
I have tried the code above and i have not been very successful. Any help at all with this.
Thanks
You have to add the script you want to execute inside your response:
createUser(email: string, password: string, username:string) {
this.af.auth.createUser({ email, password })
.then(user => {
const users = this.af.database.object('/profile');
users.update({
user.uid: { username: username }
});
})
.catch(err => console.error(`Create User Failure: ${err}`));
}

Categories