Commit db95bfeb authored by Robert Knight's avatar Robert Knight

Rename src/sidebar/{store => services/api}

Give the service which provides a client for the Hypothesis API a more
obvious name and place it in a `services/` dir in accordance with the
plan outlined in #687. The previous name of "store" was particularly
confusing because of the existence of another kind of unrelated store
(the Redux one) in the application.

The service was previously registered with the `factory` method but has
the same structure as all the other services which are registered with
`service`, so I changed that for consistency.
parent ae142778
......@@ -12,7 +12,7 @@ function getExistingAnnotation(annotationUI, id) {
// Wraps the annotation store to trigger events for the CRUD actions
// @ngInject
function annotationMapper($rootScope, annotationUI, store) {
function annotationMapper($rootScope, annotationUI, api) {
function loadAnnotations(annotations, replies) {
annotations = annotations.concat(replies || []);
......@@ -46,7 +46,7 @@ function annotationMapper($rootScope, annotationUI, store) {
}
function deleteAnnotation(annotation) {
return store.annotation.delete({
return api.annotation.delete({
id: annotation.id,
}).then(function () {
$rootScope.$broadcast(events.ANNOTATION_DELETED, annotation);
......@@ -55,7 +55,7 @@ function annotationMapper($rootScope, annotationUI, store) {
}
function flagAnnotation(annot) {
return store.annotation.flag({
return api.annotation.flag({
id: annot.id,
}).then(function () {
$rootScope.$broadcast(events.ANNOTATION_FLAGGED, annot);
......
......@@ -5,18 +5,18 @@
*
* @return Promise<Array<Annotation>>
*/
function fetchThread(store, id) {
function fetchThread(api, id) {
var annot;
return store.annotation.get({id: id}).then(function (annot) {
return api.annotation.get({id: id}).then(function (annot) {
if (annot.references && annot.references.length) {
// This is a reply, fetch the top-level annotation
return store.annotation.get({id: annot.references[0]});
return api.annotation.get({id: annot.references[0]});
} else {
return annot;
}
}).then(function (annot_) {
annot = annot_;
return store.search({references: annot.id});
return api.search({references: annot.id});
}).then(function (searchResult) {
return [annot].concat(searchResult.rows);
});
......@@ -24,7 +24,7 @@ function fetchThread(store, id) {
// @ngInject
function AnnotationViewerContentController (
$location, $routeParams, annotationUI, rootThread, streamer, store,
$location, $routeParams, annotationUI, api, rootThread, streamer,
streamFilter, annotationMapper
) {
var self = this;
......@@ -45,7 +45,7 @@ function AnnotationViewerContentController (
annotationUI.setCollapsed(id, collapsed);
};
this.ready = fetchThread(store, id).then(function (annots) {
this.ready = fetchThread(api, id).then(function (annots) {
annotationMapper.loadAnnotations(annots);
var topLevelAnnot = annots.filter(function (annot) {
......
......@@ -26,8 +26,8 @@ function updateModel(annotation, changes, permissions) {
// @ngInject
function AnnotationController(
$document, $rootScope, $scope, $timeout, $window, analytics, annotationUI,
annotationMapper, drafts, flash, groups, permissions, serviceUrl,
session, settings, store, streamer) {
annotationMapper, api, drafts, flash, groups, permissions, serviceUrl,
session, settings, streamer) {
var self = this;
var newlyCreatedByHighlightButton;
......@@ -38,9 +38,9 @@ function AnnotationController(
var updating = !!annot.id;
if (updating) {
saved = store.annotation.update({id: annot.id}, annot);
saved = api.annotation.update({id: annot.id}, annot);
} else {
saved = store.annotation.create({}, annot);
saved = api.annotation.create({}, annot);
}
return saved.then(function (savedAnnot) {
......
......@@ -3,7 +3,7 @@
var annotationMetadata = require('../annotation-metadata');
// @ngInject
function ModerationBannerController(annotationUI, flash, store) {
function ModerationBannerController(annotationUI, flash, api) {
var self = this;
this.flagCount = function () {
......@@ -27,7 +27,7 @@ function ModerationBannerController(annotationUI, flash, store) {
* Hide an annotation from non-moderator users.
*/
this.hideAnnotation = function () {
store.annotation.hide({id: self.annotation.id}).then(function () {
api.annotation.hide({id: self.annotation.id}).then(function () {
annotationUI.hideAnnotation(self.annotation.id);
}).catch(function () {
flash.error('Failed to hide annotation');
......@@ -38,7 +38,7 @@ function ModerationBannerController(annotationUI, flash, store) {
* Un-hide an annotation from non-moderator users.
*/
this.unhideAnnotation = function () {
store.annotation.unhide({id: self.annotation.id}).then(function () {
api.annotation.unhide({id: self.annotation.id}).then(function () {
annotationUI.unhideAnnotation(self.annotation.id);
}).catch(function () {
flash.error('Failed to unhide annotation');
......
......@@ -34,8 +34,8 @@ function groupIDFromSelection(selection, results) {
// @ngInject
function SidebarContentController(
$scope, analytics, annotationUI, annotationMapper, drafts, features, frameSync,
groups, rootThread, settings, streamer, streamFilter, store
$scope, analytics, annotationUI, annotationMapper, api, drafts, features, frameSync,
groups, rootThread, settings, streamer, streamFilter
) {
var self = this;
......@@ -100,7 +100,7 @@ function SidebarContentController(
}
function _loadAnnotationsFor(uris, group) {
var searchClient = new SearchClient(store.search, {
var searchClient = new SearchClient(api.search, {
// If no group is specified, we are fetching annotations from
// all groups in order to find out which group contains the selected
// annotation, therefore we need to load all chunks before processing
......
......@@ -3,7 +3,7 @@
// @ngInject
function StreamContentController(
$scope, $location, $route, $routeParams, annotationMapper, annotationUI,
queryParser, rootThread, searchFilter, store, streamFilter, streamer
api, queryParser, rootThread, searchFilter, streamFilter, streamer
) {
var self = this;
......@@ -28,7 +28,7 @@ function StreamContentController(
limit: limit,
}, searchFilter.toObject($routeParams.q));
store.search(query)
api.search(query)
.then(load)
.catch(function (err) {
console.error(err);
......
......@@ -104,7 +104,7 @@ describe('annotation', function() {
var fakeServiceUrl;
var fakeSession;
var fakeSettings;
var fakeStore;
var fakeApi;
var fakeStreamer;
var sandbox;
......@@ -222,7 +222,7 @@ describe('annotation', function() {
authDomain: 'localhost',
};
fakeStore = {
fakeApi = {
annotation: {
create: sinon.spy(function (annot) {
return Promise.resolve(Object.assign({}, annot));
......@@ -240,6 +240,7 @@ describe('annotation', function() {
$provide.value('analytics', fakeAnalytics);
$provide.value('annotationMapper', fakeAnnotationMapper);
$provide.value('annotationUI', fakeAnnotationUI);
$provide.value('api', fakeApi);
$provide.value('drafts', fakeDrafts);
$provide.value('flash', fakeFlash);
$provide.value('groups', fakeGroups);
......@@ -247,7 +248,6 @@ describe('annotation', function() {
$provide.value('session', fakeSession);
$provide.value('serviceUrl', fakeServiceUrl);
$provide.value('settings', fakeSettings);
$provide.value('store', fakeStore);
$provide.value('streamer', fakeStreamer);
}));
......@@ -345,7 +345,7 @@ describe('annotation', function() {
annotation.user = fakeSession.state.userid = 'acct:bill@localhost';
createDirective(annotation);
assert.called(fakeStore.annotation.create);
assert.called(fakeApi.annotation.create);
});
it('saves new highlights to drafts if not logged in', function() {
......@@ -355,7 +355,7 @@ describe('annotation', function() {
createDirective(annotation);
assert.notCalled(fakeStore.annotation.create);
assert.notCalled(fakeApi.annotation.create);
assert.called(fakeDrafts.update);
});
......@@ -364,7 +364,7 @@ describe('annotation', function() {
createDirective(annotation);
assert.notCalled(fakeStore.annotation.create);
assert.notCalled(fakeApi.annotation.create);
});
it('does not save old highlights on initialization', function() {
......@@ -372,7 +372,7 @@ describe('annotation', function() {
createDirective(annotation);
assert.notCalled(fakeStore.annotation.create);
assert.notCalled(fakeApi.annotation.create);
});
it('does not save old annotations on initialization', function() {
......@@ -380,7 +380,7 @@ describe('annotation', function() {
createDirective(annotation);
assert.notCalled(fakeStore.annotation.create);
assert.notCalled(fakeApi.annotation.create);
});
it('creates drafts for new annotations on initialization', function() {
......@@ -945,7 +945,7 @@ describe('annotation', function() {
it('flashes an error if saving the annotation fails on the server', function() {
var controller = createController();
var err = new Error('500 Server Error');
fakeStore.annotation.create = sinon.stub().returns(Promise.reject(err));
fakeApi.annotation.create = sinon.stub().returns(Promise.reject(err));
return controller.save().then(function() {
assert.calledWith(fakeFlash.error,
'500 Server Error', 'Saving annotation failed');
......@@ -962,7 +962,7 @@ describe('annotation', function() {
it('shows a saving indicator when saving an annotation', function() {
var controller = createController();
var create;
fakeStore.annotation.create = sinon.stub().returns(new Promise(function (resolve) {
fakeApi.annotation.create = sinon.stub().returns(new Promise(function (resolve) {
create = resolve;
}));
var saved = controller.save();
......@@ -975,7 +975,7 @@ describe('annotation', function() {
it('does not remove the draft if saving fails', function () {
var controller = createController();
fakeStore.annotation.create = sinon.stub().returns(Promise.reject({status: -1}));
fakeApi.annotation.create = sinon.stub().returns(Promise.reject({status: -1}));
return controller.save().then(function () {
assert.notCalled(fakeDrafts.remove);
});
......@@ -1005,7 +1005,7 @@ describe('annotation', function() {
it('flashes an error if saving the annotation fails on the server', function () {
var controller = createController();
var err = new Error('500 Server Error');
fakeStore.annotation.update = sinon.stub().returns(Promise.reject(err));
fakeApi.annotation.update = sinon.stub().returns(Promise.reject(err));
return controller.save().then(function() {
assert.calledWith(fakeFlash.error,
'500 Server Error', 'Saving annotation failed');
......
......@@ -4,7 +4,7 @@ var angular = require('angular');
// Fake implementation of the API for fetching annotations and replies to
// annotations.
function FakeStore(annots) {
function FakeApi(annots) {
this.annots = annots;
this.annotation = {
......@@ -51,12 +51,12 @@ describe('annotationViewerContent', function () {
highlightAnnotations: sinon.stub(),
subscribe: sinon.stub(),
},
api: opts.api,
rootThread: {thread: sinon.stub()},
streamer: {
setConfig: function () {},
connect: function () {},
},
store: opts.store,
streamFilter: {
setMatchPolicyIncludeAny: function () {
return {
......@@ -86,24 +86,24 @@ describe('annotationViewerContent', function () {
describe('the standalone view for a top-level annotation', function () {
it('loads the annotation and all replies', function () {
var fakeStore = new FakeStore([
var fakeApi = new FakeApi([
{id: 'test_annotation_id'},
{id: 'test_reply_id', references: ['test_annotation_id']},
]);
var controller = createController({store: fakeStore});
var controller = createController({api: fakeApi});
return controller.ctrl.ready.then(function () {
assert.calledOnce(controller.annotationMapper.loadAnnotations);
assert.calledWith(controller.annotationMapper.loadAnnotations,
sinon.match(fakeStore.annots));
sinon.match(fakeApi.annots));
});
});
it('does not highlight any annotations', function () {
var fakeStore = new FakeStore([
var fakeApi = new FakeApi([
{id: 'test_annotation_id'},
{id: 'test_reply_id', references: ['test_annotation_id']},
]);
var controller = createController({store: fakeStore});
var controller = createController({api: fakeApi});
return controller.ctrl.ready.then(function () {
assert.notCalled(controller.annotationUI.highlightAnnotations);
});
......@@ -112,23 +112,23 @@ describe('annotationViewerContent', function () {
describe('the standalone view for a reply', function () {
it('loads the top-level annotation and all replies', function () {
var fakeStore = new FakeStore([
var fakeApi = new FakeApi([
{id: 'parent_id'},
{id: 'test_annotation_id', references: ['parent_id']},
]);
var controller = createController({store: fakeStore});
var controller = createController({api: fakeApi});
return controller.ctrl.ready.then(function () {
assert.calledWith(controller.annotationMapper.loadAnnotations,
sinon.match(fakeStore.annots));
sinon.match(fakeApi.annots));
});
});
it('expands the thread', function () {
var fakeStore = new FakeStore([
var fakeApi = new FakeApi([
{id: 'parent_id'},
{id: 'test_annotation_id', references: ['parent_id']},
]);
var controller = createController({store: fakeStore});
var controller = createController({api: fakeApi});
return controller.ctrl.ready.then(function () {
assert.calledWith(controller.annotationUI.setCollapsed, 'parent_id', false);
assert.calledWith(controller.annotationUI.setCollapsed, 'test_annotation_id', false);
......@@ -136,11 +136,11 @@ describe('annotationViewerContent', function () {
});
it('highlights the reply', function () {
var fakeStore = new FakeStore([
var fakeApi = new FakeApi([
{id: 'parent_id'},
{id: 'test_annotation_id', references: ['parent_id']},
]);
var controller = createController({store: fakeStore});
var controller = createController({api: fakeApi});
return controller.ctrl.ready.then(function () {
assert.calledWith(controller.annotationUI.highlightAnnotations,
sinon.match(['test_annotation_id']));
......
......@@ -12,7 +12,7 @@ describe('moderationBanner', function () {
var bannerEl;
var fakeAnnotationUI;
var fakeFlash;
var fakeStore;
var fakeApi;
before(function () {
angular.module('app', [])
......@@ -29,7 +29,7 @@ describe('moderationBanner', function () {
error: sinon.stub(),
};
fakeStore = {
fakeApi = {
annotation: {
hide: sinon.stub().returns(Promise.resolve()),
unhide: sinon.stub().returns(Promise.resolve()),
......@@ -38,8 +38,8 @@ describe('moderationBanner', function () {
angular.mock.module('app', {
annotationUI: fakeAnnotationUI,
api: fakeApi,
flash: fakeFlash,
store: fakeStore,
});
});
......@@ -114,13 +114,13 @@ describe('moderationBanner', function () {
var ann = moderatedAnnotation({ flagCount: 10 });
var banner = createBanner({ annotation: ann });
banner.querySelector('button').click();
assert.calledWith(fakeStore.annotation.hide, {id: 'ann-id'});
assert.calledWith(fakeApi.annotation.hide, {id: 'ann-id'});
});
it('reports an error if hiding the annotation fails', function (done) {
var ann = moderatedAnnotation({ flagCount: 10 });
var banner = createBanner({ annotation: ann });
fakeStore.annotation.hide.returns(Promise.reject(new Error('Network Error')));
fakeApi.annotation.hide.returns(Promise.reject(new Error('Network Error')));
banner.querySelector('button').click();
......@@ -139,7 +139,7 @@ describe('moderationBanner', function () {
banner.querySelector('button').click();
assert.calledWith(fakeStore.annotation.unhide, {id: 'ann-id'});
assert.calledWith(fakeApi.annotation.unhide, {id: 'ann-id'});
});
it('reports an error if unhiding the annotation fails', function (done) {
......@@ -148,7 +148,7 @@ describe('moderationBanner', function () {
hidden: true,
});
var banner = createBanner({ annotation: ann });
fakeStore.annotation.unhide.returns(Promise.reject(new Error('Network Error')));
fakeApi.annotation.unhide.returns(Promise.reject(new Error('Network Error')));
banner.querySelector('button').click();
......
......@@ -49,7 +49,7 @@ describe('sidebar.components.sidebar-content', function () {
var fakeGroups;
var fakeRootThread;
var fakeSettings;
var fakeStore;
var fakeApi;
var fakeStreamer;
var fakeStreamFilter;
var sandbox;
......@@ -116,17 +116,17 @@ describe('sidebar.components.sidebar-content', function () {
fakeSettings = {};
fakeStore = {
fakeApi = {
search: sinon.stub(),
};
$provide.value('analytics', fakeAnalytics);
$provide.value('annotationMapper', fakeAnnotationMapper);
$provide.value('api', fakeApi);
$provide.value('drafts', fakeDrafts);
$provide.value('features', fakeFeatures);
$provide.value('frameSync', fakeFrameSync);
$provide.value('rootThread', fakeRootThread);
$provide.value('store', fakeStore);
$provide.value('streamer', fakeStreamer);
$provide.value('streamFilter', fakeStreamFilter);
$provide.value('groups', fakeGroups);
......
......@@ -19,7 +19,7 @@ describe('StreamContentController', function () {
var fakeQueryParser;
var fakeRootThread;
var fakeSearchFilter;
var fakeStore;
var fakeApi;
var fakeStreamer;
var fakeStreamFilter;
......@@ -59,7 +59,7 @@ describe('StreamContentController', function () {
toObject: sinon.stub().returns({}),
};
fakeStore = {
fakeApi = {
search: sinon.spy(function () {
return Promise.resolve({rows: [], total: 0});
}),
......@@ -85,10 +85,10 @@ describe('StreamContentController', function () {
$routeParams: fakeRouteParams,
annotationMapper: fakeAnnotationMapper,
annotationUI: fakeAnnotationUI,
api: fakeApi,
queryParser: fakeQueryParser,
rootThread: fakeRootThread,
searchFilter: fakeSearchFilter,
store: fakeStore,
streamFilter: fakeStreamFilter,
streamer: fakeStreamer,
});
......@@ -110,11 +110,11 @@ describe('StreamContentController', function () {
it('calls the search API with `_separate_replies: true`', function () {
createController();
assert.equal(fakeStore.search.firstCall.args[0]._separate_replies, true);
assert.equal(fakeApi.search.firstCall.args[0]._separate_replies, true);
});
it('passes the annotations and replies from search to loadAnnotations()', function () {
fakeStore.search = function () {
fakeApi.search = function () {
return Promise.resolve({
'rows': ['annotation_1', 'annotation_2'],
'replies': ['reply_1', 'reply_2', 'reply_3'],
......
......@@ -18,8 +18,8 @@ var { awaitStateChange } = require('./util/state-util');
var serviceConfig = require('./service-config');
// @ngInject
function groups(annotationUI, isSidebar, localStorage, serviceUrl, session,
settings, $rootScope, store) {
function groups($rootScope, annotationUI, api, isSidebar, localStorage, serviceUrl, session,
settings) {
// The currently focused group. This is the group that's shown as selected in
// the groups dropdown, the annotations displayed are filtered to only ones
// that belong to this group, and any new annotations that the user creates
......@@ -65,7 +65,7 @@ function groups(annotationUI, isSidebar, localStorage, serviceUrl, session,
if (uri) {
params.document_uri = uri;
}
return store.groups.list(params);
return api.groups.list(params);
}).then(gs => {
$rootScope.$apply(() => {
var focGroup = focused();
......@@ -104,7 +104,7 @@ function groups(annotationUI, isSidebar, localStorage, serviceUrl, session,
// The groups list will be updated in response to a session state
// change notification from the server. We could improve the UX here
// by optimistically updating the session state
return store.group.member.delete({
return api.group.member.delete({
pubid: id,
user: 'me',
});
......
......@@ -187,6 +187,7 @@ module.exports = angular.module('h', [
.service('analytics', require('./analytics'))
.service('annotationMapper', require('./annotation-mapper'))
.service('annotationUI', require('./annotation-ui'))
.service('api', require('./services/api'))
.service('apiRoutes', require('./api-routes'))
.service('auth', require('./oauth-auth'))
.service('bridge', require('../shared/bridge'))
......@@ -208,8 +209,6 @@ module.exports = angular.module('h', [
.service('unicode', require('./unicode'))
.service('viewFilter', require('./view-filter'))
.factory('store', require('./store'))
.value('Discovery', require('../shared/discovery'))
.value('ExcerptOverflowMonitor', require('./util/excerpt-overflow-monitor'))
.value('OAuthClient', require('./util/oauth-client'))
......
......@@ -2,7 +2,7 @@
var get = require('lodash.get');
var urlUtil = require('./util/url-util');
var urlUtil = require('../util/url-util');
/**
* Translate the response from a failed API call into an Error-like object.
......@@ -156,7 +156,7 @@ function createAPICall($http, $q, links, route, tokenGetter) {
* not use authentication.
*/
// @ngInject
function store($http, $q, apiRoutes, auth) {
function api($http, $q, apiRoutes, auth) {
var links = apiRoutes.routes();
function apiCall(route) {
return createAPICall($http, $q, links, route, auth.tokenGetter);
......@@ -192,4 +192,4 @@ function store($http, $q, apiRoutes, auth) {
};
}
module.exports = store;
module.exports = api;
......@@ -3,7 +3,7 @@
var angular = require('angular');
var proxyquire = require('proxyquire');
var util = require('../../shared/test/util');
var util = require('../../../shared/test/util');
// API route directory.
// This should mirror the structure (but not the exact URLs) of
......@@ -60,14 +60,14 @@ var routes = {
},
};
describe('sidebar.store', function () {
describe('sidebar.services.api', function () {
var $httpBackend = null;
var sandbox = null;
var store = null;
var api = null;
before(function () {
angular.module('h', [])
.service('store', proxyquire('../store', util.noCallThru({
.service('api', proxyquire('../api', util.noCallThru({
angular: angular,
'./retry-util': {
retryPromiseOperation: function (fn) {
......@@ -108,13 +108,13 @@ describe('sidebar.store', function () {
sandbox.restore();
});
beforeEach(angular.mock.inject(function (_$httpBackend_, _store_) {
beforeEach(angular.mock.inject(function (_$httpBackend_, _api_) {
$httpBackend = _$httpBackend_;
store = _store_;
api = _api_;
}));
it('saves a new annotation', function (done) {
store.annotation.create({}, {}).then(function (saved) {
api.annotation.create({}, {}).then(function (saved) {
assert.isNotNull(saved.id);
done();
});
......@@ -127,7 +127,7 @@ describe('sidebar.store', function () {
});
it('updates an annotation', function (done) {
store.annotation.update({id: 'an-id'}, {text: 'updated'}).then(function () {
api.annotation.update({id: 'an-id'}, {text: 'updated'}).then(function () {
done();
});
......@@ -139,7 +139,7 @@ describe('sidebar.store', function () {
});
it('deletes an annotation', function (done) {
store.annotation.delete({id: 'an-id'}, {}).then(function () {
api.annotation.delete({id: 'an-id'}, {}).then(function () {
done();
});
......@@ -151,7 +151,7 @@ describe('sidebar.store', function () {
});
it('flags an annotation', function (done) {
store.annotation.flag({id: 'an-id'}).then(function () {
api.annotation.flag({id: 'an-id'}).then(function () {
done();
});
......@@ -163,7 +163,7 @@ describe('sidebar.store', function () {
});
it('hides an annotation', function (done) {
store.annotation.hide({id: 'an-id'}).then(function () {
api.annotation.hide({id: 'an-id'}).then(function () {
done();
});
......@@ -175,7 +175,7 @@ describe('sidebar.store', function () {
});
it('unhides an annotation', function (done) {
store.annotation.unhide({id: 'an-id'}).then(function () {
api.annotation.unhide({id: 'an-id'}).then(function () {
done();
});
......@@ -188,7 +188,7 @@ describe('sidebar.store', function () {
describe('#group.member.delete', () => {
it('removes current user from a group', (done) => {
store.group.member.delete({pubid: 'an-id', user: 'me'}).then(function () {
api.group.member.delete({pubid: 'an-id', user: 'me'}).then(function () {
done();
});
......@@ -206,7 +206,7 @@ describe('sidebar.store', function () {
$notme: 'nooooo!',
allowed: 123,
};
store.annotation.create({}, annotation).then(function () {
api.annotation.create({}, annotation).then(function () {
done();
});
......@@ -220,7 +220,7 @@ describe('sidebar.store', function () {
// Our backend service interprets semicolons as query param delimiters, so we
// must ensure to encode them in the query string.
it('encodes semicolons in query parameters', function (done) {
store.search({'uri': 'http://example.com/?foo=bar;baz=qux'}).then(function () {
api.search({'uri': 'http://example.com/?foo=bar;baz=qux'}).then(function () {
done();
});
......@@ -231,7 +231,7 @@ describe('sidebar.store', function () {
it("fetches the user's profile", function (done) {
var profile = {userid: 'acct:user@publisher.org'};
store.profile.read({authority: 'publisher.org'}).then(function (profile_) {
api.profile.read({authority: 'publisher.org'}).then(function (profile_) {
assert.deepEqual(profile_, profile);
done();
});
......@@ -241,7 +241,7 @@ describe('sidebar.store', function () {
});
it("updates a user's profile", function (done) {
store.profile.update({}, {preferences: {}}).then(function () {
api.profile.update({}, {preferences: {}}).then(function () {
done();
});
......@@ -254,7 +254,7 @@ describe('sidebar.store', function () {
context('when an API calls fail', function () {
util.unroll('rejects the call with an Error', function (done, testCase) {
store.profile.update({}, {preferences: {}}).catch(function (err) {
api.profile.update({}, {preferences: {}}).catch(function (err) {
assert(err instanceof Error);
assert.equal(err.message, testCase.expectedMessage);
done();
......@@ -286,7 +286,7 @@ describe('sidebar.store', function () {
}]);
it("exposes details in the Error's `response` property", function (done) {
store.profile.update({}, {preferences: {}}).catch(function (err) {
api.profile.update({}, {preferences: {}}).catch(function (err) {
assert.match(err.response, sinon.match({
status: 404,
statusText: 'Not found',
......
......@@ -20,8 +20,8 @@ var CACHE_TTL = 5 * 60 * 1000; // 5 minutes
*
* @ngInject
*/
function session($q, $rootScope, analytics, annotationUI, auth,
flash, raven, settings, serviceConfig, store) {
function session($q, $rootScope, analytics, annotationUI, api, auth,
flash, raven, settings, serviceConfig) {
// Cache the result of load()
var lastLoad;
var lastLoadTime;
......@@ -62,7 +62,7 @@ function session($q, $rootScope, analytics, annotationUI, auth,
if (authority) {
opts.authority = authority;
}
return store.profile.read(opts);
return api.profile.read(opts);
}, profileFetchRetryOpts).then(function (session) {
update(session);
lastLoadTime = Date.now();
......@@ -80,7 +80,7 @@ function session($q, $rootScope, analytics, annotationUI, auth,
* tutorial and then update the local profile data.
*/
function dismissSidebarTutorial() {
return store.profile.update({}, {preferences: {show_sidebar_tutorial: false}}).then(update);
return api.profile.update({}, {preferences: {show_sidebar_tutorial: false}}).then(update);
}
/**
......
......@@ -9,11 +9,11 @@ describe('annotationMapper', function() {
var sandbox = sinon.sandbox.create();
var $rootScope;
var annotationUI;
var fakeStore;
var fakeApi;
var annotationMapper;
beforeEach(function () {
fakeStore = {
fakeApi = {
annotation: {
delete: sinon.stub().returns(Promise.resolve({})),
flag: sinon.stub().returns(Promise.resolve({})),
......@@ -22,8 +22,8 @@ describe('annotationMapper', function() {
angular.module('app', [])
.service('annotationMapper', require('../annotation-mapper'))
.service('annotationUI', require('../annotation-ui'))
.value('settings', {})
.value('store', fakeStore);
.value('api', fakeApi)
.value('settings', {});
angular.mock.module('app');
angular.mock.inject(function (_$rootScope_, _annotationUI_, _annotationMapper_) {
......@@ -129,8 +129,8 @@ describe('annotationMapper', function() {
it('flags an annotation', function () {
var ann = {id: 'test-id'};
annotationMapper.flagAnnotation(ann);
assert.calledOnce(fakeStore.annotation.flag);
assert.calledWith(fakeStore.annotation.flag, {id: ann.id});
assert.calledOnce(fakeApi.annotation.flag);
assert.calledWith(fakeApi.annotation.flag, {id: ann.id});
});
it('emits the "annotationFlagged" event', function (done) {
......@@ -163,7 +163,7 @@ describe('annotationMapper', function() {
it('deletes the annotation on the server', function () {
var ann = {id: 'test-id'};
annotationMapper.deleteAnnotation(ann);
assert.calledWith(fakeStore.annotation.delete, {id: 'test-id'});
assert.calledWith(fakeApi.annotation.delete, {id: 'test-id'});
});
it('triggers the "annotationDeleted" event on success', function (done) {
......@@ -178,7 +178,7 @@ describe('annotationMapper', function() {
it('does not emit an event on error', function (done) {
sandbox.stub($rootScope, '$broadcast');
fakeStore.annotation.delete.returns(Promise.reject());
fakeApi.annotation.delete.returns(Promise.reject());
var ann = {id: 'test-id'};
annotationMapper.deleteAnnotation(ann).catch(function () {
assert.notCalled($rootScope.$broadcast);
......
......@@ -17,7 +17,7 @@ describe('groups', function() {
var fakeIsSidebar;
var fakeSession;
var fakeSettings;
var fakeStore;
var fakeApi;
var fakeLocalStorage;
var fakeRootScope;
var fakeServiceUrl;
......@@ -54,7 +54,7 @@ describe('groups', function() {
$broadcast: sandbox.stub(),
};
fakeStore = {
fakeApi = {
group: {
member: {
delete: sandbox.stub().returns(Promise.resolve()),
......@@ -77,8 +77,8 @@ describe('groups', function() {
});
function service() {
return groups(fakeAnnotationUI, fakeIsSidebar, fakeLocalStorage, fakeServiceUrl, fakeSession,
fakeSettings, fakeRootScope, fakeStore);
return groups(fakeRootScope, fakeAnnotationUI, fakeApi, fakeIsSidebar, fakeLocalStorage, fakeServiceUrl,
fakeSession, fakeSettings);
}
describe('#all()', function() {
......@@ -120,7 +120,7 @@ describe('groups', function() {
return svc.load().then(() => {
svc.focus('id2');
}).then(() => {
fakeStore.groups.list = sandbox.stub().returns(Promise.resolve([
fakeApi.groups.list = sandbox.stub().returns(Promise.resolve([
{name: 'Group 3', id: 'id3'},
{name: 'Group 1', id: 'id1'},
]));
......@@ -139,7 +139,7 @@ describe('groups', function() {
fakeAnnotationUI.setState({ searchUris: ['https://asite.com'] });
return loaded.then(() => {
assert.calledWith(fakeStore.groups.list, { document_uri: 'https://asite.com' });
assert.calledWith(fakeApi.groups.list, { document_uri: 'https://asite.com' });
});
});
});
......@@ -153,7 +153,7 @@ describe('groups', function() {
fakeAnnotationUI.setState({ searchUris: [] });
var svc = service();
return svc.load().then(() => {
assert.calledWith(fakeStore.groups.list, {});
assert.calledWith(fakeApi.groups.list, {});
});
});
});
......@@ -162,7 +162,7 @@ describe('groups', function() {
fakeSettings.services = [{ authority: 'publisher.org' }];
var svc = service();
return svc.load().then(() => {
assert.calledWith(fakeStore.groups.list, sinon.match({ authority: 'publisher.org' }));
assert.calledWith(fakeApi.groups.list, sinon.match({ authority: 'publisher.org' }));
});
});
});
......@@ -270,7 +270,7 @@ describe('groups', function() {
it('should call the group leave API', function () {
var s = service();
return s.leave('id2').then(() => {
assert.calledWithMatch(fakeStore.group.member.delete, {
assert.calledWithMatch(fakeApi.group.member.delete, {
pubid: 'id2',
user: 'me',
});
......@@ -289,7 +289,7 @@ describe('groups', function() {
service();
return fakeRootScope.eventCallbacks[testCase.event]().then(() => {
assert.calledOnce(fakeStore.groups.list);
assert.calledOnce(fakeApi.groups.list);
});
}, changeEvents);
});
......
......@@ -15,7 +15,7 @@ describe('sidebar.session', function () {
var fakeRaven;
var fakeServiceConfig;
var fakeSettings;
var fakeStore;
var fakeApi;
var sandbox;
var session;
......@@ -47,7 +47,7 @@ describe('sidebar.session', function () {
fakeRaven = {
setUserInfo: sandbox.spy(),
};
fakeStore = {
fakeApi = {
profile: {
read: sandbox.stub(),
update: sandbox.stub().returns(Promise.resolve({})),
......@@ -61,12 +61,12 @@ describe('sidebar.session', function () {
mock.module('h', {
analytics: fakeAnalytics,
annotationUI: fakeAnnotationUI,
api: fakeApi,
auth: fakeAuth,
flash: fakeFlash,
raven: fakeRaven,
settings: fakeSettings,
serviceConfig: fakeServiceConfig,
store: fakeStore,
});
});
......@@ -87,14 +87,14 @@ describe('sidebar.session', function () {
authority: 'publisher.org',
grantToken: 'a.jwt.token',
});
fakeStore.profile.read.returns(Promise.resolve({
fakeApi.profile.read.returns(Promise.resolve({
userid: 'acct:user@publisher.org',
}));
});
it('should pass the "authority" param when fetching the profile', function () {
return session.load().then(function () {
assert.calledWith(fakeStore.profile.read, {authority: 'publisher.org'});
assert.calledWith(fakeApi.profile.read, {authority: 'publisher.org'});
});
});
......@@ -109,7 +109,7 @@ describe('sidebar.session', function () {
var clock;
beforeEach(() => {
fakeStore.profile.read.returns(Promise.resolve({
fakeApi.profile.read.returns(Promise.resolve({
userid: 'acct:user@hypothes.is',
}));
});
......@@ -122,15 +122,15 @@ describe('sidebar.session', function () {
it('should fetch profile data from the API', () => {
return session.load().then(() => {
assert.calledWith(fakeStore.profile.read);
assert.calledWith(fakeApi.profile.read);
});
});
it('should retry the profile fetch if it fails', () => {
fakeStore.profile.read.onCall(0).returns(
fakeApi.profile.read.onCall(0).returns(
Promise.reject(new Error('Server error'))
);
fakeStore.profile.read.onCall(1).returns(
fakeApi.profile.read.onCall(1).returns(
Promise.resolve({userid: 'acct:user@hypothes.is', groups: []})
);
......@@ -152,7 +152,7 @@ describe('sidebar.session', function () {
return session.load().then(() => {
return session.load();
}).then(() => {
assert.calledOnce(fakeStore.profile.read);
assert.calledOnce(fakeApi.profile.read);
});
});
......@@ -164,7 +164,7 @@ describe('sidebar.session', function () {
clock.tick(CACHE_TTL * 2);
return session.load();
}).then(() => {
assert.calledTwice(fakeStore.profile.read);
assert.calledTwice(fakeApi.profile.read);
});
});
});
......@@ -192,14 +192,14 @@ describe('sidebar.session', function () {
describe('#dismissSidebarTutorial()', function () {
beforeEach(function () {
fakeStore.profile.update.returns(Promise.resolve({
fakeApi.profile.update.returns(Promise.resolve({
preferences: {},
}));
});
it('disables the tutorial for the user', function () {
session.dismissSidebarTutorial();
assert.calledWith(fakeStore.profile.update, {}, {preferences: {show_sidebar_tutorial: false}});
assert.calledWith(fakeApi.profile.update, {}, {preferences: {show_sidebar_tutorial: false}});
});
it('should update the session with the response from the API', function () {
......@@ -212,14 +212,14 @@ describe('sidebar.session', function () {
describe('#reload', () => {
beforeEach(() => {
// Load the initial profile data, as the client will do on startup.
fakeStore.profile.read.returns(Promise.resolve({
fakeApi.profile.read.returns(Promise.resolve({
userid: 'acct:user_a@hypothes.is',
}));
return session.load();
});
it('should clear cached data and reload', () => {
fakeStore.profile.read.returns(Promise.resolve({
fakeApi.profile.read.returns(Promise.resolve({
userid: 'acct:user_b@hypothes.is',
}));
......@@ -239,7 +239,7 @@ describe('sidebar.session', function () {
});
// Fake profile response after logout.
fakeStore.profile.read = () => Promise.resolve({
fakeApi.profile.read = () => Promise.resolve({
userid: null,
loggedIn,
});
......@@ -266,14 +266,14 @@ describe('sidebar.session', function () {
context('when another client changes the current login', () => {
it('reloads the profile', () => {
fakeStore.profile.read.returns(Promise.resolve({
fakeApi.profile.read.returns(Promise.resolve({
userid: 'acct:initial_user@hypothes.is',
}));
return session.load().then(() => {
// Simulate login change happening in a different tab.
fakeStore.profile.read.returns(Promise.resolve({
fakeApi.profile.read.returns(Promise.resolve({
userid: 'acct:different_user@hypothes.is',
}));
$rootScope.$broadcast(events.OAUTH_TOKENS_CHANGED);
......
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