Loopback + mongoDB: Can't find extended user - node.js

I am using Loopback 3.0 with MongoDB connector.
In a REST method exposed somewhere, I need to access the currently logged user and make some updates on it.
I have extended the base User model, calling it appUser, the login works, and I can get the token (after I changed the token model to point to the appUser) of a logged user. The model is the following one:
{
"name": "appUser",
"plural": "appUsers",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"gender": {
"type": "string",
"enum": [
"M",
"F"
]
},
"birthDate": {
"type": "Date"
}
},
"validations": [],
"relations": {},
"acls": []
}
I need to access the user profile, in order to update it. But when I query it, I get null as result.
const User = app.models.appUser;
User.findOne({
where: {
_id: ObjectId("5aae7ecd2ed1b11b1c09cf25")
}
}, (err, user) => {
if (err || res == null) {
console.log("Error updating the user ");
const error = {
"name": "Database error",
"status": 500,
"message": "Can't access the database."
}
callback(error, null, null);
} else {
//Whatever
}
});
But if I run the same query from Robo3T on MongoDB, it works.
db.getCollection('appUser').find({"_id": ObjectId("5aae7ecd2ed1b11b1c09cf25")})
What am I doing wrong?
Thank you,
Massimo

You didn't call the user so that should be the case, also in your callback you are passing null and not your user result. However I don't get where the res variable came from.
const User = app.models.appUser;
User.findOne({
where: {
_id: ObjectId("5aae7ecd2ed1b11b1c09cf25"),
}
}, (err, user) => {
if (err) {
console.log("Error updating the user", err); // logs the app error
const error = {
"name": "Database error",
"status": 500,
"message": "Can't access the database."
}
callback(error, null); // passes your custom error
}
console.log("APP USER", user);
callback(null, user);
});
I don't how you calling your callback but i think you can manage this.
If you still have no result try changing _id to id

Related

Firebase database collection returns empty array when trying to get all documents

