I am creating a simple CRUD app to learn Azure. I have created a logic app (standard model) and my APIs are designed using the workflow designer. I also have a CosmoDB to hold each object.
My GET API, that gets all the documents, looks like this:
And my GET API, that gets only one document, looks like this:
Here is what my CosmosDB looks like with the ID of the item that is successfully return when statically called:
So what do I need to replace the static ID with, in the *Document ID input so that I can pass in different IDs?
I have looked at the docs and it suggests documentId, but when I type this in I get this error:
Thanks!
Thank you #404 , posting your suggestion as an answer to help other community members.
" You should know the id you want to retrieve from the flow that feeds into the Get a document block (unless it's static). Since you only have a HTTP trigger your id should be supplied through that. As example by passing the id in the url as query parameter which you then refer to in your Document ID field."
Trigger a post request to logic app with Document ID in request body.
Try as below:
Related
I'm trying to get the OneNote notebook information that is linked to my organization's CRM accounts. Each account has a OneNote book created for it that can be accessed inside of CRM.
From what I understand, I can use the SharePointDocumentLocation endpoint (found here: https://learn.microsoft.com/en-us/dynamics365/customer-engagement/web-api/sharepointdocumentlocation?view=dynamics-ce-odata-9) to get the location of the specific file if I ask for location type to be 1.
However, SharePointDocumentLocationId and SiteCollectionId don't seem to be pointing to anything on my company's sites. Should I be getting my data somewhere else?
I started searching through my company's SharePoint structure to see if I can get any hints as to where these documents may be located. My initial Postman request (getting the sites off of the root site) don't show the site that hosts our CRM documents (sites/crmdocs). I was able to find where this was stored eventually, but trying to get the OneNote notebooks stored there returns an error since we have more than 20,000 notebooks there, so I can't fetch them all. As far as I know, I'm able to get notebooks if I have the specific ID I want.
Once I fetch the CRM information, I try to send a request like this:
https://graph.microsoft.com/v1.0/sites/{myCompanyUrl},{siteCollectionId},{sharepointDocumentLocationId}/onenote/notebooks/
SiteCollectionId and SharePointDocumentLocationId are from my CRM SharePointDocumentLocation request
The error I receive is:
The requested site was not found. Please check that the site is still accessible.
Assuming your environment is using the out of the box sharepoint site and sharepoint document location hierarchy, you can access One Note files using the following link structure:
[SharePointAbsoluteUrl]/[EntityLogicalName]/[RelativeUrl]_[RegardingObjectId]/[RelativeUrl]
How to get [SharePointAbsoluteUrl] :
Querying for sharepointdocumentlocations is actually not enough because Dynamics 365 stores this information in another entity called sharepointsite. This is how you can obtain it:
var query = new QueryExpression("sharepointsite")
{
ColumnSet = new ColumnSet("absoluteurl")
};
query.Criteria.AddCondition("IsDefault", ConditionOperator.Equal, true);
var entityCollection = _service.RetrieveMultiple(query);
var absoluteUrl = entityCollection[0].Attributes["absoluteurl"];
In Web API it is equivalent to:
GET https://[Your Org]/api/data/v9.0/sharepointsites?$select=absoluteurl&$filter=isdefault%20eq%20true
There can only be a default sharepoint site so this query will return a single record.
How to get the remaining parts:
Fetch for sharepointdocumentlocations that have Location Type dedicated to One Note Integration:
var query = new QueryExpression("sharepointdocumentlocation")
{
ColumnSet = new ColumnSet("regardingobjectid", "relativeurl")
};
query.Criteria.AddCondition("locationtype", ConditionOperator.Equal, 1);
var entityCollection = _service.RetrieveMultiple(query);
In Web API it is equivalent to the following get request, don't forget to add add Prefer: odata.include-annotations="*" to your HTTP Request Headers so that it gets the lookup lookuplogicalname field:
GET https://[Your Org]/api/data/v9.0/sharepointdocumentlocations?$select=relativeurl,_regardingobjectid_value&$filter=locationtype%20eq%201
This query can return many records, I've only used the first one in the examples below for explanation purposes.
[EntityLogicalName] will be your ((EntityReference)entityCollection[0].Attributes["regardingobjectid"]).LogicalName;
In Web Api will be your value._regardingobjectid_value#Microsoft.Dynamics.CRM.lookuplogicalname value.
[RelativeUrl] will be your entityCollection[0].Attributes["relativeurl"];
In Web Api will be your value.relativeurl value.
[RegardingObjectId] can be obtained with this expression ((EntityReference)entityCollection[0].Attributes["regardingobjectid"]).Id.ToString().Replace("-", "").ToUpper();
In Web Api id will be your _regardingobjectid_value value and you have to remove dashes and convert it to upper case in whatever language you are doing the request.
You should end up with an URL like this https://mycompany.sharepoint.com/account/A Datum Fabrication_A56B3F4B1BE7E6118101E0071B6AF231/A Datum Fabrication
I would like my Actions on Google agent to store and retrieve certain pieces of information across invocations - like a cookie. How do I do this?
You have a lot of options on how you want to do this, depending on exactly what you're trying to do. It isn't exactly like a web cookie, although there are similarities.
If you want the equivalent of a session cookie, information that is retained during a single conversation, then your options are
Using the Session ID provided as part of the information sent to you on each invocation and tracking this in your fulfillment.
Storing information you want retained using a Dialogflow context
If you are using the actions-on-google JavaScript library, storing this in the app.data object created for you.
If you want the equivalent of a long-lasting cookie to retain information between conversations then your options are
Using the anonymous User ID provided as part of the information sent to you on each invocation and tracking this in your fulfillment.
If you are using the actions-on-google javascript library, storing this in the app.userStorage object created for you.
Storing it as part of the string in the JSON response under data.google.userStorage.
Some more information about each of these
Session ID
A different Session ID is created for each conversation you have. You can get this Session ID by examining the JSON sent to your webhook in the sessionId parameter.
You can then look this up in a data store of some sort that you manage.
Dialogflow context
Contexts are powerful tools that are available with Dialogflow. You return a context as part of your fulfillment webhook and indicate the name of the context, its lifetime (how many more rounds of the conversation it will be passed back to your webhook), and any parameters associated with the context (string key/value pairs).
Contexts are especially useful in helping determine what intents may be called. You can indicate what contexts must be active for an Intent to be recognized by Dialogflow.
If you're using the actions-on-google node.js library, you can set a context using something like this:
var contextParameters = {
foo: "Something foothy",
bar: "Your local bar."
};
app.setContext( "remember_this", 5, contextParameters );
You need to do this before you call app.ask() or app.tell().
Or you can do the equivalent in the JSON as part of the contextOut block of the response
"contextOut": [
{
"name": "remember_this",
"lifespan": 5,
"parameters": {
"foo": "Something foothy",
"bar": "Your local bar."
}
}
]
The next time your webhook is called, you can fetch this context either by looking at the result.contexts array or by using the app.getContext() or app.getContextArgument() methods in the library.
Using app.data
If you're using the library, Google has done some of the work for you. The app.data object is created for you. Any values you set in the object are available for the lifetime of the session - you just read them in later calls to your webhook.
(Under the covers, Google uses a context for this, so there is no magic. The two work together and you're free to do both.)
Anonymous UserID
When a user first uses your action, a user ID is generated. This ID doesn't give you access to any specific information about them, and isn't used for any other action, but every time you see it, you can be assured that it was the same user that used it on a previous occurrence. Just like a cookie, however, the user can reset it and a new ID will be generated for them for your action.
You get this from the JSON at originalRequest.user.userId or by using app.getUser().userId. Once you have it, you'd use a data store of some sort to store and retrieve information about this user.
Using app.userStorage
Similar to app.data, there is also an app.userStorage object that is created for you for each user. Any changes you make to this object are saved in between conversations you have with this user.
Unlike app.data, however, this doesn't get stored in a context. It has its own storage method. Which leads to...
Storing it in JSON
If you're not using the actions-on-google library, you still have access to userStorage through the response and request JSON directly. You need to store this as a string, but if you need to store a more complex object, a common method is to stringify it as JSON.
You'll store this value under data.google.userStorage in the response and can retrieve it under originalRequest.data.user.userStorage in the request your webhook receives.
You can save the information in Context with a key value parameter.
SAVING VALUES IN CONTEXT :
agent.set.Context({
name:'context-name',
lifespan: 5,
parameters:{
'parameter-name':'parameter-value'
}
});
GETTING VALUES FROM CONTEXT
agent.getContext('context-name');
For more Details : https://dialogflow.com/docs/contexts/contexts-fulfillment
You could also use a Google Cloud database like BigQuery or Firestore
Sounds like you may want to checkout out Account Linking: https://developers.google.com/actions/identity/account-linking. With account linking you can collect end-user information which you exchange with Google by providing a unique key. This unique key becomes part of every request you receive from Google, so when you get that unique key you lookup the information you collected from the end-user. In your case, you would store credentials or whatever key is required to access the end-user information. After the initial linking, any new data you obtain could be stored along with the original information collected, based on the unique key obtained during account linking.
For this purpose, i just did a node module just for that, in external json file from api call, i need to store and add additional informations to retrieve later. I thing that you can do a lot with this module, Store object, array, json, value, Navigation history?, back to previous page.
It work like localStorage or Cookies.
There's no limit, you can create multiple storage by name (key) an value. It's new and i'm testing it for bugs right now on my own project.
Test on Runkit
On npm
vStorage = require('virtual-storage');
vStorage.set('name', '{title:'Title 1', description:'Descriptions 1'}')
let getStorage_name = vStorage.get('name');
console.log(getStorage_name.title);
vStorage.get('name')
I have created a node/feathers project using this chat application guide as a base. It's working great, but now I would like to filter the results the api is giving. For example, when user makes GET request to /messages I would like the response to include only the messages that the authorized user has created, not anyone else's messages. Auth is working correctly in the api and message items have the userId who created the message, but I just don't understand what and where I'm supposed to do to filter the messages according to the user id. After hours of googling I couldn't find anything related to this or anyone even asking the question, so what am I missing here?
You can do a manual filtering. Both on before and after hooks. How to use hooks.
In before hooks you can create a function that update your query object to only get/find data it owns.
hook.params.query = { ... , ownedBy: hook.params.user._id }
Or do result filtering in after hooks, you have the hook.result which is the only thing you can manipulate in the after hooks. Then you can use Array.prototype.filter() to filter the results the user gets.
What AMP extensions can be used to get a response from the server in the form of variable that can be used later, such as in a template or as a parameter to an attribute?
amp-access
The authorization endpoint of amp-access can return "a free-form JSON object":
Here’s a small list of possible ideas for properties that can be returned from the Authorization endpoint:
Metering info: maximum allowed number of views and current number of views.
Whether the Reader is logged in or a subscriber.
A more detailed type of the subscription: basic, premium
Geo: country, region, custom publication region
amp-form
amp-form "allows publishers to render the responses using Extended Templates". The response is expected to be a valid JSON Object. Try the "Hiding input fields after success" demo in the amp-form sample to see it in action.
amp-list
amp-list fetches "content dynamically from a CORS JSON endpoint and renders it using a supplied template". The response must be a JSON object that contains an array property "items".
In addition to {{variable}} substitutions in Mustache templates, you can also use AUTHDATA(variable) elsewhere.
amp-live-list (not quite)
amp-live-list is a "wrapper and minimal UI for content that updates live in the client instance as new content is available in the source document". The page will re-fetch itself, giving the server a change to send new content. If new content is found, AMP will populate a <div items> element with the new (HTML) items. You can't use that as a variable.
It's name doesn't really suggest it, but I think you want AMP-list
https://github.com/ampproject/amphtml/blob/master/extensions/amp-list/amp-list.md
Fetches content dynamically from a CORS JSON endpoint and renders it using a supplied template.
I am trying to create an html object dynamically with the necessary header information depending on the query string in the link I provide to Facebook. I am hoping that Facebook open graph will call this html link as I provided. However it seems that query string info are not getting passed to my server. Do anyone know how to make this work or what is the more appropriate way to do this. BTW, I am writing my code in Node.js.
To get more info about Facebook open graph api, look here, https://developers.facebook.com/docs/beta/opengraph/actions/.
For example, the link I am trying to pass to Facebook is, "http://xxx-url.com/getFacebookObject?objectId=&description=first dynamic post", so I sent a request with the link as, "https://graph.facebook.com/me/app-name:action-name?object=http://xxx-url.com/getFacebookObject?objectId=&description=first dynamic post". However, when I check the log on the server, I don't see anything in the query string.
Instead of using the query string, you can embed the data in the URL:
http://some-domain.com/getFacebookObject/id/description
Then, depending on what node.js packages you're using, extract the data from the request:
// expess.js style
app.get("/getFacebookObject/:id/:description", function(req, res) {
var id = req.params.id,
desc = req.params.description;
// your code...
});
(See http://expressjs.com/guide.html.)
Sorry, Facebook will strip off all query string information from the URL when they launch your site in the iframe. If it was a page tab app, then you could add it to the app_data query string parameters which in turn gets passed to your iframe's page tab app via the app_data part of the signed_request parameter.