SharePoint CAML + REST + Paging issue - rest

I suppose I have found another SP bug... but maybe I do something wrong.
I have this POST request:
https://dmsdev/coll/f7c592adcb4c4e5996c2de00d444a94c/_api/Web/Lists/GetByTitle('1')/GetItems?$expand=ContentType&$select=Id,SonarDocId,ContentTypeId,EncodedAbsURL,Modified,ContentType/Name
With body:
{"query":{"ViewXml":"<View><Query><OrderBy><FieldRef Name='Modified'/></OrderBy></Query><RowLimit>50</RowLimit></View>","ListItemCollectionPosition":{"PagingInfo":"Paged=TRUE&p_Modified=2017-08-10T07:25:28"}}}
As you can see I do a CAML query with ORDER BY Modified column and I want to take items starting from the item after the item with some modified date but looks like this is not working... I mean similar request on other SP environment works, and on the other env it is not working... it takes all items starting from the first one after ordering by modified... I have no idea what is wrong :/

You could check my sample test script.
<script type="text/javascript">
function restCallwithCaml(listName, caml,PID) {
/// get the site url
var siteUrl = _spPageContextInfo.siteAbsoluteUrl;
/// set request data
var data = {
"query": {
"__metadata":
{ "type": "SP.CamlQuery" },
"ViewXml": caml,
"ListItemCollectionPosition": {
"PagingInfo": "Paged=TRUE&p_ID=" + PID
}
}
};
/// make an ajax call
return $.ajax({
url: siteUrl + "/_api/web/lists/GetByTitle('" + listName + "')/GetItems",
method: "POST",
data: JSON.stringify(data),
headers: {
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
'content-type': 'application/json;odata=verbose',
'accept': 'application/json;odata=verbose'
}
});
}
function GetItemsPaging() {
var pageLimit = 2;
var pageNumber = 0;
var caml = "<View><Query><Where><Geq><FieldRef Name='ID'/><Value Type='Number'>1</Value></Geq></Where></Query><RowLimit>" + pageLimit + "</RowLimit></View>";
var listName = "ChildB";
restCallwithCaml(listName, caml, pageNumber).done(function (data) {
if (data.d.results.length == pageLimit) {
pageNumber++;
//add to array or display
var PID=data.d.results[data.d.results.length - 1].Id;
alert(PID);
restCallwithCaml(listName, caml, PID).done(function (data) {
//add to array or display
alert(data.d.results[data.d.results.length - 1].Id);
})
}
});
}
</script>
Original thread

The problem was with my understanding of how this whole thing works + time zones
I had to write a paging query eg:
Paged=TRUE&p_ID=10&p_Modified=2018-12-14T18:52:00
So I had to add p_Modified parameter from the last item from the previous page... Additionally this data has to be in UTC, so for example I can execute get query with the time returned by the CAML
https://server/site/_api/web/RegionalSettings/TimeZone/localTimeToUTC(#date)?#date='2018-12-14T11:52:00'
And date returned by this call should be passed in p_Modified.

Related

Change filename of existing file on SharePoint Document library using REST API

