$http.get to SharePoint Online failing from Outlook Add-in - angularjs

I am writing an Outlook Add-In (for Office 365) using AngularJs (v. 1.3.15) that is using $http.get to call the SharePoint Online search API. I have abstracted my search calls into an Angular factory which I call from the primary controller.
The issue is that the $http.get call never calls the callback success or error functions. If I trace it in IE, I don't even see the request to SharePoint Online go over the wire.
Using very similar code in a stand alone Angular SPA, it works just fine. Here is some pseudo code to illustrate what I am doing...
App Controller
searchFactory.search(terms).then(function(response){
$scope.results = response.data;
},
function(error){
$scope.status = "Error";
});
Search factory:
factory.search = function(terms){
var queryStr = buildQueryStr(terms);
var results = $http.get(queryStr);
return results;
}
The factory code executes but I never see the request to the search endpoint go over the wire and neither the success nor the error function in the call in the controller is triggered.
The only error in the JavaScript console is something about no conversationId, but that doesn't seem relevant given that I'm calling the SPO API. Worth noting that the call is X-domain.
I am totally stumped. Any pointers are appreciated.

According to dev.office.com, cross-domain requests are blocked by Outlook Web due to same-origin policy:
http://dev.office.com/docs/add-ins/develop/addressing-same-origin-policy-limitations
I believe the SharePoint online API supports CORS so you can use that to get around the policy.
https://msdn.microsoft.com/en-us/office/office365/howto/create-web-apps-using-cors-to-access-files-in-office-365

Related

Detecting when a user's click goes to the server and when it does not in AngularJS web app

Is there a way to detect when a user's click somewhere in our web app accesses to the server and when it does not? We need this knowledge for a simple keep alive mechanism we want to add to the app. I have already implemented the functionality to detect user clicks anywahere in page, using help from this post: Click everywhere but here event. And now we need to add functionality to detect when the click causes an access to server and when it doesn't (because we use two timers in our keep alive, one for server session and one for client session).
The backend is implemented in ASP.NET Core Web API.
Thanks,
ashilon
The least invasive solution I can think of would be to add a request or response interceptor to the $http service that would track the time of the last event. It might look something like this, but obviously would have to be modified for the particulars of your angularjs app.
angular.module('yourAppName').
service('SessionInterceptor',
['$q', '$rootScope',
function($q, $rootScope) {
'use strict';
return {
response: function(response) {
$rootScope.lastServerActivity = response.headers().date;
return response;
},
responseError: function(rejection) {
$rootScope.lastServerActivity = rejection.headers().date;
return $q.reject(rejection);
}
};
}]);
Then you can use the lastServerActivity to calculate an idle time on their next click or via a timer and kill the session if appropriate. You could just as easily implement the request side rather than the response side. You could also use javascript to get the date rather than from the http headers. Whatever you choose will be influenced by how you are doing the client side session timeouts.

Getting No response from google drive javascript api

I'm using google drive javascript api(v2) in my reactjs project.
And I'm using this function to get files from google drive.
this.getProjectObjects = function(query, callback)
{
var request = gapi.client.drive.files.list({
corpus : 'DEFAULT',
q : query,
fields : 'items(id,description,title,properties)'
});
request.then(function(resp) {
callback(resp.result.items)
}, function(err) {
console.log(err)
});
};
After authenticate the user, I can get the files using this function.
But, when I navigate to other react component, it's no longer working.
There is no response or error, api just hangs.
Silly thing is when I refresh page, it's working. Again if I navigate to other component, it's not working.
I'm using the same query, nothing changed during navigating.
Anyone have any ideas what the issue could be?
Thanks
You may want to check the Chrome devTools to see if you are encountering any problem when switching pages. Also in the documentation - Getting Started:
There are several ways to use the JavaScript client library to make API requests, but they all follow the same basic pattern:
The application loads the JavaScript client library.
The application initializes the library with API key, OAuth client ID, and API Discovery Document(s).
The application sends a request and processes the response.
The following sections show 3 common ways of using the JavaScript client library.
Option 1: Load the API discovery document, then assemble the request.
Option 2: Use gapi.client.request
Option 3: Use CORS
See the sample for code implementation on effectively loading and making API calls.
Hope this helps.

AngularJs + Django RESTful: session based authentication

I'm developing an angular web application that will replace the current website that we have. The current website uses session based authentication. At the moment, I can't access the hosted API with get or post requests.
I'm developing the angular application on my local computer using a python simple server, whereas the api is hosted online.
I would prefer to find a fix that's completely in angular since I can't change the API without help (it was written by my boss a while ago, and is now used in the production version). I don't have a login page so I'm just trying to provide the authentication information in my headers and requests.
My angular application was written independent of django. I just want to access the django backend
So far I'm trying the following to set the headers:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.headers.common = {'username': btoa('myUsername'), 'password': btoa('myPassword')
};
}]);
And in my service:
app.factory('Test', ['$resource', function($resource) {
return $resource('https://www.phonywebsite.org/en/api/test/')
};
I consistently get 301, 400 and 403 errors. Lately it's been mostly 301 errors and I get no response from the api. I'm using the Allow CORS chrome extension as a temporary fix to try to get to the api without getting a CORS policy error.
My questions
How can I fix the CORS errors without using the chrome extension?
How do I provide my authentication to my django backend that uses session based authentication making sure the csrf cookie its looking for is in the header?
To answer your first question, using the cors extension is a temporary solution and should mostly never be used cause your clients might not use it. To handle CORS, you need to understand how cross site API calls work. In short CORS is a mechanism that allows AJAX requests to circumvent their same origin limits. To handle such situations you need to update your backend and add
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
. Once you add this your settings.py should stop getting CORS issues.
To answer your second question, angular already provides you with support for CSRF so half of your battle is already won. What you need to do is add a patch on your module to start accepting csrf tokens (The name is a bit different in angular). You have already done this and done a good job of it as well:
var app = angular.module('app', ['...']);
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
What this would do is make sure that whenever you make a $http call your csrf token is set as well.
As a learning oppurtunity, you could also try using ng-cookies as well. To go further to explain this, whenever you make a call in angular , your request in bundled with cookies as well so you can easily access them in request.COOKIES.
You need to change how you are calling your API as well, something like:
app.factory('APIService', function ($http) {
return $http({url: 'https://www.phonywebsite.org/en/api/test/',
method: 'GET'})
}
You can obviously make modifications to this but I think this shows the $http usage to make you understand the general gist.
You can try to add some more authentication around your application here as well (or replace django auth with your own custom auth), but that is on your use case.
Hope this helps.

Angular $resource.save() not working?

I am trying to create a web app with Angular, and I need some help. I need to POST data to an api. Rather than using $http (which works), I'd like to use $resource, and save().
I've also used GET and query so far, and they work fine. But when I try to call save(), I never get a response. I also don't see a POST request go through when I check on the server side.
Here's my code for the $resource factory (normally with my actual API url, of course)
.factory('ExamplePosts', function($resource) {
return {
all: $resource('http://my.website.com/api/')
};
});
In my controller, I can run ExamplePosts.all.query() or .get(), and retrieve the results. (I also see the request in my server logs.)
I then tried running ExamplePosts.all.save(), and I did not see a POST request on the server logs. I can post to it through forms and it works, but there seems to be a problem with Angular.
Appreciate any help I can get, thanks!
You actually need to add a prefix "$" to the save method as .$save() not .save() read this for more on those that need the $prefix read more

Angularjs - $resource causing a 404 - method: OPTIONS

I am trying to get a basic $resource request via angularjs. I am running this on my local computer.
However, I get a 404. A simple get request on the browser loads the json.
Here is the request shown by chrome devtools. (Question: why is the request mode: OPTIONS? Could that be the problem?)
Request URL:http://example.com/api/rentable_properties.json
Request Method:OPTIONS
Status Code:404 Not Found
Here is my controller that is attempting to make the request:
'use strict';
angular.module('adminApp')
.factory('Property', function($resource)
{
return $resource('http://example.com/api/rentable_properties.json/:propertyId');
});
angular.module('adminApp')
.controller('PropertiesCtrl', function ($scope, Property, $location) {
$scope.properties = Property.query()
The answer here is that your browser is running into a cross domain issue
See http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/ for an explanation and Why am I getting an OPTIONS request instead of a GET request? for a question basically the same as yours.
As mentioned by #JSager, the problem was a cross domain issue.
Since I had control over the server side (running a Rails server), I had to change the server to it to receive cross-site requests.
In my case, I had to install a gem and follow it's instructions.
https://github.com/cyu/rack-cors
This fixed the issue for me. No changes made on the Angularjs based app.

Resources