Facebook connect graph status objects have comments capped at 25 - ios

Does anyone know why no matter how many comments a given graph status update object has, it will cap the comments at 25? I have a feeling it only returns a 'sample' of the actual comments on the object. How do I force it to get them all without using the FQL APIs?

This is just the way the Graph API works. Take a look at the API docs. You get 25 at a time and have to loop through them. You can use the timestamp (created_time) of the last comment in the batch as a parameter in the next Graph API call or you can use the offset parameter. Which is what I've been doing. I was running into some screwiness using created_time. This is an example from my C# test app. Ignore the references to the PostComment object that's just a data structure I created to hold the data I'm pulling. The magic (and the process i'm referencing) is in the parameters being passed to the graph API call:
parameters.Add("offset", numPostComments);
parameters.Add("limit", 25);
I'm fairly certain you can set the "limit" to anything 25 or below.
do
{
foreach (var comment in comments.data)
{
numPostComments++;
PostComment pc = new PostComment();
pc.Post_ID = p.Id;
pc.Facebook_ID = comment.id;
pc.From = comment.from.name;
if (comment.likes != null)
pc.Likes = (int)comment.likes;
pc.CommentDate = DateTime.Parse(comment.created_time);
pc.CommentText = comment.message;
p.Comments.Add(pc);
}
// Create new Parameters object for call to API
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("offset", numPostComments);
parameters.Add("limit", 25);
// Call the API to get the next block of 25
comments = client.Get(string.Format("{0}/comments", p.Facebook_ID), parameters);
} while (comments.data.Count > 0);

Related

How can I retrieve all members when querying for appRoleAssignedTo in Microsoft Graph?

I am attempting to programmatically retrieve a list of users (principalType = "User") and their associated appRoleId values for an enterprise app using itsresourceId value from Azure AD. There is a total of ten Users with a combined total of twenty appRoleId values associated with the app. However, when I run my query I receive data for just two users and a combined total of four appRoleId values.
Here's my C# code:
GraphServiceClient myGraphClient = GetGraphServiceClient([scopes]);
// Retrieve the [Id] value for the app. Note [Id] is a pseudonym for the [resourceId] required to retrieve users and app roles assigned.
var servPrinPage = await myGraphClient.ServicePrincipals.Request()
.Select("id,appRoles")
.Filter($"startswith(displayName, 'Display Name')")
.GetAsync()
.ConfigureAwait(false);
// Using the first [Id] value from the [ServicePrincipals] page, retrieve the list of users and their assigned roles for the app.
var appRoleAssignedTo = await myGraphClient.ServicePrincipals[servPrinPage[0].Id].AppRoleAssignedTo.Request().GetAsync().ConfigureAwait(false);
The query returns a ServicePrincipalAppRoleAssignedToCollectionPage (as expected) but the collection only contains four pages (one per User/appRoleId combination).
As an aside, the following query in Microsoft Graph Explorer produces an equivalent result:
https://graph.microsoft.com/v1.0/servicePrincipals/[resourceId]/appRoleAssignedTo
What am I missing here? I need to be able to retrieve the complete list of users and assigned app roles. Any assistance is greatly appreciated.
The issue I was confronting has to do with the pagination feature employed by Azure AD and MS Graph. In a nutshell, I was forced to submit two queries in order to retrieve all twenty records I was expecting.
If you have a larger set of records to be retrieved you may be faced with submitting a much larger number of successive queries. The successive queries are managed using a "skiptoken" passed as a request header each time your query is resubmitted.
Here is my revised code with notation....
// Step #1: Create a class in order to strongly type the <List> which will hold your results.
// Not absolutely necessary but always a good idea when working with <Lists> in C#.
private class AppRoleByUser
{
public string AzureDisplayName;
public string PrincipalDisplayName;
}
// Step #2: Submit a query to acquire the [id] for the Service Principal (i.e. your app).
// Note the [ServicePrincipals].[id] property is synonymous with the [resourceId] needed to
// retrieve [AppRoleAssignedTo] values from Microsoft Graph in the next step.
// Initialize the Microsoft Graph Client.
GraphServiceClient myGraphClient = GetGraphServiceClient("Directory.Read.All");
// Retrieve the Service Principals page containing the app [Id].
var servPrinPage = await myGraphClient.ServicePrincipals.Request().Select("id,appRoles").Filter($"startswith(displayName, 'Your App Name')").GetAsync().ConfigureAwait(false);
// Store the app [Id] in a local variable (for readability).
string resourceId = servPrinPage[0].Id;
// Step #3: Using the [Id]/[ResourceId] value from the previous step, retrieve a list of AppRoleId/DisplayName pairs for your app.
// Results of the successive queries are typed against the class created earlier and are appended to the <List>.
List<AppRoleByUser> appRoleByUser = new List<AppRoleByUser>();
// Note, unlike "Filter" or "Search" parameters, it is not possible to
// add a "Skiptoken" parameter directly to your query in C#.
// Instead, it is necessary to insert the "skiptoken" as request header using the Graph QueryOption class.
// Note the QueryOption List is passed as an empty object on the first pass of the while loop.
var queryOptions = new List<QueryOption>();
// Initialize the variable to hold the anticipated query result.
ServicePrincipalAppRoleAssignedToCollectionPage appRoleAssignedTo = new ServicePrincipalAppRoleAssignedToCollectionPage();
// Note the number of user/role combinations associated with an app is not always known.
// Consequently, you may be faced with the need to acquire multiple pages
// (and submit multiple consecutive queries) in order to obtain a complete
// listing of user/role combinations.
// The "while" loop construct will be utilized to manage query iteration.
// Execution of the "while" loop will be stopped when the "bRepeat" variable is set to false.
bool bRepeat = true;
while (bRepeat == true)
{
appRoleAssignedTo = (ServicePrincipalAppRoleAssignedToCollectionPage) await myGraphClient.ServicePrincipals[resourceId].AppRoleAssignedTo.Request(queryOptions).GetAsync().ConfigureAwait(false);
foreach (AppRoleAssignment myPage in appRoleAssignedTo)
{
// I was not able to find a definitive answer in any of the documents I
// found but it appears the final record in the recordset carries a
// [PrincipalType] = "Group" (all others carry a [PrincipalType] = "User").
if (myPage.PrincipalType != "Group")
{
// Insert "User" data into the List<AppRoleByUser> collection.
appRoleByUser.Add(new AppRoleByUser{ AzureDisplayName = myPage.PrincipalDisplayName, AzureUserRole = myPage.AppRoleId.ToString() });
}
else
{
// The "bRepeat" variable is initially set to true and is set to
// false when the "Group" record is detected thus signaling
// task completion and closing execution of the "while" loop.
bRepeat = false;
}
}
// Acquire the "nextLink" string from the response header.
// The "nextLink" string contains the "skiptoken" string required for the next
// iteration of the query.
string nextLinkValue = appRoleAssignedTo.AdditionalData["#odata.nextLink"].ToString();
// Parse the "skiptoken" value from the response header.
string skipToken = nextLinkValue.Substring(nextLinkValue.IndexOf("=") + 1);
// Include the "skiptoken" as a request header in the next iteration of the query.
queryOptions = new List<QueryOption>()
{
new QueryOption("$skiptoken", skipToken)
};
}
That's a long answer to what should have been a simple question. I am relatively new to Microsoft Graph but it appears to me Microsoft has a long way to go in making this API developer-friendly. All I needed was to know the combination of AppRoles and Users associated with a single, given Azure AD app. One query and one response should have been more than sufficient.
At any rate, I hope my toil might help save time for someone else going forward.
Could you please remove "Filter" from the code and retry the operation. Let us know if that worked.