I have a question on how to change an existing file on SharePoint document library using REST API. I have a couple of files in the location http://site url/<RootFolder>/<SubFolder>/File.docx. I have a UI where it lists all the files from this subfloder location. When the user clicks on edit i am enabling the file name as textbox where the user can change the name of the file.
After doing some research i found that Constructing an endpoint that looks like this: https://<site url>/_api/web/lists/getbytitle('Documents')/items(<item id>) we can edit the file metadata properties. But i could not able to figure out the best way to update the filename of existing document that resides on SharePoint Doc library.
Could someone please help me with the REST API query to fetch the file and the approach to update the filename?
You could consider at least two options:
Option 1. Rename file name
You could update the name of the existing list item as demonstrated below
Example
function rename(webUrl,listTitle,itemId,fileName){
var endpointUrl = webUrl + "/_api/web/lists/getbytitle('" + listTitle + "')/items(" + itemId + ")";
return executeJson(endpointUrl)
.then(function(data){
var itemPayload = {};
itemPayload['__metadata'] = {'type': data.d['__metadata']['type']};
itemPayload['Title'] = fileName;
itemPayload['FileLeafRef'] = fileName;
var itemUrl = data.d['__metadata']['uri'];
var headers = {};
headers["X-HTTP-Method"] = "MERGE";
headers["If-Match"] = "*";
return executeJson(itemUrl,"POST",headers,itemPayload);
});
}
var webUrl = _spPageContextInfo.webAbsoluteUrl; // web url
var listTitle = "Documents"; //list title
var itemId = 1; //list item id
var fileName = "SP User Guide.docx"; //new file name
rename(webUrl,listTitle,itemId,fileName)
.done(function(item){
console.log('Renamed');
})
.fail(function(error){
console.log(error);
});
Option 2. Move file via MoveTo REST endpoint
Example
function moveTo(webUrl,sourceFileUrl,targetFileUrl){
var endpointUrl = webUrl + "/_api/web/getfilebyserverrelativeurl('" + sourceFileUrl + "')/moveto(newurl='" + targetFileUrl + "',flags=1)";
return executeJson(endpointUrl,"POST");
}
var webUrl = _spPageContextInfo.webAbsoluteUrl; // web url
var sourceFileUrl = "/Documents/SP2010.docx";
var targetFileUrl = "/Documents/SP2013.docx";
moveTo(webUrl,sourceFileUrl,targetFileUrl)
.done(function(item){
console.log('Done');
})
.fail(function(error){
console.log(error);
});
executeJson function:
function executeJson(url,method,headers,payload)
{
headers = headers || {};
method = method || 'GET';
headers["Accept"] = "application/json;odata=verbose";
if(method == "POST") {
headers["X-RequestDigest"] = $("#__REQUESTDIGEST").val();
}
var ajaxOptions =
{
url: url,
type: method,
contentType: "application/json;odata=verbose",
headers: headers
};
if(method == "POST") {
ajaxOptions.data = JSON.stringify(payload);
}
return $.ajax(ajaxOptions);
}
You need to use the MoveTo Method to do this as described here in MSDN https://msdn.microsoft.com/en-us/library/office/dn450841.aspx#bk_FileMoveTo.
executor.executeAsync({
url: "<app web url>/_api/SP.AppContextSite(#target)/web
/getfilebyserverrelativeurl('/Shared Documents/filename.docx')
/moveto(newurl='/Other Folder/filename.docx',flags=1)
?#target='<host web url>'",
method: "POST",
success: successHandler,
error: errorHandler
});

Sails GET request doesn't return data from all columns in my Postgres DB

