Skip to content
Snippets Groups Projects
Commit 85153241 authored by Chris Beer's avatar Chris Beer
Browse files

Extract configuration to control which IIIF auth services are used (and the...

Extract configuration to control which IIIF auth services are used (and the different types of generic interactions)
parent 7d5bf4c6
No related branches found
No related tags found
No related merge requests found
......@@ -2,6 +2,7 @@ import manifestFixture001 from '../../fixtures/version-2/001.json';
import manifestFixture019 from '../../fixtures/version-2/019.json';
import minimumRequired from '../../fixtures/version-2/minimumRequired.json';
import minimumRequired3 from '../../fixtures/version-3/minimumRequired.json';
import settings from '../../../src/config/settings';
import {
getVisibleCanvases,
......@@ -10,10 +11,8 @@ import {
getCanvas,
getCanvasLabel,
selectCanvasAuthService,
selectNextAuthService,
selectInfoResponse,
getVisibleCanvasNonTiledResources,
selectLogoutAuthService,
getVisibleCanvasIds,
} from '../../../src/state/selectors/canvases';
......@@ -251,69 +250,6 @@ describe('getCanvasLabel', () => {
});
});
describe('selectNextAuthService', () => {
const auth = {};
const resource = {
service: [
{
'@id': 'external',
profile: 'http://iiif.io/api/auth/1/external',
},
{
'@id': 'kiosk',
profile: 'http://iiif.io/api/auth/1/kiosk',
},
{
'@id': 'clickthrough',
profile: 'http://iiif.io/api/auth/1/clickthrough',
},
{
'@id': 'login',
profile: 'http://iiif.io/api/auth/1/login',
},
{
'@id': 'login2',
profile: 'http://iiif.io/api/auth/1/login',
},
],
};
const noAuthResource = {};
it('returns external first', () => {
expect(selectNextAuthService({ auth }, resource).id).toEqual('external');
});
it('returns kiosk next', () => {
auth.external = { isFetching: false, ok: false };
expect(selectNextAuthService({ auth }, resource).id).toEqual('kiosk');
});
it('returns clickthrough next', () => {
auth.external = { isFetching: false, ok: false };
auth.kiosk = { isFetching: false, ok: false };
expect(selectNextAuthService({ auth }, resource).id).toEqual('clickthrough');
});
it('returns logins last', () => {
auth.external = { isFetching: false, ok: false };
auth.kiosk = { isFetching: false, ok: false };
auth.clickthrough = { isFetching: false, ok: false };
expect(selectNextAuthService({ auth }, resource).id).toEqual('login');
auth.login = { isFetching: false, ok: false };
expect(selectNextAuthService({ auth }, resource).id).toEqual('login2');
});
it('returns null if there are no services', () => {
expect(selectNextAuthService({ auth }, noAuthResource)).toBeNull();
});
it('returns null if a service is currently in-flight', () => {
auth.external = { isFetching: true };
expect(selectNextAuthService({ auth }, resource)).toBeNull();
});
});
describe('selectCanvasAuthService', () => {
const resource = {
service: [
......@@ -338,6 +274,7 @@ describe('selectCanvasAuthService', () => {
const state = {
auth: {},
config: { auth: settings.auth },
infoResponses: {
'https://iiif.bodleian.ox.ac.uk/iiif/image/9cca8fdd-4a61-4429-8ac1-f648764b4d6d': {
json: resource,
......@@ -357,7 +294,7 @@ describe('selectCanvasAuthService', () => {
};
it('returns undefined if there is no current canvas', () => {
expect(selectCanvasAuthService({ manifests: {} }, { manifestId: 'a' })).toBeUndefined();
expect(selectCanvasAuthService({ config: { auth: settings.auth }, manifests: {} }, { manifestId: 'a' })).toBeUndefined();
});
it('returns the next auth service to try', () => {
......@@ -378,35 +315,38 @@ describe('selectCanvasAuthService', () => {
expect(selectCanvasAuthService({ ...state, auth }, { canvasId: 'http://iiif.io/api/presentation/2.0/example/fixtures/canvas/24/c1.json', manifestId: 'b' }).id).toEqual('external');
expect(selectCanvasAuthService({ ...state, auth }, { canvasId: 'https://purl.stanford.edu/fr426cg9537/iiif/canvas/fr426cg9537_1', manifestId: 'b' })).toBeUndefined();
});
});
describe('selectLogoutAuthService', () => {
it('returns a logout auth service if one exists', () => {
const logout = {
'@id': 'http://foo/logout',
profile: 'http://iiif.io/api/auth/1/logout',
};
const resource = {
describe('proscribed order', () => {
let auth = {};
const orderedState = {
config: { auth: settings.auth },
infoResponses: {
'https://iiif.bodleian.ox.ac.uk/iiif/image/9cca8fdd-4a61-4429-8ac1-f648764b4d6d': {
json: {
service: [
{
'@id': 'external',
profile: 'http://iiif.io/api/auth/1/external',
},
{
'@id': 'kiosk',
profile: 'http://iiif.io/api/auth/1/kiosk',
},
{
'@id': 'clickthrough',
profile: 'http://iiif.io/api/auth/1/clickthrough',
},
{
'@id': 'login',
profile: 'http://iiif.io/api/auth/1/login',
service: [
logout,
],
},
{
'@id': 'login2',
profile: 'http://iiif.io/api/auth/1/login',
},
],
};
const state = {
auth: {
login: {
ok: true,
},
},
infoResponses: {
'https://iiif.bodleian.ox.ac.uk/iiif/image/9cca8fdd-4a61-4429-8ac1-f648764b4d6d': {
json: resource,
},
},
manifests: {
a: {
......@@ -414,13 +354,43 @@ describe('selectLogoutAuthService', () => {
},
},
};
expect(
selectLogoutAuthService(
state,
{ canvasId: 'https://iiif.bodleian.ox.ac.uk/iiif/canvas/9cca8fdd-4a61-4429-8ac1-f648764b4d6d.json', manifestId: 'a' },
).id,
)
.toBe(logout['@id']);
it('returns external first', () => {
auth = {};
expect(selectCanvasAuthService({ ...orderedState, auth }, { canvasId: 'https://iiif.bodleian.ox.ac.uk/iiif/canvas/9cca8fdd-4a61-4429-8ac1-f648764b4d6d.json', manifestId: 'a' }).id).toEqual('external');
});
it('returns kiosk next', () => {
auth = { external: { isFetching: false, ok: false } };
expect(selectCanvasAuthService({ ...orderedState, auth }, { canvasId: 'https://iiif.bodleian.ox.ac.uk/iiif/canvas/9cca8fdd-4a61-4429-8ac1-f648764b4d6d.json', manifestId: 'a' }).id).toEqual('kiosk');
});
it('returns clickthrough next', () => {
auth = {
external: { isFetching: false, ok: false },
kiosk: { isFetching: false, ok: false },
};
expect(selectCanvasAuthService({ ...orderedState, auth }, { canvasId: 'https://iiif.bodleian.ox.ac.uk/iiif/canvas/9cca8fdd-4a61-4429-8ac1-f648764b4d6d.json', manifestId: 'a' }).id).toEqual('clickthrough');
});
it('returns logins last', () => {
auth = {
clickthrough: { isFetching: false, ok: false },
external: { isFetching: false, ok: false },
kiosk: { isFetching: false, ok: false },
};
expect(selectCanvasAuthService({ ...orderedState, auth }, { canvasId: 'https://iiif.bodleian.ox.ac.uk/iiif/canvas/9cca8fdd-4a61-4429-8ac1-f648764b4d6d.json', manifestId: 'a' }).id).toEqual('login');
});
it('returns services within a given type using the order from the manifest', () => {
auth = {
clickthrough: { isFetching: false, ok: false },
external: { isFetching: false, ok: false },
kiosk: { isFetching: false, ok: false },
login: { isFetching: false, ok: false },
};
expect(selectCanvasAuthService({ ...orderedState, auth }, { canvasId: 'https://iiif.bodleian.ox.ac.uk/iiif/canvas/9cca8fdd-4a61-4429-8ac1-f648764b4d6d.json', manifestId: 'a' }).id).toEqual('login2');
});
});
});
......@@ -430,6 +400,7 @@ describe('selectInfoResponse', () => {
const state = {
auth: {},
config: { auth: settings.auth },
infoResponses: {
'https://iiif.bodleian.ox.ac.uk/iiif/image/9cca8fdd-4a61-4429-8ac1-f648764b4d6d': {
json: resource,
......
......@@ -337,5 +337,13 @@ export default {
viewers: true,
windows: true,
workspace: true,
},
auth: {
serviceProfiles: [
{ profile: 'http://iiif.io/api/auth/1/external', external: true },
{ profile: 'http://iiif.io/api/auth/1/kiosk', kiosk: true },
{ profile: 'http://iiif.io/api/auth/1/clickthrough' },
{ profile: 'http://iiif.io/api/auth/1/login' },
]
}
};
......@@ -124,7 +124,7 @@ function* getAccessTokenService(resource) {
for (let i = 0; i < services.length; i += 1) {
const authService = services[i];
const accessTokenService = Utils.getService(authService, 'http://iiif.io/api/auth/1/token');
const token = accessTokens[accessTokenService.id];
const token = accessTokenService && accessTokens[accessTokenService.id];
if (token && token.json) return token;
}
......
......@@ -5,6 +5,8 @@ import CanvasGroupings from '../../lib/CanvasGroupings';
import MiradorCanvas from '../../lib/MiradorCanvas';
import { miradorSlice } from './utils';
import { getWindow } from './getters';
import { getConfig } from './config';
import { getAuth } from './auth';
import { getSequence } from './sequences';
import { getWindowViewType } from './windows';
......@@ -207,84 +209,42 @@ export const selectInfoResponse = createSelector(
},
);
const authServiceProfiles = {
clickthrough: true, external: true, kiosk: true, login: true,
};
/**
*
*/
export function selectNextAuthService({ auth }, resource, filter = authServiceProfiles) {
const orderedAuthServiceProfiles = [
'http://iiif.io/api/auth/1/external',
'http://iiif.io/api/auth/1/kiosk',
'http://iiif.io/api/auth/1/clickthrough',
'http://iiif.io/api/auth/1/login',
];
const mapFilterToProfiles = {
'http://iiif.io/api/auth/1/clickthrough': 'clickthrough',
'http://iiif.io/api/auth/1/external': 'external',
'http://iiif.io/api/auth/1/kiosk': 'kiosk',
'http://iiif.io/api/auth/1/login': 'login',
};
export const selectCanvasAuthService = createSelector(
[
selectInfoResponse,
getCanvas,
getConfig,
getAuth,
],
(infoResponse, canvas, { auth: { serviceProfiles = [] } }, auth) => {
let iiifResource;
iiifResource = infoResponse && infoResponse.json && { ...infoResponse.json, options: {} };
for (const profile of orderedAuthServiceProfiles) {
const services = getServices(resource, profile);
for (const service of services) {
if (!auth[service.id]) {
return filter[mapFilterToProfiles[profile]] && service;
}
if (!iiifResource && canvas) {
const miradorCanvas = new MiradorCanvas(canvas);
const [image] = miradorCanvas.iiifImageResources;
if (auth[service.id].isFetching || auth[service.id].ok) return null;
}
iiifResource = image && image.getServices()[0];
}
return null;
}
if (!iiifResource) return undefined;
/** */
export function selectActiveAuthService(state, resource) {
const orderedAuthServiceProfiles = [
'http://iiif.io/api/auth/1/login',
'http://iiif.io/api/auth/1/clickthrough',
'http://iiif.io/api/auth/1/kiosk',
'http://iiif.io/api/auth/1/external',
];
const orderedAuthServiceProfiles = serviceProfiles.map(p => p.profile);
for (const profile of orderedAuthServiceProfiles) {
const services = getServices(resource, profile);
const service = services.find(s => selectAuthStatus(state, s));
if (service) return service;
}
let lastAttemptedService;
return null;
}
export const selectCanvasAuthService = createSelector(
[
selectInfoResponse,
state => state,
],
(infoResponse, state) => {
const resource = infoResponse && infoResponse.json;
for (const profile of orderedAuthServiceProfiles) {
const services = getServices(iiifResource, profile);
for (const service of services) {
if (!auth[service.id]) return service;
if (!resource) return undefined;
lastAttemptedService = service;
return selectNextAuthService(state, resource)
|| selectActiveAuthService(state, resource);
},
);
if (auth[service.id].isFetching || auth[service.id].ok) return service;
}
}
export const selectLogoutAuthService = createSelector(
[
selectInfoResponse,
state => state,
],
(infoResponse, state) => {
if (!infoResponse) return undefined;
const authService = selectActiveAuthService(state, infoResponse.json);
if (!authService) return undefined;
return authService.getService('http://iiif.io/api/auth/1/logout');
return lastAttemptedService;
},
);
......@@ -299,7 +259,7 @@ export function selectAuthStatus({ auth }, service) {
/** Get all the services that match a profile */
function getServices(resource, profile) {
const services = Utils.getServices({ ...resource, options: {} });
const services = Utils.getServices(resource);
return services.filter(service => service.getProfile() === profile);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment