Updating existing mongodb data MERN - express

So I'm creating a webpage with users, and when the user first signs up for the site they are prompted to input a first name, last name, email, etc. In the user's profile page, I added a form to change the users name. I'm able to get all the info I need into the back end, but I'm not sure of the syntax to actually update the database with it.
This is my router.put function. It accepts two parameters, with first being the first name that the user wants to change it to, and email to look up the user in the database.
router.put("/updateFirst/:first/:email", function(req, res) {
console.log("------------update first hit------------");
db.User.getUserByEmail(req.params.email)
.then(res => {
console.log("updateFirst res: " + res);
})
})
Any help is appreciated.
EDIT: This is my getUserByEmail function
module.exports.getUserByEmail = function (email, callback) {
console.log("getUserByEmail", email)
var query = { email: email };
console.log(query);
return User.findOne(query, callback);
};

Related

appleAuthRequestResponse returning null for fullName and email

I am confused why me below snippet of code is showing null for email and fullName in console after user is authenticated successfully. I have read the documentation carefully and tried every possible thing I could. Any help would be highly appreciated.
async function onAppleButtonPress() {
// performs login request
const appleAuthRequestResponse = await appleAuth.performRequest({
requestedOperation: AppleAuthRequestOperation.LOGIN,
requestedScopes: [AppleAuthRequestScope.EMAIL, AppleAuthRequestScope.FULL_NAME],
});
//api getting current state of the user
const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user);
if (credentialState === AppleAuthCredentialState.AUTHORIZED) {
// user is authenticated
console.log("email is",appleAuthRequestResponse.email);
console.log("full name is",appleAuthRequestResponse.fullName);
}
}
You can still retrieve the e-mail from the identityToken provided by appleAuthrequestResponse with any jwt decoder like jwt-decode
const {identityToken, nonce, email} = appleAuthRequestResponse
const {email} = jwt_decode(identityToken)
console.log(email)
Apple only returns the full name and email on the first login, it will return null on the succeeding login so you need to save those data.
To receive these again, go to your device settings; Settings > Apple ID, iCloud, iTunes & App Store > Password & Security > Apps Using Your Apple ID, tap on your app and tap Stop Using Apple ID. You can now sign-in again and you'll receive the full name and `email.
Source here.

lucene query filter not working

I am using this filter hook in my Auth0 Delegated Administration Extension.
function(ctx, callback) {
// Get the company from the current user's metadata.
var company = ctx.request.user.app_metadata && ctx.request.user.app_metadata.company;
if (!company || !company.length) {
return callback(new Error('The current user is not part of any company.'));
}
// The GREEN company can see all users.
if (company === 'GREEN') {
return callback();
}
// Return the lucene query.
return callback(null, 'app_metadata.company:"' + company + '"');
}
When user logged in whose company is GREEN can see all users. But when user logged in whose company is RED can't see any users whose company is RED.
I need to make this when user logged in, user should only be able to access users within his company. (except users from GREEN company).
But above code is not giving expected result. What could be the issue?
This might be related to a little warning note on the User Search documentation page
Basically they don't let you search for properties in the app_metadata field anymore. Unfortunately, this change was breaking and unannounced.
We had to make changes to our API so that we keep a copy of the app_metadatas in a separate database and convert lucene syntax to MongoDB queries, so that we can query by a chain of user_id:"<>" OR user_id:"<>" OR ....
One caveat though, you can't pass a query that's longer than 72 user_ids long. This number is so far undocumented and obtained empirically.
Also, you can't rely on Auth0's hooks to add new users to your database, as these don't fire for social logins, only for Username-Password-Authentication connections.
I hope this gave you some explanation as for why it wasn't working as well as a possible solution.
If I were you, I would look for an alternative for Auth0, which is what we are currently doing.
I finally ended up with this solution.
Used search functionality to filter users. I had to change below two files.
fetchUsers function in client\actions\user.js
changed
export function fetchUsers(search = '', reset = false, page = 0)
to
export function fetchUsers(search = '#red.com', reset = false,
page = 0)
AND
onReset function in client\containers\Users\Users.jsx
changed
onReset = () => { this.props.fetchUsers('', true); }
to
onReset = () => { this.props.fetchUsers('#red.com', true); }

Deny access for user/role with ACL