I'm using $sailsSocket to make my GET and POST requests. My POST request looks like this;
$sailsSocket.post('/schedules/toDateObj',
{ jobSchedObj:
{ repair_shop_equipment_id: response.config.data.schedEquip.rsrcId,
repair_history_id: response.data.id,
technician_id: response.data.technician_id,
allotted_time: response.data.allotted_time,
times: timeObj,
repair_shop_id: $localstorage.get('shopId')
}
})
.success(function(){
$location.path('/app/checkin');
})
.error(function (response){
console.log(response);
});
And here is the table it saves to...
Everything saves fine I even threw a console.log in my ScheduleController to check what was being inserted in the database with my POST request. Here is the output;
The problem is when I make a GET request to the Schedule table it comes back with everything except repair_shop_equipment_id. Here is the get request;
var firstDay = scope.getJobsFor[0];
var lowerBound = firstDay.open_time;
var lastDay = scope.getJobsFor[scope.getJobsFor.length - 1];
var upperBound = lastDay.close_time;
$sailsSocket.get("/schedules", {params:
{where: {
repair_shop_id: scope.shopId,
technician_id: scope.schedTech.id,
repair_shop_equipment_id: scope.schedEquip.rsrcId,
scheduled_start_time:{ date: {'>':lowerBound, '<':upperBound}}
}
}
})
.success(function (response){
And this is the response...
Here is a link to a Gist with my associated Sails models and the schedule controller;
Is there something wrong with one of my model configurations? Thanks.

Posting custom stories to Facebook with batch request

I have a web application that allows users to post custom stories to their Facebook timeline with the list of fitness exercises they have performed.
The first version is looping through the exercises and calling FP.api for each exercise and it works fine.
Now I would like to make a single call to FB.api with a batch request to speed up the posting and that's where I'm having trouble.
Here is the code with the loop that works fine (exids is an array of numbers):
function postToFB(exids)
{
fbi = 0;
fblength = exids.length;
for (var i = 0; i < fblength; i++)
{
FB.api(
'me/' + vitNamespace + ':perform',
'post',
{
exercise: "http://www.vitalclub.net/scripts/getExforFB.php?exid=" + exids[i],
'fb:explicitly_shared': true
},
function(response) {
...
});
}
}
and here is the code with the batch request that returns an error:
function postToFB(exids)
{
var batcharr = [];
for (var i = 0; i < exids.length; i++)
batcharr.push({ method: 'post', relative_url: 'me/' + vitNamespace + ':perform', body: "exercice=http://www.vitalclub.net/scripts/getExforFB.php%3Fexid%3D" + exids[i] + "&fb:explicitly_shared=true" });
FB.api(
'/',
'post',
{ batch: batcharr, include_headers: false },
function(response) {
...
});
}
The error I get (for each exercise) is the following: The action you're trying to publish is invalid because it does not specify any reference objects. At least one of the following properties must be specified: exercise.
I presume this has to do with the way the body in the batch request is formatted but I cannot find the right way to format it. I have tried using encodeURIComponent on the URL representing the exercise but the error is the same.
Anybody has an idea of what the problem is?
Thanks,
Jean
OK, my bad. It was really a stupid error. I had written the parameter "exercise" in French instead of English (so "exercice" instead of "exercise") and that's where the problem was.
I'm also now using $.param to format the parameters so I now have:
var batcharr = [];
var opts;
for (var i = 0; i < exids.length; i++)
{
opts = { exercise: "http://www.vitalclub.net/scripts/getExforFB.php?exid=" + exids[i], 'fb:explicitly_shared': true };
batcharr.push({ method: 'post', relative_url: 'me/' + vitNamespace + ':perform', body: $.param(opts) });
}
before calling FB.api and it works like a charm!

Facebook api multiple request

I am creating a facebook application generator. And I need to check if the user has currently added the application on this facebook page or not.
In order to do that, i first request facebook api to give a list of his pages. Then i loop through all the pages. And request for apps on each of these pages.
Lastly i compare the appId with the one user just created and displays the display the warning accordingly.
The problem is , when i loop through each of the pageId and request FbApi for subpages, the request response is delayed and the for each loop completes its cycle before the results are fetched from facebook.
Here is my code, which is quite complex... Any ideas to fix the issue is highly appreciated.
FB.login(function (response) {
FB.api('/me/accounts', function (apiresponse) {
var totalPages = apiresponse.data.length;
var pageIndex = 0;
$.each(apiresponse.data, function (pageNumber, pageData) {
var pageAccessToken = pageData.access_token;
var tabPageName = pageData.name;
var tabPageId = pageData.id;
FB.api("/" + tabPageId + "/tabs", function (response) {
var foundApp = false
$.each(response.data, function (index, value) {
var exsistingAppId = (value.id).split("app_").pop();
if (exsistingAppId == fbAppId) {
foundApp = true;
}
});
if (foundApp === true) {
var data = {
PageId: tabPageId,
Url: window.location.href.split("/").pop()
}
$.ajax({
type: "POST",
url: '/facebook/Match',
contentType: "application/json",
data: JSON.stringify(data),
success: function (data) {
if (data == "True") {
$("#addToFacebookModal ul").append("<li><span class='pageTab'><a class='pageTabName' target='_blank' href='https://facebook.com/profile.php?id=" +tabPageId + "'>" +tabPageName + "</a></span><a class='deleteAppFromPageTab' data-id='" +tabPageId + "' data-accessToken='" +pageAccessToken + "'>[x]</a></li>");
alreadyAdded.push(true);
} else {
alreadyAdded.push(false);
}
pageIndex++;
if (pageIndex == totalPages) {
console.log("Total Pages = " + totalPages + ", Looped through = " + alreadyAdded.length);
if (alreadyAdded.indexOf(true) >= 0) {
$("#addToFacebookModal").modal();
} else {
addToFacebook();
}
}
}
});
}
else {
pageIndex++;
}
});
});
});
}, { scope: 'manage_pages' });
Here is pseudocode of what i am doing
var myVariable
-Fb.Api Callback function returns response array
-Loop through the response array
-Get new Response array based on the previous response in that array
-Loop through each item of the new response array and compare it with myVariable.
The problem is that responses are delayed while the loop finishes up before the responses arrive. As i result i cant compare the nested Item with myVariable.
If by "facebook page" you mean a business page / organization page (not a profile), you can get the same information more easily by checking the endpoint '/{{page_id}}/tabs/{{app_id}}.
Replace page_id with the ID of the page you want to check and app_id similarly with your app ID. I don't have working code at the moment, but something like this:
FB.api(
'/' + checkPageID + '/tabs/{{app_id}}',
function (response) {
// Do console.log(response) to figure out how to see if installed or not
}
)
YOu can use fields expansion:
https://developers.facebook.com/docs/graph-api/using-graph-api/v2.3#fieldexpansion
FB.api('/me/accounts', {fields: 'name, address{city}'},function (response)
{
//do something here.
}

JQuery AJAX get not working correctly?

I have a partial view with this jquery script:
$("#btnGetEmpInfo").click(function () {
var selectedItem = $('#EmployeeId').val();
var focusItem = $('#EmployeeId')
alert("Starting");
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
url: "<%= Url.Action("getEmpInfo", "NewEmployee")%>?sData=" + selectedItem,
data: "{}",
success: function(data) {
if (data.length > 0) {
alert("Yeah!");
} else {
alert("No data returned!");
}
}
});
alert("Back!");
});
Then in my controller I have:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getEmpInfo(string sData)
{
return new JsonResult { Data = "test" };
}
I can breakpoint in the controller and it is hitting, but the only "Alerts" I get are the "Starting" and "Back". Why would the data not be returned or at least hit saying no data returned?
Thanks in advance for any and all help.
Geo...
You probably might want to improve this ajax call like this:
$.ajax({
type: 'GET',
url: '<%= Url.Action("getEmpInfo", "NewEmployee")%>',
data: { sData: selectedItem },
success: function(data) {
// Warning: your controller action doesn't return an array
// so don't expect a .length property here. See below
alert(data.Data);
}
});
and have your controller action accept GET requests:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getEmpInfo(string sData)
{
return Json(new { Data = "test" }, JsonRequestBehavior.AllowGet);
}
OK, now that we have fixed the error let me elaborate. In your code you were using an application/json content type to format your request string. Unfortunately in ASP.NET MVC 2 there is nothing out of the box that is capable of making sense of JSON requests (unless you wrote a custom json value provider factory). Then using string concatenation to append the sData parameter to the URL without ever URL encoding it meaning that your code would break at the very moment the user enters some special character such as & in the EmployeeId textbox.
Try adding the 'beforeSend', 'error' and 'complete' callbacks to get more info in your javascript debugger. http://api.jquery.com/jQuery.ajax/
Are you using a javascript debugger? (firebug, ie9 dev-tools, chrome dev-tools are decent ones 3 that come to mind)