Skip to content

Commit

Permalink
feat(citSci): for annotations from different hosts, the correct absol…
Browse files Browse the repository at this point in the history
…ute urls are now used for media
  • Loading branch information
peichins committed Oct 28, 2019
1 parent 82f10d7 commit 05270e8
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 56 deletions.
40 changes: 23 additions & 17 deletions src/app/annotationLibrary/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,20 @@ angular
* For a given child model that has the properties startOffset, endOffset and AudioRecording,
* fetch the Media json and add as a property. Child models are e.g. AudioEvent or DatasetItem.
* @param childModel object
* @param host string optional. If provided, the media will be requested form this host.
* @return {*|Function}
*/
function getMedia(childModel) {
function getMedia(childModel, host = null) {
// modify annotation/datasetItem by reference
// async
var mediaParameters;
if (childModel instanceof DatasetItem) {
mediaParameters = getDatasetItemMediaParameters(childModel);
mediaParameters = getDatasetItemMediaParameters(childModel, host);
} else {
mediaParameters = getAnnotationMediaParameters(childModel);
mediaParameters = getAnnotationMediaParameters(childModel, host);
}


var x = Media.get(
mediaParameters,
mediaGetSuccess.bind(null, childModel),
mediaGetFailure
);

return x.$promise;
return Media.getFromHost(mediaParameters, host).then(mediaGetSuccess.bind(null, childModel), mediaGetFailure);

}

Expand Down Expand Up @@ -104,7 +98,18 @@ angular


function mediaGetSuccess(audioEvent, mediaValue, responseHeaders) {
audioEvent.media = new MediaModel(mediaValue.data);

var host = audioEvent.meta.source.origin;

// depending on whether this is the result of a resource.get or $http.get, media value will structured differently
if (mediaValue.hasOwnProperty("headers")) {
responseHeaders = mediaValue.headers;
mediaValue = mediaValue.data;
}

var data = mediaValue.data;

audioEvent.media = new MediaModel(data, host);

// create properties that depend on Media

Expand Down Expand Up @@ -214,19 +219,20 @@ angular
});
});
},
getSiteMediaAndProject: function getSiteMediaAndProject({annotations, annotationIds, recordingIds}) {
getSiteMediaAndProject: function getSiteMediaAndProject({annotations, annotationIds, recordingIds}, host = null) {
var arsp = {
audioRecordings: [],
sites: [],
projects: []
};


if (annotations.length === 0) {
return arsp;
}

return AudioRecording
.getRecordingsForLibrary(recordingIds)
.getRecordingsForLibrary(recordingIds, host)
.then(arResult => {
arsp.audioRecordings = arResult.data.data;
return arsp;
Expand All @@ -237,7 +243,7 @@ angular
}

return Site
.getSitesByIds(arspData.audioRecordings.map(x => x.siteId))
.getSitesByIds(arspData.audioRecordings.map(x => x.siteId), host)
.then(sResult => {
arspData.sites = sResult.data.data;
return arspData;
Expand All @@ -251,7 +257,7 @@ angular
return Project
.getProjectsBySiteIds(arspData.sites.reduce((previous, x) => {
return previous.concat(x.projectIds);
}, []))
}, []), host)
.then(pResult => {
arspData.projects = pResult.data.data;
return arspData;
Expand All @@ -277,7 +283,7 @@ angular
AudioRecording: audioRecordings
});

mediaPromises.push(getMedia(annotation));
mediaPromises.push(getMedia(annotation, host));
});

