Creating new users without resetting current user session - parse-platform

In my Parse web app, I have a user management page that is accessible to administrators. This page allows admins to create new user accounts.
To create the accounts, I use Parse.User.signUp().
It works great, but it has the nasty side effect of resetting the current user session, which logs out the admin who created the new user account.
This is actually the documented behaviour of User.signUp():
This will create a new Parse.User on the server, and also persist the session in localStorage so that you can access the user using #current.
But I want to create new users without changing the current user. How do I do this?

Before creating the new user account with User.signUp, save the current user's sessionToken. Then, once the new user has been created, restore the session with User.become:
var sessionToken = Parse.User.current().getSessionToken();
Parse.User.signUp(username, password).then(function(newUser) {
Parse.User.become(sessionToken);
});

I can create a 'Parse Cloud' method that allows you use the 'Master Key' and call it from the SDK using the Cloud.
Parse.Cloud.define('salvarUsuario', function(request, response) {
var nomeCompleto = request.params.nomeCompleto;
var Email = request.params.Email;
var Username = request.params.Username;
var cpf = request.params.cpf;
var Password = request.params.Password;
var funcionarioBool = request.params.funcionarioBool;
var ativo = request.params.ativo;
var primeiroAcesso = request.params.primeiroAcesso;
var tipoAcesso = request.params.tipoAcesso;
var medicoBool = request.params.medicoBool;
//Parâmetros de controle
var fotoSelecionada = request.params.fotoSelecionada;
var usuario = new Parse.User();
usuario.set("nomeCompleto", nomeCompleto);
usuario.set("email", Email);
usuario.set("username", Username);
usuario.set("cpf", cpf);
usuario.set("password", Password);
usuario.set("funcionarioBool", funcionarioBool);
usuario.set("ativo", ativo);
usuario.set("primeiroAcesso", primeiroAcesso);
usuario.set("tipoAcesso", tipoAcesso);
usuario.set("medicoBool", medicoBool);
if(medicoBool) {
var medicoId = request.params.medico;
var Medico = Parse.Object.extend("Medico");
var medicoPointer = Medico.createWithoutData(medicoId);
usuario.set("medico", medicoPointer);
}
if(fotoSelecionada) {
var bytes = request.params.bytesFoto;
var file = new Parse.File("foto.png", bytes, "image/png");
usuario.set("foto", file);
}
usuario.save(null, {
useMasterKey: true,
success: function(salvoUsuario){
// The user was saved correctly
response.success("1");
},
error: function(error){
response.error("Erro ao criar novo usuário");
}
});
});

Related

Parse Cloud Code Setting Relation On User Class

I have an issue with not getting some cloud code to run in Parse. Currently, I pass an objectId of another user who I want to set a review for. In client side, I am saving the review, and capturing that object. I pass that as well up to cloud code. Both show up there, but I cannot figure out the right way to set the relation on this user and apply that review that was created. Code snip is below. Any help would be appreciated before I bang my head against a wall.
Parse.Cloud.define("addReview", async (request, response) => {
let { userObjId, reviewObj } = request.params;
const query = new Parse.Query(Parse.User);
//get the user object to post review of
try{
let object = await query.get(userObjId, {useMasterKey: true});
console.log(object);
console.log("running");
object.set('Reviews', new Parse.Object(reviewObj));
object.save(null, { useMasterKey: true })
return ("saved relation and updated reviews");
} catch (err){
throw new Error(err.message)
}
});
I assume
reviewObj is the review object, the user recently created.
and in your User class, you got a to-many-relation to Review class, named 'Reviews'.
First I'd suggest to name your user object user instead of object, to make it clearer what you're dealing with and make your code easier to understand.
Since you said, the review object is already successfully saved on server side, I'd recommend to transmit only the reviewId in your request.
To add an object to a relation, you first need to get the relation property of your user object:
const reviewsRelation = user.relation('Reviews');
Then to add the object to the relation just call:
reviewsRelation.add(user);
In total, your snippet should look like this:
Parse.Cloud.define("addReview", async (request, response) => {
let { userObjId, reviewObjId } = request.params;
const userQuery = new Parse.Query(Parse.User);
const reviewQuery = new Parse.Query(Parse.Review);
//get the user object to post review of
try{
let user = await userQuery.get(userObjId, {useMasterKey: true});
let review = await reviewQuery.get(reviewObjId, {useMasterKey: true});
console.log(user);
console.log("running");
const reviewsRelation = user.relation('Reviews');
reviewsRelation.add(review);
user.save(null, { useMasterKey: true })
return ("saved relation and updated reviews");
} catch (err){
throw new Error(err.message)
}
});

Parse Cloud Right Query to retrieve Friendslist and not (like Instagram)

