I'm having a problem with the URL of the Facebook Graph API. Is there any possibility to get all the fields of a Facebook post including reactions? I use the following URL for the posts:
https://graph.facebook.com/{pageName}/feed?access_token={access_token}
Now I'm getting data like this (which is quite nice):
{
"data": [
{
"id": "someId",
"from": {
"Name": "Page name",
"category": "Sports Team",
"id": "someId"
},
"message": "Hello world!",
[...]
"shares": {
"count": 1
},
"likes": {
"data": [
{
"id": "someId",
"name": "Some person"
}
]
}
},
[...]
]
}
As for now I have to get the reactions (LOVE, WOW, HAHA, SAD, ANGRY and THANKFUL) by downloading the json from the following URL for every single post (and this is very time consuming):
https://graph.facebook.com/v2.9/{postId}?access_token={access_token}&fields=reactions
The only problem is that I can't get the reactions when using the "normal" URL (without &fields). Is there any chance to get all information including reactions without having to add all the fields to &fields=from,message,likes,shares,reactions?
From CBroe's comment:
I had to pass all the fields I wanted to save to my DB in my URL:
https://graph.facebook.com/v2.9/{pageName}/feed?access_token={access_token}&fields=id,from,message,name,[...],likes,comments,reactions,shares
Related
I am using adaptive card templating in bot framework. When user selects a particular value from a dropdown, based on the selection, few input fields on the input form card should be auto populated. How to achieve this?
Based on the dropdown, if user chooses 'myself', his email id should be auto populated in his/her email address textbox(email address I can get from user profile stored in user state).
The adaptive card I am using is as below:
{
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.2",
"body": [
{
"type": "TextBlock",
"text": "Please enter the email Id, on behalf of whom you want to raise the request.",
"wrap": true
},
{
"type": "Input.ChoiceSet",
"id":"dropdown",
"choices": [
{
"title": "Myself",
"value": "Myself"
},
{
"title": "Other",
"value": "Other"
}
],
"placeholder": "Raise request for"
},
{
"type": "Input.Text",
"id": "email",
"placeholder": "Enter email address here",
"validation": {
"necessity": "Required",
"errorMessage": "Email address is required"
}
},
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Submit",
"title": "Submit",
"data": "Submit"
}
]
},
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Submit",
"title": "Cancel",
"data": {
"id": "stepCancel"
}
}
]
}
]
}
I used actions instead of actionset. The card looks something like this:
{
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.2",
"body": [
{
"type": "TextBlock",
"text": "Please enter the email Id, on behalf of whom you want to raise the request.",
"wrap": true
},
{
"type": "Input.ChoiceSet",
"id": "dropdown",
"choices": [
{
"title": "Myself",
"value": "Myself"
},
{
"title": "Other",
"value": "Other"
}
],
"placeholder": "Raise request for"
},
{
"type": "Input.Text",
"id": "email",
"placeholder": "Enter email address here",
"validation": {
"necessity": "Required",
"errorMessage": "Email address is required"
},
"inlineAction": {
"type": "Action.Submit",
"title": "Submit"
}
}
]
}
If you want to get Adaptive Cards to do something they were not designed to do, you will need to write your own renderer code using Adaptive Cards extensibility. You can use this answer and its many linked answers as your guide.
I've found that the usual pattern for these kinds of issues has two parts: come up with your own "schema" for your code to read, and then write the code to read it. If you want a choice set input to populate a certain text input with a certain value when a certain choice is selected, then your schema has three pieces of information: the text input's ID, the value to populate it with, and the choice that triggers it. Since this is a lot of information, it would be ideal if you could have all three of those pieces in their own "populate" object property like this:
{
"type": "Input.ChoiceSet",
"id": "dropdown",
"choices": [
{
"title": "Myself",
"value": "Myself"
},
{
"title": "Other",
"value": "Other"
}
],
"placeholder": "Raise request for",
"populate": {
"target": "email",
"with": "my_email#email.com",
"when": "Myself",
},
},
Unfortunately, Direct Line will strip out additional properties from your Adaptive Card so they'll never reach Web Chat. There is a workaround for that problem where you can preserve your full JSON by tricking Direct Line into thinking it's not an Adaptive Card and then making sure Web Chat knows it's an Adaptive Card when it receives it.
If you don't use the workaround, you will need to find some way of getting those three pieces of information to Web Chat. If don't want your code to be reusable for different cards then you can just hardcode the name of the text input and the choice into your JavaScript so that it doesn't need to be transmitted through the card. If you go the usual route of putting the information in the id property then it could look pretty crowded, and a dynamic ID could be hard for your bot to read after the data is submitted:
"id": "populate_email_when_Myself_with_my_email#email.com",
If the user's email is already stored on the Web Chat side somehow then you won't need to transmit it through the card, and the ID could just be "populate_email_when_Myself". That's a bit less imposing, and it would be easier for your bot to find because it's not dynamically generated. I'll go even further by assuming your client has the email address already and the text input's ID "email" is hardcoded in the JavaScript, so the choice set input ID can just be "populateEmail_Myself".
Once you're ready to write the JavaScript code, I usually like to go with onParseElement so most of my code only gets executed at the beginning as part of a sort of initialization. However, I've discovered that a problem with onParseElement is that you'll only have access to the elements that have already been parsed, so if your text input is parsed after your choice set input then the onParseElement function for the choice set input won't have access to the text input. You could solve that problem by having the function look for an element at the very end of your card so that the function will have access to all the other elements, but my example here just uses onInputValueChanged instead of onParseElement. Note that this means the function will be executed any time any input value is changed in any card, including each time a key is pressed in a text input.
window.AdaptiveCards.AdaptiveCard.onInputValueChanged = input => {
const PREFIX_POPULATE_EMAIL = 'populateEmail_';
if (input.id && input.id.startsWith(PREFIX_POPULATE_EMAIL)) {
// Myself
const targetValue = input.id.slice(PREFIX_POPULATE_EMAIL.length);
// The Adaptive Card object
const card = input.getRootElement();
// The text input with the hardcoded ID
const emailElement = card.getElementById('email');
// Did the user choose "Myself"?
if (input.value == targetValue) {
emailElement.renderedInputControlElement.value = THEIR_EMAIL_ADDRESS;
}
}
}
In many cases you'll need to re-render the element after you modify it by calling emailElement.render(). We don't need to do that in this case because we're changing the value in the rendered element directly with renderedInputControlElement rather than changing the value in the internal unrendered card element. This is a bit hacky because renderedInputControlElement is marked as protected in the TypeScript file, but if you wanted to do things the more official way then I suspect you'd have to rerender the whole card.
I followed this guide in order to create account linking in my app
https://developers.google.com/actions/identity/google-sign-in#json
I'm able to verify the user's jwt decoder and send back a response that the user is authorised. Then, according to the guide, in the next request, I should get the user's profile payload (user.profile.payload in the json structure) but It's missing from the next request. More than that, I get the tokenId for jwt verification again.
I think that what i miss here is in the possibleIntent object but I'm not sure, as I didn't see any documentation for that, because I work with asp.net server. There are SDKs with documentation for java and nodeJS only
this is the request provided for the sign in the contain the tokenId
{
"user": {
"locale": "en-US",
"lastSeen": "2019-07-11T14:18:10Z",
"idToken": "<tokenId>",
"userVerificationStatus": "VERIFIED"
},
"conversation": {
"conversationId": "ABwppHH9uZfcKj6pS6A6wItKC1dOXuZJ5oFYt2Og7cqrElSQYC9bv-aV7iQ5FDYaJPp-fa7tQNhc2yS0fw3QBu-M",
"type": "ACTIVE",
"conversationToken": "e0e78f40-a207-49c2-9050-50c6ed526c24"
},
"inputs": [
{
"intent": "actions.intent.SIGN_IN",
"rawInputs": [
{
"inputType": "KEYBOARD"
}
],
"arguments": [
{
"name": "SIGN_IN",
"extension": {
"#type": "type.googleapis.com/google.actions.v2.SignInValue",
"status": "OK"
}
},
{
"name": "text"
}
]
}
],
"surface": {
"capabilities": [
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.ACCOUNT_LINKING"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
},
{
"name": "actions.capability.WEB_BROWSER"
}
]
},
"isInSandbox": true,
"requestType": "SIMULATOR"
}
this is the response that i provide after verifying the user.
I tried it with both intents actions.intent.TEXT and actions.intent.SIGN_IN but with no success. the next request is provided with the user.idToken property again instead of the user.profile (that should contain the payload)
{
"conversationToken": "b09d915e-6df9-496d-acde-b76858cd95b4",
"expectUserResponse": true,
"expectedInputs": [
{
"inputPrompt": {
"richInitialPrompt": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Hi",
"displayText": "Hi"
}
}
],
"suggestions": []
}
},
"possibleIntents": [
{
"intent": "actions.intent.TEXT",
"inputValueData": {
"#type": "type.googleapis.com/google.actions.v2.SignInValue",
"status": "OK"
}
}
]
}
]
}
The user.profile attribute you're talking about is something that is provided via the actions-on-google library for JavaScript. It isn't in the JSON that you will receive. But...
You don't need it because the basic profile information (name, email, and Google ID) is encoded in the user.idToken. That string, which will be sent to you for every request, is just a JWT token which you can verify and decode. The profile will be in the "payload" section.
I don't know c#, but https://jwt.io/ contains a list of libraries which can decode the JWT string for you so you can read the "payload".
Keep in mind that you don't need to verify the token each time (although if you do it right, this shouldn't be expensive), but that you can decode it to get the information that you're looking for.
If you don't want to decode it, you can decode it when you first verify it, get the information you need, and store that information in the userStorage string (assuming you don't expect it to change).
I am performing an update operation on a contact using the Google PeopleService "updateContact" endpoint, and I'm noticing that some fields are not properly updating. I've acquired a contact using the "get" endpoint, and updated the contact's Work-type address to add in a postal code where there was none before, and then submitted the contact back using updateContact. I get a 200 OK response, but the returned contact object does not show the change. I see this behavior in using the .NET Client Libraries as well as the API explorer.
Address data before updating:
"addresses": [
{
{
"metadata": {
"source": {
"type": "CONTACT",
"id": "61327fef08903be4"
}
},
"formattedValue": "123 Anywhere Street\nSometown",
"type": "work",
"formattedType": "Work",
"streetAddress": "123 Anywhere Street",
"city": "Sometown"
}]
Address data altered, prior to update:
"addresses": [
{
{
"metadata": {
"source": {
"type": "CONTACT",
"id": "61327fef08903be4"
}
},
"formattedValue": "123 Anywhere Street\nSometown",
"type": "work",
"formattedType": "Work",
"streetAddress": "123 Anywhere Street",
"city": "Sometown",
"postalCode": "55555"
}]
Address data received in response to update request:
"addresses": [
{
{
"metadata": {
"source": {
"type": "CONTACT",
"id": "61327fef08903be4"
}
},
"formattedValue": "123 Anywhere Street\nSometown",
"type": "work",
"formattedType": "Work",
"streetAddress": "123 Anywhere Street",
"city": "Sometown"
}]
In the above example, the expectation is that the new postal code with a value of "55555" would show up in the addresses object.
I am specifying the full set of possible fields in the Update Person Fields Mask (specifically, in this case, the "addresses" field), and confirmed that the resource name and ETag of the contact in question is accurate and the latest, and that I am pulling the latest copy after the update is complete.
Is this a known issue with the People Service update endpoint? Is there something more I need to specify in the request to force an update that isn't documented in the documentation?
A fix has been submitted for this bug, the address should now update properly without needing to modify the formattedValue.
I am using the function to BuildJsonForm to define a form using a JSON schema. I generate the JObject with some parameters the bot asks the user during runtime.
An example of the JObject/JSON I send to the function BuildJsonForm is this one:
`
{
"References": [
"Microsoft.Bot.Connector.dll",
"System.dll",
"mscorlib.dll",
"System.Net.Http.dll"
],
"Imports": [
"Microsoft.Bot.Connector.ThumbnailCard",
"Microsoft.Bot.Connector.StateClient",
"System.Net.Mail",
"System",
"System.Text.RegularExpressions",
"System.Net.Http",
"System.Net",
"System.Text"
],
"type": "object",
"required": [
"username",
"password"
],
"Templates": {
"NotUnderstood": {
"Patterns": [
"I do not understand, Please rephrase that"
]
},
"EnumSelectOne": {
"Patterns": [
"Choose one please"
],
"ChoiceStyle": "Auto"
}
},
"properties": {
"username": {
"Prompt": {
"Patterns": [
"Tell me the {&}, please",
"I need you to especify a {&}, please"
]
},
"type": [
"string",
"null"
],
"Templates": {
"NotUnderstood": {
"Patterns": [
"That is not a valid input"
]
}
}
},
"password": {
"Prompt": {
"Patterns": [
"Tell me the {&}, please",
"I need you to especify a {&}, please"
]
},
"type": [
"string",
"null"
],
"Templates": {
"NotUnderstood": {
"Patterns": [
"That is not a valid input"
]
}
}
}
},
"OnCompletion": "await context.PostAsync(\"Thank you!\"); string files = \"\"; context.PrivateConversationData.TryGetValue<string>(\"Files\", out files); [more code...]"
}
`
I need to send to the database the user's answers to the generated JObject/JSON form's questions, but so far, I haven't found a way to do that.
I also tried accessing the BotData with this line context.PrivateConversationData.TryGetValue<string>("Files", out files);, so I could send the user's answers to the database directly from the "OnCompletion" section of the JSON, but still I can't seem to access to the botdata or context on the OnCompletion section.
Is there any other way I can successfully retrieve the user's responses to the JObject/JSON generated form after the user answers the last question in the form?
It seemed that what was causing the trouble in my project were sending this parameters to the function:
GeneratedForm.BuildJsonForm(channel, user, convers);
since I edited the function without those parameters and I stopped getting the exception specified in the question. I will look for the reason these parameters were causing problems but the solution I found in this case was to define the funtction this way:
GeneratedForm.BuildJsonForm();
I am using Andy Crum's EmberDataModelMaker.
Having punched in the following two classes
// app/models/server-item.js
export default DS.Model.extend({
hostName: DS.attr('string'),
syncServers: DS.hasMany('string'),
subscribers: DS.hasMany('string'),
mailHost: DS.attr('string'),
mailHostLogin: DS.hasMany('credentials')
});
// app/models/credentials.js
export default DS.Model.extend({
user: DS.attr('string'),
password: DS.attr('string'),
server: DS.belongsTo('serverItem')
});
It's showing the following three different expected JSON formats (a very nice feature btw.):
DS.RESTAdapter
"serverItems": [
{
"id": 1,
"hostName": "foo",
"syncServers": [
<stringids>
],
"subscribers": [
<stringids>
],
"mailHost": "foo",
"mailHostLogin": [
<Credentialsids>
]
}
],
"credentials": [
{
"id": 1,
"user": "foo",
"password": "foo",
"server": <ServerItemid>
}
]
DS.ActiveModelAdapter
"serverItems": [
{
"id": 1,
"host_name": "foo",
"sync_server_ids": [
<stringids>
],
"subscriber_ids": [
<stringids>
],
"mail_host": "foo",
"mail_host_login_ids": [
<Credentialsids>
]
}
],
"credentials": [
{
"id": 1,
"user": "foo",
"password": "foo",
"server_id": <ServerItemid>
}
]
DS.JSONAPIAdapter
{
"data": {
"type": "server-items",
"id": "1",
"attributes": {
"HostName": "foo",
"MailHost": "foo",
},
"relationships": {
"SyncServers": {
"data": {
"type": "SyncServers",
"id": <SyncServersid>
}
},
"Subscribers": {
"data": {
"type": "Subscribers",
"id": <Subscribersid>
}
},
"MailHostLogin": {
"data": {
"type": "MailHostLogin",
"id": <MailHostLoginid>
}
}
},
"included": [
{
<sideloadedrelationships>
]
}
}
}
{
"data": {
"type": "credentials",
"id": "1",
"attributes": {
"User": "foo",
"Password": "foo",
},
"relationships": {
"Server": {
"data": {
"type": "Server",
"id": <Serverid>
}
}
},
"included": [
{
<sideloadedrelationships>
]
}
}
}
I am going to implement (or rather change) some WebServices on the Server side (using C#, ASP.NET Web API). Currently, the WebService already creates a result that is pretty similar to the format expected with DS.RESTAdapter - obviously, it would be ideal if I could use it without compromising the Data Integrity - can I?
If yes, would it empower Ember Data to send all the requests necessary to maintain the data consistency on the server? Meaning, would the client send a DELETE request to the server not only for the ServerItem but also for the Credentials item that is referenced via the mailHostLogin property when the user wants to delete a ServerItem?
If not: are both of the other two adapters fulfilling the above mentioned consistency requirement? Which of the other two should I implement - any experiences/recommendations out there?
You should choose whichever Adapter closest fits your API data structure as a basis(sounds like DS.RESTAdapter in this case). You can extend the adapters and serializers that are a closest fit to make any necessary adjustments(this can be done both application wide or on a per model basis).
However, I don't think that the Ember Data model relationships(i.e. belongsTo and hasMany) are binding in such a way that will automatically result in the "data consistency" you are looking for. If your application requirements are to delete all associated Credentials records when a ServerItem is deleted, I would recommend doing that server side when handling the DELETE ServerItem API request. That would result in better performance(1 HTTP call instead of 2 or N depending if credentials can be deleted in bulk) and be much less error prone due to potential network or other failure of calls to delete Credentials after a ServerItem is deleted.
After a successful ServerItem delete, you could loop through it's credentials and unload the records from the client side store to keep it in sync with the new state on the server. Something like:
serverItemCredentials.forEach(function(id) {
if (this.store.recordIsLoaded('credential', id)) {
this.store.unloadRecord(this.store.peekRecord('credential', id));
}
});