Is there any way of using ACL in Parse Server to deny access to items for a specific user or role?
Say I have a social networking app where users post updates. I have a role called all_users which all registered users are added to. All updates are readable by this role, EXCEPT users that the author has blocked.
I can grant read and write access to users/roles, but removing both read and write access through the Parse Dashboard removes the entry completely.
Tips would be greatly appreciated.
I wasn't 100% sure the answer, so I did what I usually do, make a unit test to figure it out.
As it happens, I am working on a PR to create an 'all user role' that will improve on your current solution for that, especially if your social network takes off and you have many many users.
See the issue: https://github.com/parse-community/parse-server/issues/4107
You can track the current state of my solution (which currently works, but isn't ready to merge just yet) here: https://github.com/parse-community/parse-server/pull/4111
But all I'm working on is the 'all user role' case, not the 'deny a user' case you need.
What I did to test your question was extend the unit test from my pr to address your particular (interesting) use case:
it('should respect for read.', function (done) {
let role, user;
const userP = new Parse.User()
.set('username', 'userA')
.set('password', 'password')
.save()
.then((user) => Parse.User.logIn(user.get('username'), 'password'));
const roleP = new Parse.Role('aRole', new Parse.ACL())
.save();
Parse.Promise.when(userP, roleP)
.then((newUser, newrole) => {
user = newUser;
role = newrole;
const acl = new Parse.ACL();
acl.setRoleReadAccess(role, true);
return new Parse.Object('Foo')
.setACL(acl)
.save();
})
.then(() => new Parse.Query('Foo').first())
.then((obj) => {
expect(obj).not.toBeDefined();
return new Parse.Query(Parse.Role)
.equalTo('name', '_All_Role')
.first()
})
.then((allRole) => {
expect(allRole).toBeDefined();
const roles = role.relation('roles');
roles.add(allRole);
return role.save(null, { useMasterKey: true });
})
.then(() => new Parse.Query('Foo').first())
.then((obj) => {
expect(obj).toBeDefined();
const acl = obj.getACL();
acl.setReadAccess(user.id, false); // <--- this is what you want!!!
console.log(acl);
const valid = obj.setACL(acl);
expect(valid).toBe(true);
return obj.save();
})
.then(() => new Parse.Query('Foo').first())
.then((obj) => {
expect(obj).not.toBeDefined(); // <--- but this fails :(....
done();
})
.catch(done.fail);
});
As I suspected, the test failed. I'm not an expert on parse permission (though learning) but my current understanding is that in there is no concept of precedence, so once you have added the permission through your everyone group, there is no way to 'deny'. In other words, the current permission model is that permissions are added, not explicitly denied.
Your use case is compelling though so finding a way to accommodate your use case would be interesting. As is often the case though, either you're going to need to figure out how to add it in such a way that it would be acceptable for the general use cases too or recruit someone who can (not volunteering, my dance card is full :).

How to use DirtyKeys to know if "email" field in PFUser has been modified?

I'm using cloudcode of Parse-Server and mailgun to send email-verification Code to users that signup or change their email.
The BeforeSave Method :
Parse.Cloud.beforeSave(Parse.User, function(request, response) {
var verificationCode = Math.floor(Math.random()*999999);
var text = "Hi ... this is a verification code:" + verificationCode;
var data = {
from: 'WBP Team <info#test.eu>',
to: request.object.get("email"),
subject: 'Please verify your e-mail for you Account',
text: text
};
mailgun.messages().send(data, function (error, body) {
if (error) {
response.error("Email not sent..."+error);
}else{
var user = Parse.User.current();
user.set("emailVerificationCode", verificationCode);
user.save();
response.success("Email Sent");
}
console.log(body);
});
});
Now the email is sent everytime the user modify any filed. But I would like to use the method only when the user change the email.
This has been answered here: you just check if request.object.dirtyKeys() contains "email"; if this is the case, the email property was changed, and you can send your verification.
Note that this check also catches the first saving (i.e. creation) of a user; if you want to avoid sending a mail then, you can use request.object.isNew() to find out if the operation is a create or an update.

How to login not with a username but a different selector?

I want to implement "Login with username or customerID (never both) and password" where I let the user enter a username or their customerID in the first field and password in the second field.
The accounts-password package lets me login using a username by calling
Meteor.loginWithPassword(<username>,<password>);
OR
var selector = {username: <username>}
Meteor.loginWithPassword(selector, <password>);
I tried to select the user using the selector.
var selector = {customerID: <customerID>}
But it seems that I can use only _id,username or email in this way to select a user or I get a Match failed error.
Isn't there any other method to log a user in without a username, _id or email?
This workaround is the farthest I have reached:
1. First retrieve the username or _id using customerID.
2. Then login using the retrieved username/_id and password.
//SERVER
Meteor.methods({
findIDFromCustomerID: function(customerID){
user = Meteor.users.findOne({customerID: customerID});
if(user){
return user._id;
}else{
throw new Meteor.Error(403,"User not found");
}
}
});
//CLIENT
Meteor.call('findIDFromCustomerID',<customerID>,function(err,data){
if(data && !err){
Meteor.loginWithPassword({id: data}, <password>);
}
});
But in this, I feel that I leave a small window for the misbehaving users.