I need to find the collection data by an single MongoDB query using Node.js. I am providing the collection below.
f_user_login:
{
"_id": {
"$oid": "5981b48654d471000459208e"
},
"email": "subhrajyoti.pradhan#oditeksolutions.com",
"password": "d0e49bcba946540cb3d5fc808870d16b",
"dob": "02-08-2017",
"created_date": "2017-08-02 11:16:21",
"updated_date": "2017-08-02 11:16:21",
"status": 1,
"token": "b85ff4c47093217587f8c7f2fff7ff86b1bcbf6a7321705871435929ee38",
"verification_id": ""
}
{
"_id": {
"$oid": "598aa189e5f78d00042f48ae"
},
"email": "subhrajyotipradhan#gmail.com",
"password": "d0e49bcba946540cb3d5fc808870d16b",
"dob": "1986-04-10",
"created_date": "2017-08-09 05:45:44",
"updated_date": "2017-08-09 05:45:44",
"status": 0,
"token": "",
"verification_id": "7ffbe3f9be82b2af84491d3e8dff4fa1a65f973d"
}
I am providing my code below.
exports.userSignin=function(req,res){
var email=req.body.email;//subhrajyotipradhan#gmail.com
var password=req.body.password;//d0e49bcba946540cb3d5fc808870d16b
var pass=mden(password);
if (email !='' && password !='') {
db.f_user_login.count({email:email,password:pass,status:1},function(err,docs){
if(docs > 0){
token=crypto.randomBytes(30).toString('hex');
db.f_user_login.update({email:email},{$set:{token:token}},function(err,doc){
db.f_user_login.find({email:email},function(error,docu){
var edata=[{"email": docu[0].email,"dob": docu[0].dob,"created_date":docu[0].created_date ,"id": docu[0]._id,"updated_date":docu[0].updated_date,"token_id":token}];
var data={"statusCode": 200,"data":edata,"message": "The user logged successfully."};
res.send(data);
})
})
}else{
console.log(email,password);
db.f_user_login.find({$or:[{email:email},{password:pass},{status:1}]},function(err,getdocs){
if (!err) {
var uemail=getdocs[0].email;
var upass=getdocs[0].password;
var ustatus=getdocs[0].status;
console.log('email,pass,status',uemail,upass,ustatus);
if (uemail != email) {
var data={"statusCode": 401,"error": "Unauthorized","message": "Invalid email id .Please provide a valid email id"};
}
if (upass != pass) {
var data={"statusCode": 401,"error": "Unauthorized","message": "Invalid Password .Please provide a valid Password"};
}
if (ustatus == 0) {
var data={"statusCode": 401,"error": "Unauthorized","message": "you have not verified your account using the link sent to your email."};
}
res.send(data);
}
})
}
})
}
}
Here my input email and password is right and I need to check the status and get this you have not verified your account using the link sent to your email. message. But unfortunately both document has same password its always checking the first document but originally I need to check the second document for validation.
It is possible using 3 three different query but here I want to operate a single query. Is this possible?
You can use below code for the entire process:
Note: Some typos or code may need to be changed. But you can use the basic idea.
if (email !='' && password !='') {
console.log(email,password);
db.f_user_login.find({$and:[{email:email},{password:pass}]},function(err,getdocs){
if (!err && /*check if the getdocs is not empty*/) {
var uemail=getdocs[0].email;
var upass=getdocs[0].password;
var ustatus=getdocs[0].status;
// update your collection from here with ID
// Remember update is work fine with id
console.log('email,pass,status',uemail,upass,ustatus);
if (ustatus === 0) {
var data={"statusCode": 401,"error": "Unauthorized","message": "you have not verified your account using the link sent to your email."};
}else if(ustatus === 1){
var data={"statusCode": 200,"data":edata,"message": "The user logged successfully."};
}
res.send(data);
}
})
}
Related
I have order app created on strapi, how can I secure data from other users, but user who create order can view him.
I use relation one-to-many from user to many orders, when ?populate=orders requests other authorized users can view them, and when I turn off find action this field removing from /users/me?populate=orders.
How can I set visibility for order by user who made it?
you would need a middleware for this, the more general approach is to use policy to make users not able to fetch other user data, like here: Why all users in Strapi have access to update all users profile?
So let's mod code a bit to fit your case, the steps we are going to do are following:
Create global middleware.
Inject middleware to user-permissions routes.
Mod middleware to remove orders from request if user aren't the one that is registered.
The result is if we do /api/users?populate=orders or /api/users/:id?populate=orders we would not receive orders.
So:
strapi generate
? Strapi Generators middleware
? Middleware name orders
? Where do you want to add this middleware? Add middleware to root of project
So by default middleware would log in console:
'In orders middleware.'
We need to apply it to find, findOne, update, delete routes of user-permissions plugin:
src/extensions/user-permissions/strapi-server.js
module.exports = (plugin) => {
for (let i = 0; i < plugin.routes["content-api"].routes.length; i++) {
const route = plugin.routes["content-api"].routes[i];
// checks if this one of the routes we target
if (
route.handler === "user.findOne" ||
route.handler === "user.find" ||
route.handler === "user.update" ||
route.handler === "user.destroy"
) {
// if it's append middleware to route
plugin.routes["content-api"].routes[i] = {
...route,
config: {
...route.config,
middlewares: route.config.middlewares
? [...route.config.middlewares, "global::orders"]
: ["global::orders"],
},
};
}
}
return plugin;
};
yarn build
yarn develop
If you did the step correct you should see:
[2023-02-14 14:59:51.472] http: GET /api/users (30 ms) 200
[2023-02-14 15:00:01.852] info: In orders middleware.
every time you hit /api/users
Next step we going to tweak middleware, so middleware has two stages, first stage is before await next() it's stage that executed before controller, the second stage is after await next() is stage executed after controller.
We are going to modify the second stage and if we find attribute orders we are going to remove it from response:
src/middlewares/orders.js
'use strict';
/**
* `orders` middleware
*/
module.exports = (config, { strapi }) => {
return async (ctx, next) => {
// before controller
await next();
// after controller
// we need to check if the reponse is correct,
// otherwise we will have error message in the data
if (ctx.response.status === 200) {
// get the authenticated user, if no user - undefined
const { user } = ctx.state;
// get data from response
let data = ctx.response.body;
// check if data is array
if (Array.isArray(data)) {
// run sanitize function for each element
data = data.map(item => sanitizeItem(item, user))
} else {
// else run for single item
data = sanitizeItem(data, user);
}
// apply result to response
ctx.response.body = data;
}
};
};
// sanitizer function
const sanitizeItem = (item, user) => {
// check if user is not undefined
if (user) {
// check if user id is same as the item.id (user from request)
if (user.id === item.id) {
// if it's same return full object
return item;
}
}
// else extract orders from object
let { orders, ...rest } = item;
return rest;
}
And whoala:
[
{
"id": 1,
"username": "user1",
"email": "user1#email.com",
"provider": "local",
"confirmed": true,
"blocked": false,
"createdAt": "2023-02-14T11:39:43.246Z",
"updatedAt": "2023-02-14T11:39:43.246Z",
"orders": [
{
"id": 1,
"title": "Order 1",
"createdAt": "2023-02-14T11:39:01.990Z",
"updatedAt": "2023-02-14T11:39:01.990Z"
},
{
"id": 2,
"title": "Order 2",
"createdAt": "2023-02-14T11:39:09.182Z",
"updatedAt": "2023-02-14T11:39:09.182Z"
}
]
},
{
"id": 2,
"username": "user2",
"email": "user2#email.com",
"provider": "local",
"confirmed": true,
"blocked": false,
"createdAt": "2023-02-14T11:40:04.793Z",
"updatedAt": "2023-02-14T11:40:04.793Z"
}
]
I'm authenticated as user1
I'm trying to update a document in MongoDB using NodeJS (NextJS). My current code is:
import connect from "../../util/mongodb";
async function api(req, res) {
if (req.method === "POST") {
const { id } = req.body;
const { name } = req.body;
const { email} = req.body;
const { anything1 } = req.body;
const { anything2 } = req.body;
if (!id) {
res.status(400).json({ "error": "missing id param" });
return;
}
const { db } = await connect();
const update = await db.collection("records_collection").findOneAndUpdate(
{ id },
{
$set: {
name,
email,
anything1,
anything2
}
},
{ returnOriginal: false }
);
res.status(200).json(update);
} else {
res.status(400).json({ "error": "wrong request method" });
}
}
export default api;
Everything is working. But I would like to request only the ID as mandatory, and for the other information, leave optional.
In this code, passing the id and name for example, the other three fields (email, anything1 and anything2) will be null in the document.
It is possible to implement the update without requiring all document information and ignore when body fields are null? (As a beginner in NodeJS and MongoDB, the only way to do that that comes to my head now is to surround it all by a lot of if...)
If I've understood your question correctly you can achieve your requirement using the body object in $set stage.
If there is a field which not exists in the object, mongo will not update that field.
As an example check this example where only name field is updated and the rest of fields are not set null.
Another example with 2 fields updated and 3 fields.
You can see how only is updated the field into object in the $set.
So you only need to pass the object received into the query. Something like this:
const update = await db.collection("records_collection").findOneAndUpdate(
{ id },
{
$set: req.body
},
{ returnOriginal: false }
);
I want to set roles for a new user.
I tried updating roles array in metadata during signup but I get an error. If I remove the roles metadata new user is created just fine.
db.signUp(userId, 'pass', {
metadata: {
email: 'robi434n#boywonder.com',
birthday: '1932-03-27T00:00:00.000Z',
likes: ['acrobatics', 'short pants', 'sidekickin\'']
roles: ['basic']
}
}, function (err, response) {
if (err) {
if (err.name === 'conflict') {
console.log('batman" already exists, choose another username')
// "batman" already exists, choose another username
} else if (err.name === 'forbidden') {
console.log('invalid username')
// invalid username
} else {
console.log('sign up error')
// HTTP error, cosmic rays, etc.
}
} else {
console.log('user signed up')
// login()
}
})
So I figured it out first modify the pouchdb-authentication index.js code to accept roles.
var signUp = pouchdbUtils.toPromise(function (username, password,roles, opts, callback) {
var db = this;
if (typeof callback === 'undefined') {
callback = typeof opts === 'undefined' ? (typeof password === 'undefined' ?
username : password) : opts;
opts = {};
}
if (['http', 'https'].indexOf(db.type()) === -1) {
return callback(new AuthError('This plugin only works for the http/https adapter. ' +
'So you should use new PouchDB("http://mysi3te.org:5984/mydb") instead.'));
} else if (!username) {
return callback(new AuthError('You must provide a username'));
} else if (!password) {
return callback(new AuthError('You must provide a password'));
}
var userId = 'org.couchdb.user:' + username;
var user = {
name: username,
password: password,
roles: roles,
type: 'user',
_id: userId,
};
updateUser(db, user, opts, callback);
});
Then you can send the roles in the sign up. I'm sending basic below
signUp()
function signUp () {
db.signUp(userId, 'pass', ['basic'], {
metadata: {
email: 'robi434n#boywonder.com',
birthday: '1932-03-27T00:00:00.000Z',
likes: ['acrobatics', 'short pants', 'sidekickin\'']
}
}, function (err, response) {
if (err) {
if (err.name === 'conflict') {
console.log('batman" already exists, choose another username')
// "batman" already exists, choose another username
} else if (err.name === 'forbidden') {
console.log('invalid username', err)
// invalid username
} else {
console.log('sign up error', err)
// HTTP error, cosmic rays, etc.
}
} else {
console.log('user signed up', err)
login()
}
})
}
now you have to go to couchdb _user database _design/_auth document modify
else if (newDoc.roles.length > 0 ) {\n
set this to
else if (newDoc.roles.length > 0 && newDoc.roles[0] !== 'basic' ) {\n
Now you will have basic in your session and can add more roles my adjusting the code a bit. This allows me to set member role permissions easily to limit access to other databases. Or a simpler solution i found and tested is to add a new design doc to your database with the following code. It will only allow users that are logged in to access your database
{
"_id": "_design/usersOnly",
"_rev": "17-6fb7e6c0ccfca8b2e56738ad63e26107",
"language": "javascript",
"validate_doc_update": "\n function(newDoc, oldDoc, userCtx){ \n // check if user is logged in \n if(!userCtx.name){ throw({forbidden : 'No way.. login man!'});} \n //reqired fields to update \n function require(field){ var message = field + ' is required'; if(!newDoc[field]){ throw({'forbidden':message}) }} require('name'); }"
}
The validate function design documentation uses the _users design document as the primary example:
Example: The _design/_auth ddoc from _users database uses a validation function to ensure that documents contain some required fields and are only modified by a user with the _admin role:
...
} else if (newDoc.roles.length > 0) {
throw({forbidden: 'Only _admin may set roles'});
}
...
In fauxton (for example) you can login as the couchdb admin user and go to _users database and change the design (at your own peril), for example:
} else if (newDoc.roles.length > 0 && !("basic" === newRoles[0] && newDoc.roles.length === 1)) {
throw({forbidden: 'Only _admin may set roles'});
}
saving it as you would any other document. (I say peril, since subtle accidents in this design document can potentially allow unauthorized users to drastically raise their permissions.)
With such a change, new users are allowed to be created with the basic role by couchdb, so your client code works if it sets roles correctly. In pouchdb-authenticate this seems to be with opt.roles and not opt.metadata.roles, i.e.:
db.signUp(userId, 'pass', {
metadata: {
email: 'robi434n#boywonder.com',
birthday: '1932-03-27T00:00:00.000Z',
likes: ['acrobatics', 'short pants', 'sidekickin\'']
},
roles: ['basic'] }, ... )
{
"_id": {
"$oid": "5a2de0a00d6baa43e8b925d0"
},
"name": "test",
"playList": [
{
"url": "https://p.scdn.co/mp3-preview/8aa799e60164f8a1fb311188d9d85ef65d7782c6?cid=ed36a056ee504173a3889b2e55cbd461",
"artist": "Kenny G",
"songName": "My Heart Will Go On (Love Theme from \"Titanic\")",
"_id": {
"$oid": "5a2de0ad0d6baa43e8b925d1"
}
},
{
"url": "https://p.scdn.co/mp3-preview/7c49854f18e6dfda6cd97ab5e8bc139d7ca82b7c?cid=ed36a056ee504173a3889b2e55cbd461",
"artist": "PRODUCE 101",
"songName": "PICK ME",
"_id": {
"$oid": "5a2de13b0d6baa43e8b925d2"
}
}
],
"__v": 0
}
I have a database called channels where each channels contain a playList as shown below. I want to delete a single item when a button is clicked. I can handle the onClick event part, but I am not sure how to implement the routes part.
I know that I start by doing something like
router.delete(''/channels/:id', function(req, res){
something here...
})
but how can I access a particular item (probably with a unique id?) and delete it from the DB?
EDIT
By using the GET below
router.get('/channels/:id',
isLoggedIn,
function(req, res) {
channel.findOne({'name':req.params.id},function(err,channeldata){
if(err || channeldata === null){
res.status(404).send({
message: 'Channel Not Found',
data: []
})
}
else {
res.status(200).json({
message: "channel to "+req.params.id+"success",
data:channeldata
})
}
})
});
I get the data for a single channel in my DB.
But since I am new to this stuff, I am not sure how to access each item of the playList and delete a single data.
EDIT2
var mongoose = require('mongoose');
var ChannelSchema = new mongoose.Schema({
name: {type:String,required:true},
playList: [{
songName: { type : String },
artist: { type : String },
url: { type : String }
}]
})
module.exports = mongoose.model('Channel',ChannelSchema);
You can try the following snippet that contains the DELETE (part of CRUD) endpoint for your resource collection (i.e. the channels):
router.delete('/channels/playlist/song', isLoggedIn, (req, res) => {
const channel_id = req.query.channelId;
const song_id = req.query.songId;
// the following query deletes a song form a playlist of a certain channel
channel.update({_id: ObjectId(channel_id)},{$pull:{playList:{_id:ObjectId(song_id)}}})
.exec()
.then(result => {
// for checking if document was found and deleted
// mongodb actually returns special object `result`
// which has its own certain fields
res.status(200).send({
status: "success",
message: result
});
})
.catch(error => {
// here we see if we had any problem with server or db itself
console.log(error)
res.status(500).send({
success: false,
message: "Something went wrong with DELETE /channels/:id"
})
})
});
I assume that you know what ObjectId() function does
if you do not have it declared, declare the following comment
in the beginning of the file (where you require everything)
const mongoose = require('mongoose'); // you must have this
const ObjectId = mongoose.Types.ObjectId; // gets the function
Let me know if this helps, or if you do not understand something - I will make an edit so that you get it.
I am fairly new to using Mongoose and MongoDB. I am working on a register / login page. The register function works fine, storing the user account onto the database, but my problem is with logging in. What I am trying to do is get the 'password' attribute from the matching user off of the database, to match against the password that the user enters. This is my login function.
router.post('/logSubmit', function(req, res, next) {
var gusername = req.body.username;
var gpassword = req.body.password;
User.count({
'credentials.username': gusername
}, function(err, count) {
if (err) throw err;
console.log(count);
if (count > 0) {
// Where I need to pull password attribute from the database
} else {
// Wrong username or password
}
});
});
I have looked all over the internet on how to read an attribute from a database entry, but I can't find anything. I feel like it is something very simple, but I guess I don't know the syntax. The name of my model is User. I figured it would be something like:
User.find({ username: gusername }, function(err, user) {
if (err) throw err;
var getpassword = user.password;
console.log(getpassword);
});
I half-thought that would work, but it didn't. How do I access the password attribute from the database?? Thanks.
EDIT:
This is what my user accounts look like stored in my database:
{
"_id": {
"$oid": "569e5344d4355010b63734b7"
},
"credentials": {
"username": "testuser",
"password": "password1234"
},
"__v": 0
}
A find query is sufficient for your purposes. If a non-null user object is retrieved from the find query, you have a guarantee that it is a user with a password.
User.find({ 'credentials.username': gusername }, function(err, users) {
if (err) throw err;
// 'users' is an array of the User objects retrieved.
users.forEach(function(user) {
// Do something with the password.
// The password is stored in user.credentials.password
console.log(user.credentials.password);
});
});