I have the class "Users" the default of Parse Dashboad. I have also the class "Friends", where I store the friendships between users like this:
There are two columns, "toUser" and "fromUser", which are showing who of the two users sent the friend request. These two columns are Pointers(Pointer<_User>) to the Users Class.
My concept is to retrieve two lists:
1. Friendlist for the logged in user
2. Userlist of users (who are not friends with the logged in user)
What would be the appropriate queries for that?
The first one logically should not scan all the class Users because it may slow down the perfomance of the app which is using Ionic 3 and Angular 4
Thank you
you don't need another class to do so all you need is a relation column in the default user class
to add new friend you just need the following code
var friendtoadd
//this is the friend object from parse user class you want to add you can get it by anyway you want
var currentUser = Parse.User.current();
var relation = currentUser.relation("friends");
relation.add(friendtoadd)
currentUser.save();
to retrieve array of friends of logged in user you can use the following code
var currentUser = Parse.User.current();
var friendRelation = currentUser.relation('friends');
var env = this
friendRelation.query().find({
success: function(users) {
for (var i = 0; i< users.length; i++) {
var object = users[i];
env.friends.push(object)
console.log(env.friends)
}
}
});
// you should define friends = []; in the class
if I understood your question right you want to find the friend requests you sent, or the ones you received. because I don't see where you made a relation between the user and his friends.
this is the code if you want to do this using cloud code:
First I validated the parameters of the friendRequest being saved :
Parse.Cloud.beforeSave("Friends", function(request, response){
var friendRequest = request.object;
if (!friendRequest.has("toUser") || !friendRequest.has("fromUser")) {
response.error("Invalid parameters");
return;
}
response.success();
});
then I created two cloud functions, one for retrieving the sentRequests:
Parse.Cloud.define("getSentRequests", function(request, response){
var query = new Parse.Query("Friends");
query.equalTo("fromUser", request.user);
if (!request.master) {
query.find({ sessionToken: request.user.getSessionToken() }).then(function(friends){
response.success(friends);
});
}else{
query.find({useMasterKey:true}).then(function(friends){
response.success(friends);
});
}
});
and you can call this either from a logged in user or using the masterKey if you want, and the other query is for the recievedRequests:
Parse.Cloud.define("getRecievedRequests", function(request, response){
var query = new Parse.Query("Friends");
query.equalTo("toUser", request.user);
if (!request.master) {
query.find({ sessionToken: request.user.getSessionToken() }).then(function(users){
response.success(users);
});
}else{
query.find({useMasterKey:true}).then(function(users){
response.success(users);
});
}
});

Visual Studio Online SDK

I am working on a project where I have a requirement to create workitem on Visual Studio Online instance. I am using personal access token. This will set CreatedBy as my name (Expected behavior). I am considering to use Oauth2; However, I am not sure if there's the way to do this Server-to-Server (Non-Interactive)? Any suggestions thoughts?
var personalAccessToken = "PAT Value fro Config";
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalAccessToken))));
return client;
PAT's are created in Security context of the user. I need to find a way to use Oauth without having to involved UI. So I'm looking for Server-to-Server Auth.
object[] patchDocument = new object[5];
patchDocument[0] = new { op = "add", path = "/fields/System.Title", value = bugTitle };
patchDocument[1] = new { op = "add", path = "/fields/Microsoft.VSTS.TCM.ReproSteps", value = bugReproSteps };
patchDocument[2] = new { op = "add", path = "/fields/Microsoft.VSTS.Common.Priority", value = "1" };
patchDocument[3] = new { op = "add", path = "/fields/Microsoft.VSTS.Common.Severity", value = "2 - High" };
patchDocument[4] = new { op = "add", path = "/fields/System.IterationPath", value = deserializeIteration };
//System.IterationPath
string postUrl = $"{_vsoInstanceUrl}/DefaultCollection/ProjectName/_apis/wit/workitems/$Bug?api-version=1.0";
await ExecutePatch(patchDocument.ToArray(), postUrl, "application/json-patch+json");
No there is no Server-to-Server OAuth support. If you use the .NET Client Object Model you can leverage Impersonation support.
If your account has "Act on behalf of others" permissions you can also achieve a "User X via YourAccount".

parse.com inherited ACL + roles - afterSave or beforeSave, tricky scenario