Best way to continue to query Quickbooks data

I have a problem with the qbxml.
I'm trying to migrate the qb customers, items etc to zohobooks.
I want to grab 50 customers first from quickbooks and calling zohobooks apis to create contacts on there. and again another 50 customers from quickbooks and to zohobooks.
The problem is I'm sure how can I continue to query after calling the zohobooks apis?
When I tried to use the same iteratorID from the first query response I got nothing from QB.
I'm building desktop app using .net, please advise me the best option to track the migration and where I'm.
Assume that I have 150 customers and for some reason stopped migrating after 100customers, in this case how can I get the last 50 customers next time?
public string customerQueryXml()
{
XmlDocument inputXMLDoc = new XmlDocument();
inputXMLDoc.AppendChild(inputXMLDoc.CreateXmlDeclaration("1.0", null, null));
inputXMLDoc.AppendChild(inputXMLDoc.CreateProcessingInstruction("qbposxml", "version=\"1.0\""));
XmlElement qbXML = inputXMLDoc.CreateElement("QBPOSXML");
inputXMLDoc.AppendChild(qbXML);
XmlElement qbXMLMsgsRq = inputXMLDoc.CreateElement("QBPOSXMLMsgsRq");
qbXML.AppendChild(qbXMLMsgsRq);
qbXMLMsgsRq.SetAttribute("onError", "stopOnError");
XmlElement customerQueryRq = inputXMLDoc.CreateElement("CustomerQueryRq");
qbXMLMsgsRq.AppendChild(customerQueryRq);
//customerQueryRq.SetAttribute("requestID", "1");
//customerQueryRq.SetAttribute("iterator", "Start");
customerQueryRq.SetAttribute("requestID", "2");
customerQueryRq.SetAttribute("iterator", "Continue");
customerQueryRq.SetAttribute("iteratorID", "{A1601C19-C6DC-43C0-AE43-6F45088C39F2}");
// for test only, read 10 customers
XmlElement MaxReturned = inputXMLDoc.CreateElement("MaxReturned");
customerQueryRq.AppendChild(MaxReturned).InnerText = "50";
XmlElement ownerID = inputXMLDoc.CreateElement("OwnerID");
customerQueryRq.AppendChild(ownerID).InnerText = "0";
XmlElement timeModifiedRangeFilter = inputXMLDoc.CreateElement("TimeModifiedRangeFilter");
customerQueryRq.AppendChild(timeModifiedRangeFilter);
XmlElement fromTimeModified = inputXMLDoc.CreateElement("FromTimeModified");
timeModifiedRangeFilter.AppendChild(fromTimeModified).InnerText = "1980-01-01T00:00:00";
XmlElement toTimeModified = inputXMLDoc.CreateElement("ToTimeModified");
timeModifiedRangeFilter.AppendChild(toTimeModified).InnerText = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss");
return inputXMLDoc.OuterXml;
}
EDIT:
I noticed that I have to use the iteratorID in the same request. By the way I have no problem with the qbxml itself.
My question is how can I continue to query the customers, items or whatever on another request?
ProcessRequest (first time)
migrated xml data to another system
and after that for whatever reason I stopped the request
here, can I continue to query on another ProcessRequest?
Iterators have to be used within a single Session. e.g. this will work:
Connect to QuickBooks (establish a session)
Do a request to create an iterator and get the first page of records
Do another request to continue the iterator
Do another request to continue the iterator
While this will not work, and is not something supported by QuickBooks:
Connect to QuickBooks (establish a session)
Do a request to create an iterator and get the first page of records
Disconnect
Do a request to create an iterator and get the first page of records

