Commit ba2de7c8 authored by Robert Knight's avatar Robert Knight

Convert "store" and "serviceUrl" services to use "apiRoutes"

Make these services use the "apiRoutes" service introduced in the
previous commit to fetch the API route directory and page links.
parent 5b214a6e
......@@ -33,9 +33,9 @@ var urlUtil = require('./util/url-util');
*
* @ngInject
*/
function serviceUrl(annotationUI, store) {
function serviceUrl(annotationUI, apiRoutes) {
store.links()
apiRoutes.links()
.then(annotationUI.updateLinks)
.catch(function(error) {
console.warn('The links API request was rejected: ' + error.message);
......
......@@ -2,7 +2,6 @@
var get = require('lodash.get');
var retryUtil = require('./retry-util');
var urlUtil = require('./util/url-util');
/**
......@@ -150,15 +149,15 @@ function createAPICall($http, $q, links, route, tokenGetter) {
*
* Returns an object that with keys that match the routes in
* the Hypothesis API (see http://h.readthedocs.io/en/latest/api/).
*
* This service handles authenticated calls to the API, using the `auth` service
* to get auth tokens. The URLs for API endpoints are fetched from the `/api`
* endpoint, a responsibility delegated to the `apiRoutes` service which does
* not use authentication.
*/
// @ngInject
function store($http, $q, auth, settings) {
var links = retryUtil.retryPromiseOperation(function () {
return $http.get(settings.apiUrl);
}).then(function (response) {
return response.data.links;
});
function store($http, $q, apiRoutes, auth) {
var links = apiRoutes.routes();
function apiCall(route) {
return createAPICall($http, $q, links, route, auth.tokenGetter);
}
......@@ -178,7 +177,9 @@ function store($http, $q, auth, settings) {
read: apiCall('profile.read'),
update: apiCall('profile.update'),
},
links: apiCall('links'),
// The `links` endpoint is not included here. Clients should fetch these
// from the `apiRoutes` service.
};
}
......
......@@ -26,19 +26,19 @@ function createServiceUrl(linksPromise) {
var annotationUI = fakeAnnotationUI();
var store = {
var apiRoutes = {
links: sinon.stub().returns(linksPromise),
};
return {
annotationUI: annotationUI,
store: store,
serviceUrl: serviceUrlFactory(annotationUI, store),
apiRoutes,
serviceUrl: serviceUrlFactory(annotationUI, apiRoutes),
replaceURLParams: replaceURLParams,
};
}
describe('links', function () {
describe('sidebar.service-url', function () {
beforeEach(function() {
sinon.stub(console, 'warn');
......@@ -50,7 +50,7 @@ describe('links', function () {
context('before the API response has been received', function() {
var serviceUrl;
var store;
var apiRoutes;
beforeEach(function() {
// Create a serviceUrl function with an unresolved Promise that will
......@@ -58,12 +58,12 @@ describe('links', function () {
var parts = createServiceUrl(new Promise(function() {}));
serviceUrl = parts.serviceUrl;
store = parts.store;
apiRoutes = parts.apiRoutes;
});
it('sends one API request for the links at boot time', function() {
assert.calledOnce(store.links);
assert.isTrue(store.links.calledWithExactly());
assert.calledOnce(apiRoutes.links);
assert.isTrue(apiRoutes.links.calledWithExactly());
});
it('returns an empty string for any link', function() {
......
......@@ -5,13 +5,60 @@ var proxyquire = require('proxyquire');
var util = require('../../shared/test/util');
describe('store', function () {
// API route directory.
// This should mirror the structure (but not the exact URLs) of
// https://hypothes.is/api/.
var routes = {
annotation: {
create: {
method: 'POST',
url: 'http://example.com/api/annotations',
},
delete: {
method: 'DELETE',
url: 'http://example.com/api/annotations/:id',
},
read: {},
update: {
method: 'PUT',
url: 'http://example.com/api/annotations/:id',
},
flag: {
method: 'PUT',
url: 'http://example.com/api/annotations/:id/flag',
},
hide: {
method: 'PUT',
url: 'http://example.com/api/annotations/:id/hide',
},
unhide: {
method: 'DELETE',
url: 'http://example.com/api/annotations/:id/hide',
},
},
search: {
method: 'GET',
url: 'http://example.com/api/search',
},
profile: {
read: {
method: 'GET',
url: 'http://example.com/api/profile',
},
update: {
method: 'PATCH',
url: 'http://example.com/api/profile',
},
},
};
describe('sidebar.store', function () {
var $httpBackend = null;
var sandbox = null;
var store = null;
before(function () {
angular.module('h')
angular.module('h', [])
.service('store', proxyquire('../store', util.noCallThru({
angular: angular,
'./retry-util': {
......@@ -25,9 +72,14 @@ describe('store', function () {
beforeEach(function () {
sandbox = sinon.sandbox.create();
var fakeApiRoutes = {
links: sinon.stub(),
routes: sinon.stub(),
};
var fakeAuth = {};
angular.mock.module('h', {
apiRoutes: fakeApiRoutes,
auth: fakeAuth,
settings: {apiUrl: 'http://example.com/api/'},
});
......@@ -37,6 +89,8 @@ describe('store', function () {
fakeAuth.tokenGetter = function () {
return $q.resolve('faketoken');
};
fakeApiRoutes.routes.returns($q.resolve(routes));
});
});
......@@ -49,56 +103,6 @@ describe('store', function () {
beforeEach(angular.mock.inject(function (_$httpBackend_, _store_) {
$httpBackend = _$httpBackend_;
store = _store_;
$httpBackend.expectGET('http://example.com/api/').respond({
// Return an API route directory.
// This should mirror the structure (but not the exact URLs) of
// https://hypothes.is/api/.
links: {
annotation: {
create: {
method: 'POST',
url: 'http://example.com/api/annotations',
},
delete: {
method: 'DELETE',
url: 'http://example.com/api/annotations/:id',
},
read: {},
update: {
method: 'PUT',
url: 'http://example.com/api/annotations/:id',
},
flag: {
method: 'PUT',
url: 'http://example.com/api/annotations/:id/flag',
},
hide: {
method: 'PUT',
url: 'http://example.com/api/annotations/:id/hide',
},
unhide: {
method: 'DELETE',
url: 'http://example.com/api/annotations/:id/hide',
},
},
search: {
method: 'GET',
url: 'http://example.com/api/search',
},
profile: {
read: {
method: 'GET',
url: 'http://example.com/api/profile',
},
update: {
method: 'PATCH',
url: 'http://example.com/api/profile',
},
},
},
});
$httpBackend.flush();
}));
it('saves a new annotation', function (done) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment