/****************************************************************************** Flatmap viewer and annotation tool Copyright (c) 2019 - 2023 David Brooks Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ******************************************************************************/ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _AnnotationService_instances, _AnnotationService_serverEndpoint, _AnnotationService_currentUser, _AnnotationService_currentError, _AnnotationService_request; import Cookies from 'js-cookie'; //============================================================================== const SERVER_TIMEOUT = 10000; // 10 seconds //============================================================================== /** * Interface to a SPARC map annotation service. */ export class AnnotationService { /** * @param serverEndpoint The URL of a map annotation service. */ constructor(serverEndpoint) { _AnnotationService_instances.add(this); _AnnotationService_serverEndpoint.set(this, void 0); _AnnotationService_currentUser.set(this, null); _AnnotationService_currentError.set(this, null /** * @param serverEndpoint The URL of a map annotation service. */ ); if (serverEndpoint.slice(-1) === '/') { // Strip any trailing slash __classPrivateFieldSet(this, _AnnotationService_serverEndpoint, serverEndpoint.slice(0, -1), "f"); } else { __classPrivateFieldSet(this, _AnnotationService_serverEndpoint, serverEndpoint, "f"); } } /** * Get information about the logged-in SPARC user. * * Requires {@linkcode authenticate} to first be called. */ get currentUser() { return __classPrivateFieldGet(this, _AnnotationService_currentUser, "f"); } /** * Get information about any error from the last call * to {@linkcode authenticate}. */ get currentError() { return __classPrivateFieldGet(this, _AnnotationService_currentError, "f"); } /** * Authenticate the logged-in SPARC user. * * @param userApiKey The Api token of the logged-in Pennsieve user * @return A Promise resolving to either data about a valid user * or a reason why the user is invalid. */ async authenticate(userApiKey) { __classPrivateFieldSet(this, _AnnotationService_currentError, null, "f"); __classPrivateFieldSet(this, _AnnotationService_currentUser, null, "f"); const userData = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'authenticate'); if (!('error' in userData)) { Cookies.set('annotation-key', userData.session, { secure: true, expires: 1 }); __classPrivateFieldSet(this, _AnnotationService_currentUser, userData.data, "f"); return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentUser, "f")); } Cookies.remove('annotation-key'); return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f")); } /** * Unauthenticate with the annotation service. * * @param userApiKey The Api token of the logged-in Pennsieve user * @return A Promise with data about the call. */ async unauthenticate(userApiKey) { __classPrivateFieldSet(this, _AnnotationService_currentError, null, "f"); __classPrivateFieldSet(this, _AnnotationService_currentUser, null, "f"); const responseData = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'unauthenticate'); if ('success' in responseData) { return Promise.resolve(responseData); } return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f")); } /** * Get identifiers of all annotated items in a resource. * * @param userApiKey The Api token of the logged-in Pennsieve user * @param resourceId The resource's identifier * @param userId A user identifier (ORCID). Optional * @param participated Get items the user was involved in annotating or not. * Optional, default ``true`` * @return A Promise resolving to either a list of identifiers of annotated * items or a reason why identifiers couldn't be retrieved. */ async annotatedItemIds(userApiKey, resourceId, userId, participated) { const params = { resource: resourceId }; if (userId !== undefined) { params.user = userId; } if (participated !== undefined) { params.participated = participated; } const itemIds = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'items/', 'GET', params); if (!('error' in itemIds)) { return Promise.resolve(itemIds); } return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f")); } /** * Get all annotated features drawn on a resource. * * @param userApiKey The Api token of the logged-in Pennsieve user * @param resourceId The resource's identifier * @return A Promise resolving to either a list of annotated * features drawn on the resource or a reason why * features couldn't be retrieved. */ async drawnFeatures(userApiKey, resourceId, itemIds) { const params = { resource: resourceId }; if (itemIds !== undefined) { params.items = itemIds; } const features = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'features/', 'GET', params); if (!('error' in features)) { return Promise.resolve(features); } return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f")); } /** * Get all annotations about a specific item in a resource. * * @param userApiKey The Api token of the logged-in Pennsieve user * @param resourceId The resource's identifier * @param itemId The item's identifier within the resource * @return A Promise resolving to either a list of * annotations about the item or a reason * why annotations couldn't be retrieved. */ async itemAnnotations(userApiKey, resourceId, ItemId) { const annotations = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'annotations/', 'GET', { resource: resourceId, item: ItemId }); if (!('error' in annotations)) { return Promise.resolve(annotations); } return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f")); } /** * Get details of a specific annotation. * * @param userApiKey The Api token of the logged-in Pennsieve user * @param annotationId The annotation's URI * @return A Promise resolving to either an annotation * with the given URI or a reason why the * annotation couldn't be retrieved. */ async annotation(userApiKey, annotationId) { const annotation = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'annotation/', 'GET', { annotation: annotationId }); if (!('error' in annotation)) { return Promise.resolve(annotation); } return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f")); } /** * Add an annotation about a specific item in a resource. * * @param userApiKey The Api token of the logged-in Pennsieve user * @param annotation Annotation about the feature * @return A Promise resolving to either the resulting * full annotation or a reason why the * annotation couldn't be added */ async addAnnotation(userApiKey, userAnnotation) { if (__classPrivateFieldGet(this, _AnnotationService_currentUser, "f") && __classPrivateFieldGet(this, _AnnotationService_currentUser, "f").canUpdate) { const annotationRequest = Object.assign({ creator: __classPrivateFieldGet(this, _AnnotationService_currentUser, "f"), created: (new Date()).toISOString() }, userAnnotation); const annotationResponse = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, `annotation/`, 'POST', { data: annotationRequest }); if (!('error' in annotationResponse)) { return Promise.resolve(annotationResponse); } __classPrivateFieldSet(this, _AnnotationService_currentError, annotationResponse, "f"); } else { __classPrivateFieldSet(this, _AnnotationService_currentError, { error: 'user cannot add annotation' }, "f"); } return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f")); } } _AnnotationService_serverEndpoint = new WeakMap(), _AnnotationService_currentUser = new WeakMap(), _AnnotationService_currentError = new WeakMap(), _AnnotationService_instances = new WeakSet(), _AnnotationService_request = async function _AnnotationService_request(userApiKey, endpoint, method = 'GET', parameters = {}) { let noResponse = true; const abortController = new AbortController(); setTimeout(() => { if (noResponse) { console.log('Annotation server timeout...'); abortController.abort(); // how is the promise resolved/rejected when there's a timeout?? } }, SERVER_TIMEOUT); const options = { method: method, signal: abortController.signal }; let url = `${__classPrivateFieldGet(this, _AnnotationService_serverEndpoint, "f")}/${endpoint}`; const sessionKey = Cookies.get('annotation-key') || ''; if (method === 'GET') { const params = []; for (const [key, value] of Object.entries(parameters)) { params.push(`${key}=${encodeURIComponent(JSON.stringify(value))}`); } params.push(`key=${encodeURIComponent(userApiKey)}`); params.push(`session=${encodeURIComponent(sessionKey)}`); url += '?' + params.join('&'); options['headers'] = { "Accept": "application/json; charset=utf-8", "Cache-Control": "no-store" }; } else if (method === 'POST') { const params = Object.assign({ key: userApiKey, session: sessionKey }, parameters); options['body'] = JSON.stringify(params); options['headers'] = { "Accept": "application/json; charset=utf-8", "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store" }; } const response = await fetch(url, options); noResponse = false; if (response.ok) { return Promise.resolve(await response.json()); } else { __classPrivateFieldSet(this, _AnnotationService_currentError, { error: `${response.status} ${response.statusText}` }, "f"); return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f")); } }; //==============================================================================