I'm testing the Assistant feature of using Webhooks and by some reason I don't receive any output. My Cloud-Function code looks so:
async function main(params) {
switch (params.action){
case 'bills':
var resp_final = [
{
value: 'Rechnung RN1074801326',
datum: '28.02.2021',
total_preis: '710€'
},
{
value: 'Rechnung RN8243559014',
datum: '01.03.2021',
total_preis: '130€'
}
];
return { elements: resp_final };
break;
//DEFAULT RETURN
default:
return {no: 'default'};
}
}
And I invoke it from the assistant like so:
As you can see, only [0].value gets printed to the console. Even if I don't specify any attribute there is still no result on the console. However, I tested the Cloud function with parameters and it's working (it shows the array without problems). Any reason why this might occurs?
Related
I'm trying to display Firestore data in a Flutter app. To do that, I created a Firebase function like the following:
exports.getHouses = functions.https.onCall((data, context) => {
let pathBeginning = "users/";
console.log(data.userID);
let path = pathBeginning.concat(data.userID, "/houses");
let houses = [];
admin.firestore().collection(path).get().then(snapshot => {
console.log("COLECTION WHERE DOCUMENTS ARE RETREIVED:");
console.log(path);
snapshot.forEach(doc => {
let newHouse = {
"id": doc.id,
"address": doc.data().address
}
houses = houses.concat(newHouse);
});
console.log("THE FOLLOWING LOG SHOULD RETURN THE FULL LIST OF HOUSES:")
console.log(houses);
return houses;
}).catch(reason => {
response.send(reason);
});
});
I think this part works properly, because logs in Firebase look exactly as expected:
Firebase logs
The problem happens when I try to print this data in my Flutter app. To do so, I use the following code:
Future<void> listHouses() async {
var parameters = {
"userID": "1"
};
HttpsCallable getHouses = FirebaseFunctions.instance.httpsCallable("getHouses");
await getHouses.call(parameters).then((HttpsCallableResult response) {
print(response.data);
});
}
When called the funtion, it always returns null, even when Firebase log displays everything properly.
I would appreciate if anyone can help me solving this issue. Thank you in advance.
You're missing a return in front of your get() call. Without that, the Cloud Functions container doesn't know about the asynchronous get() operation and thus will/may terminate the function before loading the data completes.
To fix this, add return:
return admin.firestore().collection(path).get().then(snapshot => {
...
This is an extremely common problem within Cloud Functions and when dealing with asynchronous APIs in general, so I recommend taking a moment to read the Firebase documentation on terminating functions and watching the video series linked in there.
Hi I'm new to ionic/angular and I'm reading someone else code and came across the function below in the Service
makePostRequest(100)
public makePostRequest(param) {
return this.http.post('/sample/api', param);
}
Does this mean param is sent as json body or just a value, online documentation just shows json body as the argument not a single value. Can someone help me with this
Thanks in advance.
The post body is sent as serialized parameters as explained here.
In the example you have provided, they are calling the makePostRequest() function and providing an argument of 100. When the makePostRequest() function runs, it takes that value from the argument and sets it as a parameter which is then used to populate the body in the POST request.
You can still send single values as you would multiple values with something similar to this:
sendData() {
const data = {
number: 100
};
return this.http.post('myurl.com', data);
}
Or for multiple:
sendData() {
const data = {
number: 100,
fruit: 'banana'
};
return this.http.post('myurl.com', data);
}
You can of course pass multiple arguments if you have parameters set up to accept them:
sendData(body: { score: number, fruit: string }) {
return this.http.post('myurl.com', body);
}
I have been on this for a while. The problem with is is that this line of code never get executed let userSchool = SchoolDb.findOne({slug: Session.get('ReceivedSlug')}); When I logged on the console I see the the slug is dynamic as it is suppose to be pull the record from the db. What am I to do right?
The oncreated template
Template.view.onCreated(function () {
Session.set('ReceivedSlug', FlowRouter.getParam('myslug'));
this.autorun(function () {
Meteor.subscribe('SingleSchool', Session.get('ReceivedSlug'));
});
});
The helper function
singleSchool: function () {
if (Meteor.userId()) {
console.log('reactive this ---- ' +Session.get('ReceivedSlug'));
let userSchool = SchoolDb.findOne({slug: Session.get('ReceivedSlug')});
if (!userSchool) {
Bert.alert('School not present', 'danger', 'growl-top-right');
} else {
console.log('school name ----' +userSchool.slug);
return userSchool;
}
}
},
Can you please check whether the subscription has fetched data. Also console out inside publish that whether data gets published when slug changed.
Use below code to check if subscription is working
Meteor.subscribe('SingleSchool', Session.get('ReceivedSlug'), {
onReady: function(){
console.log(SchoolDb.find({}).fetch());
}
});
I have an issue saving changes to an object from a Cloud Code function.
I have a collection called Character and one record inside it.
This Character record has an ACL with Public Read, and Private Write Access by a specific ParseUser (6MwfSLdAxd).
In Unity, I authenticated the user and I then call the Cloud Code function as follows:
ParseCloud.CallFunctionAsync<Character>("startBattle", null).ContinueWith(t =>
{
Debug.Log("I got here...");
Debug.Log(t.Result.ClassName);
});
In my Cloud Code function, I grab the first character in the collection (ignoring checking if it belongs to this user, because at the moment there is only one and it DOES belong to this user - there's only one user too).
var Character = Parse.Object.extend("Character");
Parse.Cloud.define("startBattle", function (request, response) {
var user = request.user;
if (user == null)
{
return response.error("You must login before you can battle!");
}
var characterQuery = new Parse.Query(Character);
characterQuery.first()
.then(
function (character) {
character.set("name", "Cloud Code sucka");
character.save().then(function(character) {
return response.success(character);
});
},
function (error) {
return response.error("You must create a character before you can battle! " + error);
}
)
});
However, I simply cannot save any changes to this character. All the documentation and forum posts I've found suggest that if you call a Cloud Code function when authenticated then that function should have the same level permissions as the user calling it.
The only time this code works is if I set the ACL of the character to Public Write.
Does anyone have any ideas why this wouldn't be working?
Note: Worth noting that I can see in the server logs that the Cloud Code function IS being called by the authenticated user 6MwfSLdAxd as I get this error (if I add a response.error call):
error: Failed running cloud function startBattle for user 6MwfSLdAxd with:
Input: {}
Error: {"code":141,"message":"Messed up: [object Object]"} functionName=startBattle, code=141, message=Messed up: [object Object], , user=6MwfSLdAxd
error: Error generating response. ParseError { code: 141, message: 'Messed up: [object Object]' } code=141, message=Messed up: [object Object]
[object Object]
[object Object]
After some extensive searching I've now found the solution to this.
For anyone else encountering the same issues, you should be aware that whilst Parse.com used to run Cloud Code functions in the context of the user that called them (afaik), self-hosted Parse Servers do not.
In order to call queries or saves in the context of a user you must pass their session token as shown below. I hope this saves someone the hours of confusion I went through!
var MyObject = Parse.Object.extend("MyObject");
Parse.Cloud.define("myCloudFunction", function (request, response) {
var user = request.user;
var sessionToken = user.getSessionToken();
var query = new Parse.Query(MyObject)
.find({ sessionToken: sessionToken })
.then(
function (object) {
object.set("someKey", "someValue");
return object.save(null, { sessionToken: sessionToken });
}
)
.then(
function (object) {
return response.success(object);
},
function (error) {
return response.error(error.message);
}
);
});
For further context see:
https://github.com/ParsePlatform/parse-server/wiki/Compatibility-with-Hosted-Parse#cloud-code
There are restful APIs, for instance:
/players - to get list for all players
/players{/playerName} - to get info for specific player
and I already have a function using ng-resource like:
function Play() {
return $resource('/players');
}
Can I reuse this function for specific player like:
function Play(name) {
return $resource('/players/:name', {
name: name
});
}
so I want to...
send request for /players if I didn't pass name parameter.
send request for /players/someone if I passed name parameter with someone
Otherwise, I have to write another function for specific play?
Using ngResource it's very, very simple (it's basically a two-liner). You don't need even need to create any custom actions here*.
I've posted a working Plunkr here (just open Chrome Developer tools and go to the Network tab to see the results).
Service body:
return $resource('/users/:id/:name', { id:'#id', name: '#name' })
Controller:
function( $scope, Users ){
Users.query(); // GET /users (expects an array)
Users.get({id:2}); // GET /users/2
Users.get({name:'Joe'}); // GET /users/Joe
}
of course, you could, if you really wanted to :)
This is how I did it. This way you don't have to write a custom resource function for each one of your endpoints, you just add it to your list resources list. I defined a list of the endpoints I wanted to use like this.
var constants = {
"serverAddress": "foobar.com/",
"resources": {
"Foo": {
"endpoint": "foo"
},
"Bar": {
"endpoint": "bar"
}
}
}
Then created resources out of each one of them like this.
var service = angular.module('app.services', ['ngResource']);
var resourceObjects = constants.resources;
for (var resourceName in resourceObjects) {
if (resourceObjects.hasOwnProperty(resourceName)) {
addResourceFactoryToService(service, resourceName, resourceObjects[resourceName].endpoint);
}
}
function addResourceFactoryToService (service, resourceName, resourceEndpoint) {
service.factory(resourceName, function($resource) {
return $resource(
constants.serverAddress + resourceEndpoint + '/:id',
{
id: '#id',
},
{
update: {
method: 'PUT',
params: {id: '#id'}
},
}
);
});
}
The nice thing about this is that it takes 2 seconds to add a new endpoint, and I even threw in a put method for you. Then you can inject any of your resources into your controllers like this.
.controller('homeCtrl', function($scope, Foo, Bar) {
$scope.foo = Foo.query();
$scope.bar = Bar.get({id:4});
}
Use Play.query() to find all players
Use Play.get({name:$scope.name}) to find one player