Parse.com - Cloud function call from another cloud function makes request.user null - parse-platform

I've written a Cloud function ("newUserLog") that i call from the iOS SDK and everything works correctly. the cloud function heavily uses "request.user".
Now i've made another cloud function ("doStats"), and in that function at some scenarios, i need to call "newUserLog" function.
I do this with
Parse.Cloud.run("newUserLog").then(function(logCreated){
...
});
But at "newUserLog" function, request.user is null.
What is the best practice to solve this kind of problem? i know i can pass the request.user pointer and fetch it again, but i'm afraid it's less secure and i'll have to do alot of refactoring.
Is there a simple way transferring request.user from one cloud function to another?
Thanks alot
Or

Don't call one cloud function from another if you can help it. Instead, create plain JS functions which hold your reusable logic and pass them a set of parameters. This is much easier to manage and much clearer about what those functions actually need in order to operate.

change newUserLog code to be something like:
var user;
if( request.User )
{
user = request.User;
}
else
{
user = new Parse.User();
user.id = request.params.userId;
}
In both cases you have basically the shell of the user, and will need to perform a fetch if you want the rest of the data.
Change your doStats method to pass in the userId as a parameter to the other cloud code function:
Parse.Cloud.run("newUserLog", {userId:request.User.id});
or
var user = request.User;
Parse.Cloud.run("newUserLog", {userId:user.id});
That being said, you could consider creating a function that gets called by both doStats and newUserLog that is not a cloud code function, and pass relevant parameters into it from either of your cloud code functions.

Related

How to work with multiple variables in Cypress?

tl;dr: can cypress variables be stored in some accesible place (like this or something similar) or do I have to get into an endless callback cycle if I want to access all of them for a single usage?
Long story:
the app I'm trying to cover with cypress tests runs on many different datasets so in order to prepare the test data before the test, I usually make few API calls and I'd like to work with their results:
Example:
The test should cover a "delete task" functionality. As test data, I want to create a task beforehand over our API. To do this, I need to make these calls:
Call ".../users/me" to get my userId (one of required params)
Call ".../users" to get a list of all users for particular dataset (first id is used to filter another, that is then used for assigneeId, another required param)
Call ".../tasks" with previous id's as required parameters
I currently have custom commands that handle those specific api calls while returning the result. I then call those commands and save their return as cypress variable. Should I want to do the third api call, I have to do something like this:
cy.getUserID().then((userId) => {
cy.wrap(userId).as('userId')
})
cy.getAllUsersForTenant().then((users) => {
cy.get('#userId').then((userId) => {
const result = users.find((escalationUserId) => escalationUserId !== userId)
cy.wrap(result.id).as('assigneeId')
})
})
cy.get('#assigneeId').then((assigneeId) => {
cy.get('#userId').then((userId) => {
// do the POST call with both assigneeId and userId available
})
})
Right now it's not really a big deal but I can imagine that I'l need more than 2 variables, will I have to add more nested callbacks or is there a way to store those variables at one accessible place?
I sort of figured it out by looking at other tickets - if I use function() instead of arrow functions, it is possible to share this context.

How can I call a back-end service function from the Success function of the MainCell in the front-end in a JAMstack RedwoodJS app?

I'm using RedwoodJS.
My front-end (what they call the "web" "side") has (among other files) a HomePage.ts and MainCell.ts, and then the Success function in MainCell calls a 3rd party API.
Everything is working.
However, I now want to start caching the results from the 3rd party API.
I've created a database table and a back-end "service" called cachedQueries.ts (using Prisma), which has:
export async function getFromCacheOrFresh(key: string, getFresh: Function, expiresInSec: number): Promise<any> {
const nowMoment = dayjs.utc();
const nowStr = nowMoment.format(dbTimeFormatUtc);
const cached = await getCachedQuery({ key, expiresAtCutoff: nowStr });
console.log('getFromCacheOrFresh cached', cached);
if (cached) {
const cachedValueParsed = JSON.parse(cached.value);
console.log('cachedValueParsed', cachedValueParsed);
return cachedValueParsed;
} else {
const fresh = await getFresh();
saveToCache(key, JSON.stringify(fresh), expiresInSec);
return fresh;
}
}
I have proven that this cachedQueries.ts service works and properly saves to and retrieves from the DB. I.e. for any 3rd-party APIs that can be called from the back-end (instead of from the front-end), the flow all works well.
Now my challenge is to enable it to cache front-end 3rd-party API queries too.
How I can call my getFromCacheOrFresh function from the Success function of the MainCell in the front-end?
I must be confused about Apollo, GraphQL, RedwoodJS, Prisma, etc relate to each other.
P.S. Client-side caching will not suffice. I really need the 3rd-party API results to be saved in the DB on my server.
I eventually figured it out.
I created a new cell called GeoCell, and I'm returning an empty string for each function of GeoCell (Success, Loading, Empty, and Failure).
That feels weird but works.
What was unintuitive to me was the idea that I was required to use a JSX component (since Apollo would never let me query or mutate GraphQL outside of a JSX component), but I didn’t want the cell component to actually display anything… because all that it needs to do in its Success is call a helper function that affects elements aleady created by a different cell (i.e. addMarkerAndInfoWindow affects the div of the existing Google Map but doesn’t display anything where the GeoCell was actually located).
As https://stackoverflow.com/a/65373314/470749 mentions, there's a related discussion on the Redwood Community Forum: Thinking about patterns for services, GraphQL, Apollo, cells, etc.