Here's what I am trying to achieve but somehow I am stuck and I am not sure what's the proper approach, I cannot find any good examples of such case so I am seeking your help.
Each registered user can add new object to class "List". Once the new item is created I call afterSave function and assign proper ACL creating new role ("membersOf_" + List.id). Next, user can add new object to class "Items", which will store List.id as a reference and ACL for item should be inherited from list. Lists and Items can be shared between multiple users of their choice. There are few problems in such case:
when creating new List, I need to create new role and assign creator to it and add such role to created List
when creating new Item, I need to pass List.id as a payload and validate with cloud code if current user can create such item (assigned to specified List) by checking first if he has proper permissions to List
if permission check is ok, I need give this item the same ACL as List has and proceed with saving
Here's my afterSave for List, creating role properly and assigning ACL to List object. (1) I am missing adding this role to user (creator)
Parse.Cloud.afterSave("List", function(request, response) {
var list = request.object;
var user = Parse.User.current();
if (list.existed()) {
// quit on update, proceed on create
return;
}
var roleName = "membersOf_" + list.id;
var listRole = new Parse.Role(roleName, new Parse.ACL(user));
return listRole.save().then(function(listRole) {
var acl = new Parse.ACL();
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setReadAccess(listRole, true);
acl.setWriteAccess(listRole, true);
var itemData = new Parse.Object("List", {
ACL: acl
});
return itemData.save('objectId', list.id);
});
// to do - add user to this role too
});
Here's my Item beforeSave to validate if user can actually create such object, I am checking if he can query the List table, if he get >0 results for such List that means he will be ok to adding an Item assigned to this List. (2) Missing ACL inheritance
Parse.Cloud.beforeSave("Item", function(request, response) {
var item = request.object;
var listId = request.object.get("list");
var user = Parse.User.current();
var List = Parse.Object.extend("List");
var query = new Parse.Query(List);
query.equalTo("objectId", listId);
query.first({
success: function(list) {
if (list.id) {
response.success();
}
else {
response.error('No such list or you don\'t have permission to perform this operation.');
}
},
error: function(error) {
response.error(error);
}
});
});
Can someone point me to the proper solution or help solve that puzzle? I am missing two things:
- (1) I need to add user (creator) to new role created in afterSave
- (2) I need to add the same ACL to Item, inherit it from List object
I have tried many things, passing ACL in afterSave for Item, modifying payload in beforeSave. Many different functions following documentation and different examples, but still no luck.
Any advice would be awesome!
Ok, I think I finally figured it out. Hopefully this will help someone in future.
Here are final beforeSave and afterSave functions adding user to specified role and assigning the same ACL to Item object
Parse.Cloud.afterSave("List", function(request, response) {
var list = request.object;
var user = Parse.User.current();
if (list.existed()) {
// quit on update, proceed on create
return;
}
var roleName = "membersOf_" + list.id;
var listRole = new Parse.Role(roleName, new Parse.ACL(user));
//+ adding user to role in this line:
listRole.relation("users").add(user);
return listRole.save().then(function(listRole) {
var acl = new Parse.ACL();
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setReadAccess(listRole, true);
acl.setWriteAccess(listRole, true);
var itemData = new Parse.Object("List", {
ACL: acl
});
return itemData.save('objectId', list.id);
});
// to do - add user to this role too
});
Parse.Cloud.beforeSave("Item", function(request, response) {
var item = request.object;
var listId = request.object.get("list");
var user = Parse.User.current();
// + modifying payload with the same ACL here
var acl = new Parse.ACL();
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setRoleWriteAccess("membersOf_" + listId, true);
acl.setRoleReadAccess("membersOf_" + listId, true);
item.set('ACL', acl);
var List = Parse.Object.extend("List");
var query = new Parse.Query(List);
query.equalTo("objectId", listId);
query.first({
success: function(list) {
if (list.id) {
response.success();
}
else {
response.error('No such list or you don\'t have permission to perform this operation.');
}
},
error: function(error) {
response.error(error);
}
});
});

Modifying Parse.User object before FIRST save

I'm working on an app and I need some changes to be made on new users registering during certain periods.
I've added a variable which I will change manually, and a check if that value is true or false.
This is my current code:
Parse.Cloud.beforeSave(Parse.User, function(request, status)
{
console.log("********************************************");
Parse.Cloud.useMasterKey();
var special = true;
if(special)
{
request.object.set("points", 1000);
request.object.set("role/objectid", "PZHTquGti0");
}else{
request.object.set("points", 0);
request.object.set("role/objectid", "TQyjIY59oL");
}
console.log("********************************************");
status.success("Job finished successfully!");
}); // end of Parse.define
This code errors out with "Uncaught Error: change must be passed a Parse.Object" and I've been looking through the documentation to find out how to change a value of a subclass of the User object, but have found none.
Also, this code will also run when updating a user, which I don't want it to do.
Any help is highly appreciated!
First of all for running the code on first save (insert), you can use request.object.isNew()
As the role column is a pointer, you should set an object & not the id string directly.
So create a new dummy object and assign the id to it.
Parse.Cloud.beforeSave(Parse.User, function(request, status)
{
console.log("********************************************");
Parse.Cloud.useMasterKey();
if(request.object.isNew()){ // Object Insert
var Role = Parse.Object.extend("_Role");
var role = new Role();
var special = true;
if(special)
{
request.object.set("points", 1000);
role.id = "PZHTquGti0";
request.object.set("role", role);
}else{
request.object.set("points", 0);
role.id = "TQyjIY59oL";
request.object.set("role", role);
}
}
else{ // Object Update
//Do nothing
}
console.log("********************************************");
status.success("Job finished successfully!");
}); // end of Parse.define

Resources