HTTPClient GetAsync post object

We currently have a generic MVC method that GET's data from ASP.NET Web API
public static T Get<T>(string apiURI, object p)
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(Config.API_BaseSite);
HttpResponseMessage response = client.GetAsync(apiURI).Result;
// Check that response was successful or throw exception
if (response.IsSuccessStatusCode == false)
{
string responseBody = response.Content.ReadAsStringAsync().Result;
throw new HttpException((int)response.StatusCode, responseBody);
}
T res = response.Content.ReadAsAsync<T>().Result;
return (T)res;
}
}
Our question is:- obviously, we can not send 'p' as you would with a post,
client.PostAsync(apiURI, new StringContent(p.ToString(), Encoding.UTF8, "application/json")
but how we go about sending this object / JSON with a get.
We have seen sending it as part of the URL, however, is there an alternative?
GET sends the values with the query string (end of url), in regards to "but how we go about sending this object / JSON with a get. We have seen sending it as part of the URL, however, is there an alternative?".
The alternative is POST or PUT.
PUT is best used when the user creates the key/url. You can look at examples such as cnn.com - where the URL's are just short versions of the article title. You want to PUT a page at that URL.
Example:
http://newday.blogs.cnn.com/2014/03/19/five-things-to-know-for-your-new-day-wednesday-march-19-2014/?hpt=hp_t2
has the url of "five-things-to-know-for-your-new-day-wednesday-march-19-2014", which was generated from the article title of "Five Things to Know for Your New Day – Wednesday, March 19, 2014"
In general, you should follow these guidelines:
Use GET when you want to fetch data from the server. Think of search engines. You can see your search query in the query string. You can also book mark it. It doesn't change anything on the server at all.
Use POST when you want to create a resource.
Use PUT when you want to create resources, but it also overwrites them. If you PUT an object twice, the servers state is only changed once. The opposite is true for POST
Use DELETE when you want to delete stuff
Neither POST nor PUT use the query string. GET does

What object (key-value) can I use for actionscript's URLRequest/Loader classes?

I am trying to get my Actionscript program to turn in a key-value (more specifically: a key, value1, value2) object into a server. I am doing the html request properly, but I'm not sure what kind of object to send; can anyone help?
--Thanks
When I understand correctly you want to post an object to the server, which has 1 key and multiple values. The latter is not supported by a HTTP_POST/GET call, you could however use something as AMF to send a VO from Flash over to a server and decode the AMF object on the server. Not sure whether or not that is where you are looking for, or you just want to post 2 values to a server.
Posting 2 values to a server is simple, but it requires two keys.
public function URLVariablesExample() {
var url:String = "http://www.domain.com/script.php";
var request:URLRequest = new URLRequest(url);
var variables:URLVariables = new URLVariables();
variables.keyOne = new Date().getTime();
variables.keyTwo = "Something";
request.data = variables;
navigateToURL(request);
}

Is it possible to get the current total Twitter followers number? and how often?

Here is the thing. I'd like to set up a counter that shows total number of Twitter followers for a user. When the number of followers reach exactly 1,000,000, would love to do something. If there's an api to do that, how often can I call the api.
Thanks.
Hello
Sorry I don't know PHP that well, and not at all JQuery, however, here is what I've done in C# ... hope it helps ;)
// Launch the request to obtain the number of followers of the user
WebRequest request = HttpWebRequest.Create("http://twitter.com/users/show.xml?screen_name=[username]");
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
StreamReader streamReader = new StreamReader(response.GetResponseStream());
// Load response in an XML Document
XmlDocument doc = new XmlDocument();
doc.LoadXml(streamReader.ReadToEnd());
// Parse the node we're interested in...
XmlNode node = doc.DocumentElement.SelectSingleNode("followers_count");
// ... and affect the number of followers
labelScore.Text = node.InnerText;
}
Yes, you can use the users/show call to get this information. You'll find it as a property named followers_count:
"followers_count": 160752,

Resources