How does one read the data value from a Function outside FunctionCallbackInfo?

When I create a function like this:
v8::Function::New(<Isolate>, <C_Function>, <Data_Value>);
The Data_Value that I supply is useful for many things and I can access that when the function is called, with something like FunctionCallbackInfo->GetData().
But I have found no way to get back this data in a different scenario. Let's say I store that Function in a Persistent object, and then I would like to read which data is currently bound to it. Any ideas?
I don't think it's exposed via the API.
But there's an alternative:
manually construct a v8::FunctionTemplate
set its ->InstanceTemplate()->SetInternalFieldCount(num_fields)
get the v8::Function from the template with template->GetFunction(context),
now you should have function->InternalFieldCount() == num_fields
you can use function->SetInternalField(index, value) and function->GetInternalField(index) to store any data you want.
For complete examples, search for "SetInternalFieldCount" in V8's test-api.cc.

How can I get a user with a given facebook id using cloud code?

My app requires facebook login, so it is supposed I have all facebook ids from my users. What I want to o in cloud code is a function that given a facebook id (a string), returns the user (or null if no exists). The problem I see is that it seems the facebook id is inside a json structure in the authData column, but I have no idea how to create a query to access to that information. I found this: https://www.parse.com/questions/how-to-get-the-facebook-id-of-an-pfuser-from-a-pfquery-in-ios but no idea about how to use it.
Can you help me with the function I want to create? Thanks in advance.
My comment on Eric's answer expresses my concerns around security, but the cloud-code BeforeSave() function to address my concerns really isn't difficult... for simple use-cases:
Parse.Cloud.beforeSave("MyObject", function(request, response) {
request.object.set("owner_facebook_id", request.user.get("authData").facebook.id);
response.success();
});
In your case, MyObject is the user class, and as long as no users can modify properties on another user object, than this will work pretty well.
However, for the app I was working on, we allowed any user to "like" an object, which incremented a "number_of_likes" property on the object. At that point, this became more tricky, because the user making that request was not, in fact, the owner of the object, so their Facebook_id properties wouldn't have matched.
The work-around was to try and detect whether or not the object had previously existed, and then just make sure the Facebook_id never changed after it was originally created.
We had to access the ORIGINAL object and make sure the newly-saving object had the same Facebook id... it was not exactly trivial, and that lookup actually counts against your request limit. This, combined with a few more edge-cases, caused us to ultimately abandon Parse for that project.
The problem with using authData is that you need a valid active session of that user (or use your master key) to access the data.
If you don't already have a large amount of users, I would recommend creating a new column in your User class that stores the Facebook ID so you can query for it later. That way, you could do something like:
var query = new Parse.Query("User");
query.equalTo("facebookId", request.params.facebookId);
query.find({
success: function(results) {
// do something with the resulting user at results[0], if found
},
error: function() {
response.error("lookup failed");
}
});

Ajax / Json How to run an INSERT/UPDATE into mysql

Again related with my weekend project, I'm trying to learn a bit more of web-development. So I'm putting in the list of features i want to implement, some stuff i absolutely have no idea how to do.
I've been reading tutorials on how to use ajax, but i can't find a simple one, that i can copy-paste (with one or two changes) to see it work before i go into the how it works.
What I've been searching is just a simple example on an ajax function, that triggers a mysql insert or update. Anyone as a simple example on how to do this? I think it would prove a nice start to learn it. (Ajax or Json are both ok).
Correct me if I'm mystaken: I'm basing myself on this tutorial. So as obviously the client side doesn't have access to database calls, what I should do, would be something like creating a code snippet to add stuff to the database right? For example create an "addcomment.php" that can be called with xhr.open(GET, "addcomment.php?comment=mycomment", true);
Sounds like you got it right. Use Ajax to call a server side script which then does the database work for you.
A good setup is to use a framework like jQuery on the client side. This framework will encode and decode JSON automatically. On the server side you could create a class that handles all the ajax (or rather, ajaj, since we are using JSON) requests. Here is a short PHP file that shows the general idea. Add more elements to the functionMap array, and add the respective functions to the class.
class Ajaj{
private $callback = "";
private $functionMap = array( "select" => 'getIt');
function Ajaj(){
if(array_key_exists('jsoncallback',$_GET)){
$this->callback=$_GET['jsoncallback'];
}
}
function parse(){
echo "$this->callback(";
if(array_key_exists('action', $_POST)){
$action = $_POST['action'];
if(array_key_exists($action, $this->functionMap)){
echo $this->functionMap[$action];
}
}else{
echo "{}";
}
echo ")";
}
function getIt(){
return json_encode(//get the database stuff here);
}
}
$ajaj = new Ajaj();
$ajaj->parse();

Resources