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.
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'm currently working on an app in Xamarin.Android with one of the features being that, upon clicking a button, the user is taken to a specific calendar event in the Microsoft Outlook app. Thus far I've been using the Microsoft Graph API to get the event items and I've succeeded in opening the Outlook app to the calendar or opening Outlook with an error message saying "Event could not be opened" but I haven't gotten both behaviors to happen, nor the specific event item to open. The way I open the Outlook app is by calling the device's default browser with an Outlook uri scheme. Both are provided below
browserLaunch("ms-outlook://events/open?account={my.account#email.com}&restid={id}");
private async void browserLaunch( string uri ) {
await Browser.OpenAsync(uri, BrowserLaunchMode.SystemPreferred);
}
The exact call I've been making to the Graphs API is as follows
https://graph.microsoft.com/v1.0/me/calendarview?startdatetime=2020-01-23T15:54:40.377Z&enddatetime=2020-01-30T15:54:40.377Z
which returns a list of even items with the following scheme:
"#odata.etag": "string",
"id": "string",
"createdDateTime": "20##-##-##T##:##:##.######Z",
"lastModifiedDateTime": "20##-##-##T#3:##:##.#######Z",
"changeKey": "string",
"categories": [],
"originalStartTimeZone": "Central Standard Time",
"originalEndTimeZone": "Central Standard Time",
"iCalUId": "string",
"reminderMinutesBeforeStart": int,
"isReminderOn": true/false,
"hasAttachments": true/false,
"subject": "string",
"bodyPreview": "string",
"importance": "string",
"sensitivity": "string",
"isAllDay": true/false,
"isCancelled": true/false,
"isOrganizer": true/true,
"responseRequested": true/false,
"seriesMasterId": null,
"showAs": "string",
"type": "string",
"webLink": "https://outlook.office365.com/owa/?itemid={id}&exvsurl={int}&path=/calendar/item",
"onlineMeetingUrl": null,
"recurrence": null,
"responseStatus": {
"response": "none",
"time": "0001-01-01T00:00:00Z"
},
"body": {
"contentType": "html",
"content": "string"
},
"start": {
"dateTime": "20##-##-##T##:##:##.#######",
"timeZone": "UTC"
},
"end": {
"dateTime": "20##-##-##T##:##:##.#######",
"timeZone": "UTC"
},
"location": {
"displayName": "string",
"locationType": "string",
"uniqueId": "string",
"uniqueIdType": "stirng"
},
"locations": [
{
"displayName": "string",
"locationType": "string",
"uniqueId": "hexstrin-hexs-hexs-hexs-hexstringhex",
"uniqueIdType": "string"
}
],
"attendees": [
{
"type": "string",
"status": {
"response": "string",
"time": "0001-01-01T00:00:00Z"
},
"emailAddress": {
"name": "string",
"address": "my.account#email.com"
}
}
],
"organizer": {
"emailAddress": {
"name": "string",
"address": "my.account#email.com"
}
}
I've also tried different ids that are given by the graphs API for the restid param. Thus far I've used the itemid param found in the url of the webLink field, the id of the json object, the changeKey, and the iCalUId but those last two didnt get me anything beyond just opening up Outlook.
I've also just passed in the webLink but it just opens a lightweight browser (and get's stuck on a white page) which I don't want as I need it specifically to go to the Outlook app. Any ideas?
So the best current solution I have been able to find is to open up a lightweight browser using a different url scheme than any prior:
https://outlook.office365.com/calendar/item/{webLinkItemId}
where webLinkItemId is the itemId param from the webLink url gotten from the returned Graphs API json object. You can find that complete object above in my original post but what you're looking for within that object is the following field
"webLink": "https://outlook.office365.com/owa/?itemid={webLinkItemId}&exvsurl={int}&path=/calendar/item"
You want to take the {webLinkItemId} string embedded in the url above and plug it into the corresponding spot in the scheme above
I have a template in DocuSign that contains a SigningGroup as one of its recipients. when I tried to retrieve this template via C#/SOAP, the value of SigningGroupId is 0 and SigningGroupIdSpecified false. Is there any setting I need to enable or a flag I need to set to true to be able to correctly retrieve the recipient's SigningGroupId?
Below is the code to retrieve the template
dsApi.RequestTemplate(templateId, false);
dsApi obviously contains the reference to the SOAP API loaded in C#
Image below shows the SigningGroupId value returned by the API
Thank you and good day
I think its not possible to get it via SOAP API, instead you can get the same via REST API
GET /v2/accounts/{accountId}/templates/{templateId}/recipients
Details are available at RecipientList
Response will look like:
{
"creationReason": "sender",
"isBulkRecipient": "false",
"name": "TestSigningGrp",
"email": "",
"signingGroupId": "27343",
"signingGroupName": "TestSigningGrp",
"signingGroupUsers": [
{
"userName": "Test1",
"userId": "a832164e-0da7-449c-9405-be21632564a4",
"email": "email1#gmail.com",
"uri": "/users/a832164e-0da7-449c-9405-be21632564a4"
},
{
"userName": "Test2",
"userId": "68139c8e-8dee-4b51-8b78-842e470ee5b3",
"email": "email2#gmail.com",
"uri": "/users/68139c8e-8dee-4b51-8b78-842e470ee5b3"
}
],
"recipientId": "23764479",
"recipientIdGuid": "5474c7d9-1548-42a4-99ee-dba6ea87fdda",
"requireIdLookup": "false",
"routingOrder": "1",
"note": "",
"roleName": "SigningRole",
"status": "created",
"declinedReason": "",
"deliveryMethod": "email"
}
I've accepted as an answer the comment of #amit but the actual answer is the 8th comment of that answer, also by #amit.
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
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));
}
});