arspData.annotations = annotations;
Expand Down
6 changes: 3 additions & 3 deletions src/app/annotationLibrary/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ angular
function librarySuccess(response, responseHeaders) {
console.debug("annotationLibrary::librarySuccess");

var data = response.data.data || [];
var paging = response.data.meta.paging;
$scope.status = "loaded";
$scope.paging = getPagingSettings(paging.page, paging.items, paging.total);
Expand All @@ -92,8 +91,9 @@ angular
var annotationIds = new Set(),
recordingIds = new Set();

data.forEach(function (resource, index) {
var audioEvent = new AudioEvent(resource);
var audioEvents = AudioEvent.makeFromApi(response);

audioEvents.data.data.forEach(function (audioEvent, index) {

annotationIds.add(audioEvent.id);
recordingIds.add(audioEvent.audioRecordingId);
Expand Down
14 changes: 7 additions & 7 deletions src/app/citizenScience/labels/thumbLabels/labels.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,26 +62,26 @@ angular.module("bawApp.components.citizenScienceThumbLabels",
// examples can have annotation ids or spectrogram image filenames (for static image examples)
var annotationIds = [].concat.apply([], labels.map(l => l.examples)).map(e => e.hasOwnProperty("annotationId") ? e.annotationId : null);

var annotationDomains = [].concat.apply([], labels.map(l => l.examples)).map(e => e.hasOwnProperty("annotationDomain") ? e.annotationDomain : null);
var annotationHosts = [].concat.apply([], labels.map(l => l.examples)).map(e => e.hasOwnProperty("annotationHost") ? e.annotationHost : null);


annotationIds = annotationIds.filter(id => id);
if (annotationIds.length === 0) {
return;
}

// currently all annotations must come from the same domain.
var annotationDomain = annotationDomains[0];
if (!annotationDomains.every(v => v === annotationDomain)) {
console.warn("Example annotations can not come from multiple domains");
// currently all annotations must come from the same host.
var annotationHost = annotationHosts[0];
if (!annotationHosts.every(v => v === annotationHost)) {
console.warn("citizenScienceThumbLabels: Example annotations can not come from multiple hosts");
return;
}


var annotations = [];

AudioEventService
.getAudioEventsByIds(annotationIds, annotationDomain)
.getAudioEventsByIds(annotationIds, annotationHost)
.then(function (response) {

annotations = response.data.data || [];
Expand All @@ -103,7 +103,7 @@ angular.module("bawApp.components.citizenScienceThumbLabels",
recordingIds
};

var x = libraryCommon.getSiteMediaAndProject(data);
var x = libraryCommon.getSiteMediaAndProject(data, annotationHost);
return x;

}, function (error) {
Expand Down
2 changes: 2 additions & 0 deletions src/components/models/associations.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ angular
}
meta.capabilities = new Capabilities(meta.capabilities);

meta.source = new URL(canonicalResponse.config.url);

// give each object a reference to meta
items.forEach((a) => a[metaKey] = meta);

Expand Down
11 changes: 7 additions & 4 deletions src/components/models/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ angular
function (ApiBase, paths, Authenticator, url, ProgressEvent) {

class Media extends ApiBase {
constructor(resource) {
constructor(resource, host = null) {
super(resource);

this.host = host || paths.api.root;

// convert the datetime
this.recording.recordedDate = new Date(this.recording.recordedDate);

Expand Down Expand Up @@ -49,7 +51,8 @@ angular

var imageKey = imgKeys[0];
var imageFormat = mediaItem.available.image[imageKey];
var fullUrl = paths.api.root + imageFormat.url;
var root = this.host;
var fullUrl = root + imageFormat.url;
mediaItem.available.image[imageKey].url = url.formatUriServer(fullUrl, {userToken: Authenticator.authToken});

mediaItem.spectrogram = imageFormat;
Expand All @@ -58,7 +61,7 @@ angular
mediaItem.available.audioOrder = [];
angular.forEach(mediaItem.available.audio, function (value, key) {
// just update the url so it is an absolute uri
var fullUrl = paths.api.root + value.url;
var fullUrl = root + value.url;

// also add auth token
this[key].url = url.formatUriServer(fullUrl, {userToken: Authenticator.authToken});
Expand All @@ -67,7 +70,7 @@ angular

}, mediaItem.available.audio);

var jsonFullUrl = paths.api.root + mediaItem.available.text.json.url;
var jsonFullUrl = root + mediaItem.available.text.json.url;
mediaItem.available.text.json.url = url.formatUriServer(jsonFullUrl, {userToken: Authenticator.authToken});
}

Expand Down
20 changes: 5 additions & 15 deletions src/components/services/audioEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,31 +81,21 @@ angular
};


/**
* return the filterUrl, allowing for cross-site access of audioEvents in other deployments
* @param domain if provided will construct the url with the relative url and the provided domain
*/
function filterUrl (domain = null) {
if (domain) {
return domain.replace(/\/$/,"") + paths.api.routes.audioEvent.filter;
} else {
return paths.api.routes.audioEvent.filterAbsolute;
}
}


resource.getAudioEventsByIds = function (audioEventIds, domain = null) {

resource.getAudioEventsByIds = function (audioEventIds, host = null) {

var query = QueryBuilder.create(function (q) {
return q.in("id", audioEventIds);
});

return $http
.post(filterUrl(domain), query.toJSON())
.post(bawResource.crossDomainUrlAbsolute("audioEvent", "filter", host), query.toJSON())
.then(x => AudioEventModel.makeFromApi(x));
};

resource.getAudioEventsWithinRange = function (audioRecordingId, offsets, domain = null) {
resource.getAudioEventsWithinRange = function (audioRecordingId, offsets, host = null) {
var query = QueryBuilder.create(function (q) {
return q.and(
q.eq("audioRecordingId", audioRecordingId),
Expand All @@ -114,7 +104,7 @@ angular
);
});

return $http.post(filterUrl(domain), query.toJSON())
return $http.post(bawResource.crossDomainUrlAbsolute("audioEvent", "filter", host), query.toJSON())
.then(resultPager.loadAll)
.then(x => AudioEventModel.makeFromApi(x));
};
Expand Down
4 changes: 2 additions & 2 deletions src/components/services/audioRecording.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ angular
.then(x => AudioRecordingCore.makeFromApi(x));
};

resource.getRecordingsForLibrary = function (audioRecordingIds) {
resource.getRecordingsForLibrary = function (audioRecordingIds, host = null) {
var query = QueryBuilder.create(q => q
.in("id", audioRecordingIds)
.project({include: ["id", "siteId", "durationSeconds", "recordedDate"]}));

return $http
.post(filterUrl, query.toJSONString())
.post(bawResource.crossDomainUrlAbsolute("audioRecording", "filter", host), query.toJSONString())
.then(x => AudioRecordingModel.makeFromApi(x));
};
return resource;
Expand Down
23 changes: 21 additions & 2 deletions src/components/services/bawResource.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ angular
.factory(
"bawResource",
[
"$resource",
function ($resource) {
"$resource", "conf.paths",
function ($resource, paths) {

/**
*
Expand All @@ -17,6 +17,24 @@ angular
return uri.replace(/(\{([^{}]*)\})/g, ":$2");
}


/**
* return the filterUrl, allowing for cross-site access of audioEvents in other deployments
* @param service string a key in paths.api.routes e.g. 'audioEvent'
* @param endpoint string a key in paths.api.routes[service]
* @param domain if provided will prepend to the relative url, otherwise will use absolute
* Note:
*/
function crossDomainUrlAbsolute(service, endpoint, host = null) {

if (host) {
return host.replace(/\/$/,"") + paths.api.routes[service][endpoint];
} else {
return paths.api.routes[service][endpoint + "Absolute"];
}

}

/**
* @name bawResource
* Helper method for adding a put request onto the standard angular resource service
Expand All @@ -39,6 +57,7 @@ angular
};

bawResource.uriConvert = uriConvert;
bawResource.crossDomainUrlAbsolute = crossDomainUrlAbsolute;
return bawResource;
}
]
Expand Down
11 changes: 9 additions & 2 deletions src/components/services/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ angular
.factory(
"Media",
[
"$resource", "bawResource", "conf.paths",
function ($resource, bawResource, paths) {
"$resource", "bawResource", "conf.paths", "$http", "$url",
function ($resource, bawResource, paths, $http, $url) {

// create resource for rest requests to media api
var mediaResource = $resource(bawResource.uriConvert(paths.api.routes.media.showAbsolute),
Expand All @@ -13,6 +13,13 @@ angular
format: "@format"
});

mediaResource.getFromHost = function (mediaParameters, host) {

var mediaUrl = bawResource.crossDomainUrlAbsolute("media", "show", host);
return $http.get($url.formatUriServer(mediaUrl, mediaParameters));

};

// this is a read only service, remove unnecessary methods
// keep GET
delete mediaResource.save;
Expand Down
5 changes: 3 additions & 2 deletions src/components/services/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ angular

};

resource.getProjectsBySiteIds = function (siteIds) {
var gpbsiUrl = paths.api.routes.project.filterAbsolute;
resource.getProjectsBySiteIds = function (siteIds, host = null) {

var gpbsiUrl = bawResource.crossDomainUrlAbsolute("project", "filter", host);


var query = QueryBuilder.create(function (q) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/services/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ angular
.then( x => SiteModel.makeFromApi(x));
};

resource.getSitesByProjectIds = function (projectIds) {
resource.getSitesByProjectIds = function (projectIds, host = null) {
var projectIdsUnique = _.uniq(projectIds);
var query = QueryBuilder.create(function (q) {
return q.in("projects.id", projectIdsUnique)
.project({include: ["id", "name"]})
.sort({orderBy: "name"});
});
return $http
.post(url, query.toJSONString())
.post(bawResource.crossDomainUrlAbsolute("site", "filter", host), query.toJSONString())
.then( x => SiteModel.makeFromApi(x));
};

Expand Down

0 comments on commit 05270e8

Please sign in to comment.