I'm trying to get all documents from my database collection "posts" but I'm getting an empty array instead.
The strange thing is that I'm able to get all documents from another collection called "users" that has the same structure and using the exact same code.
I've spent days looking for an answer but I haven't been able to find the solution.
This is the request:
const db = admin.firestore();
exports.getAllPosts = (req, res) => {
db.collection('posts')
.orderBy('createdAt', 'desc')
.get()
.then(snapshot => {
let posts = [];
snapshot.forEach((doc) => {
posts.push({
id: doc.id,
body: doc.data().body,
author: doc.data().author,
createdAt: doc.data().timestamp,
voteScore: doc.data().voteScore
});
});
return res.json(posts);
})
.catch(err => {
console.error(err);
res.status(500).json({ error: err.code });
});
}
And this is the response:
[]
This is what my current collection looks like:
Posts collection screenshot
This the response that I get when I return "snapshot":
{
"_query": {
"_firestore": {
"_settings": {
"projectId": "readable-bf7a6",
"firebaseVersion": "9.6.0",
"libName": "gccl",
"libVersion": "4.10.0 fire/9.6.0"
},
"_settingsFrozen": true,
"_serializer": {
"allowUndefined": false
},
"_projectId": "readable-bf7a6",
"registeredListenersCount": 0,
"bulkWritersCount": 0,
"_backoffSettings": {
"initialDelayMs": 100,
"maxDelayMs": 60000,
"backoffFactor": 1.3
},
"_clientPool": {
"concurrentOperationLimit": 100,
"maxIdleClients": 1,
"activeClients": {},
"failedClients": {},
"terminated": false,
"terminateDeferred": {
"promise": {}
}
}
},
"_queryOptions": {
"parentPath": {
"segments": []
},
"collectionId": "posts",
"converter": {},
"allDescendants": false,
"fieldFilters": [],
"fieldOrders": [
{
"field": {
"segments": [
"createdAt"
]
},
"direction": "DESCENDING"
}
],
"kindless": false
},
"_serializer": {
"allowUndefined": false
},
"_allowUndefined": false
},
"_readTime": {
"_seconds": 1622395245,
"_nanoseconds": 513743000
},
"_size": 0,
"_materializedDocs": null,
"_materializedChanges": null
}
Notice how the request for the collection "users" works successfully:
const db = admin.firestore();
exports.getAllUsers = (req, res) => {
db.collection('users')
.orderBy('createdAt', 'desc')
.get()
.then(snapshot => {
let users = [];
snapshot.forEach((doc) => {
let users = [];
snapshot.forEach((doc) => {
users.push({
id: doc.data().userId,
email: doc.data().email,
handle: doc.data().handle
});
});
return res.json(users);
})
.catch(err => {
console.error(err);
res.status(500).json({ error: err.code });
});
}
And the response:
[
{
"id": "EPoHBxhQFUXbcL3TCVx1LdUG2nO2",
"email": "ruben#gmail.com"
},
{
"id": "RqEa3dEq8TSDcZYeolXafju67rB2",
"email": "user10#gmail.com"
},
{
"id": "dxveb4n2iMQej5Q14uprsKRxFp23",
"email": "user4#gmail.com",
"handle": "user4"
},
{
"id": "YQPzBPcsqlVZk9iJEuZTHKUNuVG2",
"email": "user2#gmail.com",
"handle": "user2"
},
{
"id": "CZ05BJxi3TUOpIrmBaz539OWlbC3",
"email": "user#gmail.com",
"handle": "user"
},
{
"id": "t0t83BVwt4gVgJkDv7HL1r1MaKr1",
"email": "userJose2#gmail.com",
"handle": "Jose"
}
]
This is what the users collection looks like in Firebase:
Users collection screenshot
Why is one collection failing when the other works fine and I'm using the same code? What am I missing here?
Thanks in advance and I hope I've made it as clear as possible. Please let me know if you need me to provide anything else.
Very simple my friend, your posts documents can't be ordered like this:
.orderBy('createdAt', 'desc')
Because the post documents does not have the createdAt property, but they have a timestamp property, you should use that property to order your posts like this:
.orderBy('timestamp', 'desc')
I hope that helps 👍
I am not answering directly to #Ruben Garcia Bri, but for future firebase developers who may run into the problem of getting empty documents, I also ran into the same problem, but I solved it by adding a field to the particular document I am trying to retrieve.
Sometimes the cause is because the documents you are trying to get have no field in them.
I mean that a document must have a field before the server can recognize it as an existing document.
So if you run into this problem, consider adding a field to that document before you can successfully retrieve it.

Sagepay Issue - Retrieve a Transaction not working after 3D-Secure Authenticate

https://developer.sage.com/api/payments/api/#operation/retrieveTransaction
After 3D-Secure Authenticate, I can't retrieve transaction using transactionId. I'm getting the following response :
{
"description": "Transaction not found",
"code": 1012
}
Sometimes it's working fine. then it's a response like this:
{
"statusCode": "0000",
"statusDetail": "The Authorisation was Successful.",
"transactionId": "5D208A72-C1A6-68E7-A61D-B67D51CXXXXX",
"transactionType": "Payment",
"retrievalReference": 6764XXX,
"bankResponseCode": "00",
"bankAuthorisationCode": "999XXX",
"paymentMethod": {
"card": {
"cardType": "Visa",
"lastFourDigits": "0006",
"expiryDate": "0720",
"cardIdentifier": "8B27BE84-E06C-4F88-ADCD-AFF22EBXXXXX",
"reusable": false
}
},
"amount": {
"totalAmount": 13500,
"saleAmount": 13500,
"surchargeAmount": 0
},
"currency": "GBP",
"fiRecipient": {},
"status": "Ok",
"avsCvcCheck": {
"status": "AllMatched",
"address": "Matched",
"postalCode": "Matched",
"securityCode": "Matched"
},
"3DSecure": {
"status": "Authenticated"
}
}
Does anybody know How can I fix this issue?
I experienced the same issue. I am using the test sandbox environment and forcing 3dsv1.0 processing. In 3DS version 1 , after the challenge/response returns it does not give the full transaction details, so you then need to query sagepay to get the authorisation status. As stated above it either returns the transaction object successfully OR quite randomly gives {"description":"Transaction not found","code":1012}.
I then assumed some timing issue - so put in place a retry option below to query the transaction. This appeared to assist things (meaning "sometimes" it got the transaction) but was not a fix in itself.
async.retry({
times: 10,
interval: function(retryCount) {
return 50 * Math.pow(2, retryCount);
},
errorFilter: function(errorCode) {
return errorCode === 404; // only retry on transaction 'not-found'
},
},
function (callback) {
return getSageTransactionStatus(MD, callback)
},
function(err, result) {
if (err) {
if (global.gLogging ) console.log ("Transaction Search Result", err);
}
else console.log (result);
});

Node js check if user id is in array

I'm trying to validate who can do a PUT request on a document.
I have a field that indicates who created the document. If the user created it he/she can edit it and this part is working correctly.
I also have an array of user ids that should also be able to edit but I can't seem to be able to check if the current user is in this array and therefore I can't edit the document.
Here's one document:
{
"teachers": ["5c740f96e0d6b10016801daa"],
"_id": "5cd552b179b1b30016c4c0e9",
"date": "2019-05-10T10:30:09.978Z",
"name": "prof",
"goal": "goal",
"activity": {
"affective_objectives": [],
"social_objectives": [],
"_id": "5cd552b179b1b30016c4c0ea",
"learning_objectives": [
{
"_id": "5cd552b179b1b30016c4c0eb",
"knowledge_category": "Factual",
"behaviour": "teste",
"subject_matter": "asdas",
"conditions": "",
"degree": ""
}
],
"description": "des",
"subject": "subj",
"delivery_mode": "teste",
"interaction": "teste",
"scope": "teste",
"age": 5,
"feedback_use": "High",
"interrelationship": "High",
"motivation": "High",
"participation": "High",
"performance": "None"
},
"project_manager": "5cb48f6a169a9b0016d34dac",
"__v": 0
}
And my PUT function:
function edit(req, res) {
let query = {
_id : req.params.id
};
Projeto.findById(query)
.then(async (projeto) => {
if(!projeto) {
return res.status(404).json({error: 'not_found', message: 'This project doesn\'t exist.'});
}
if ( (projeto.project_manager != req.user._id) && (projeto.teachers.indexOf(req.user._id) != -1) ) {
return res.status(403).json({error: 'forbidden', message: 'You can\'t edit this project.'});
} else {
await Projeto.findOneAndUpdate(query, req.body, {new: true});
res.json({ message: 'Project successfully edited.'});
}
})
.catch(utils.handleError(req, res));
}
If I try to do a PUT request with the project_manager user everything works but with the user in "teachers" I get the error message that I can't edit.
What's the correct way to verify that here?
If the user is not in teachers array the indexOf() method will return -1.
So, you need to check if it's the case for you:
function edit(req, res) {
let query = {
_id : req.params.id
};
Projeto.findById(query)
.then(async (projeto) => {
if(!projeto) {
return res.status(404).json({error: 'not_found', message: 'This project doesn\'t exist.'});
}
if ( (projeto.project_manager != req.user._id) && (projeto.teachers.indexOf(req.user._id) === -1) ) {
return res.status(403).json({error: 'forbidden', message: 'You can\'t edit this project.'});
} else {
await Projeto.findOneAndUpdate(query, req.body, {new: true});
res.json({ message: 'Project successfully edited.'});
}
})
.catch(utils.handleError(req, res));
}
TLDR:
Replace projeto.teachers.indexOf(req.user._id) != -1 by projeto.teachers.indexOf(req.user._id) === -1

Email verification using secrettoken in nodejs

I am trying to verify the user by taking the secrettoken from the link sent in the email. I am able to extract the secrettoken but not able to update the value of active as true.
Below is my code
router.route('/verify')
.get((req,res)=>{
console.log('request recieved');
const token = req.query.id;
User.updateOne(
{ secretToken: token },
{
$set: { price: true }
},function(err,res){
if(err){
throw err;
}
else{
console.log('one document updated');
}
}
);
});
"email": "surendrap720#gmail.com",
"username": "surendrap720",
"password": "$2a$10$UEKSpPpVWfZ3urclkayW6OcAUvscBrql23WU6fvfbI0Nd1jzo2Bxa",
"type": "tutor",
"secretToken": "5A6fXVh5gEObwUQxgpG4DpJ85COMJveJ",
"active": false,
You are not modifying active at all in your updateOne code.
change this:
$set: { price: true }
to this:
{ active: true }

Cascade delete from array using Mongoose middleware remove hook

I am building a Node.js express RESTfull API using Mongodb and mongoose.
This is my schema:
var UserSchema = new mongo.Schema({
username: { type: String },
password: { type: String, min: 8 },
display_name: { type: String, min: 1 },
friends: { type: [String] }
});
UserSchema.post('remove', function(next){
console.log({ friends: this._id }); // to test if this gets reached (it does)
UserSchema.remove({ friends: this._id });
});
And this is the function that removes a User:
.delete(function(req, res) {
User.findById(req.params.user_id, function(err, user) {
if (err) {
res.status(500);
res.send(err);
} else {
if (user != null) {
user.remove();
res.json({ message: 'User successfully deleted' });
} else {
res.status(403);
res.json({ message: 'Could not find user.' });
res.send();
}
}
});
});
What I need to do is when a user is removed, his or her _id (String) should also be removed from all the other users' friends array. Hence the remove hook in the schema.
Right now the user gets deleted and the hook gets triggered, but the user _id is not removed from the friends array (tested with Postman):
[
{
"_id": "563155447e982194d02a4890",
"username": "admin",
"__v": 25,
"password": "adminpass",
"display_name": "admin",
"friends": [
"5633d1c02a8cd82f5c7c55d4"
]
},
{
"_id": "5633d1c02a8cd82f5c7c55d4",
"display_name": "Johnybruh",
"password": "donttouchjohnsstuff",
"username": "John stuff n things",
"__v": 0,
"friends": []
}
]
To this:
[
{
"_id": "563155447e982194d02a4890",
"username": "admin",
"__v": 25,
"password": "adminpass",
"display_name": "admin",
"friends": [
"5633d1c02a8cd82f5c7c55d4"
]
}
]
To try and figure it out I have looked at the Mongoosejs Documentation, but the mongoose doc example doesn't cover the remove hook. Also this stackoverflow qestion but this question seems to be about removing from other schemas.
I think i'm doing the remove in the hook wrong, but I can't seem to find the problem.
Thanks in advance!
EDIT:
I could not get the first suggestion by cmlndz to work, so I ended up fetching all the documents with arrays that contained the to-be-deleted users' id and pulling it from them one-by-one:
The delete function now contains this bit of code that does the magic:
// retrieve all documents that have this users' id in their friends lists
User.find({ friends: user._id }, function(err, friends) {
if (err) {
res.json({ warning: 'References not removed' });
} else {
// pull each reference to the deleted user one-by-one
friends.forEach(function(friend){
friend.friends.pull(user._id);
friend.save(function(err) {
if (err) {
res.json({ warning: 'Not all references removed' });
}
});
});
}
});
You could use $pull to find all documents that contain the "ID" in the "friends" array -or- find any matching document and popping the "ID" out of the array one by one.

Resources