diff options
Diffstat (limited to 'src/api/user/StatusAPI.js')
-rw-r--r-- | src/api/user/StatusAPI.js | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/src/api/user/StatusAPI.js b/src/api/user/StatusAPI.js new file mode 100644 index 000000000..9c1318c38 --- /dev/null +++ b/src/api/user/StatusAPI.js @@ -0,0 +1,295 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2022, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is 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. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ +import EventEmitter from "EventEmitter"; + +export default class StatusAPI extends EventEmitter { + #userAPI; + #openmct; + + constructor(userAPI, openmct) { + super(); + this.#userAPI = userAPI; + this.#openmct = openmct; + + this.onProviderStatusChange = this.onProviderStatusChange.bind(this); + this.onProviderPollQuestionChange = this.onProviderPollQuestionChange.bind(this); + this.listenToStatusEvents = this.listenToStatusEvents.bind(this); + + this.#openmct.once('destroy', () => { + const provider = this.#userAPI.getProvider(); + + if (typeof provider?.off === 'function') { + provider.off('statusChange', this.onProviderStatusChange); + provider.off('pollQuestionChange', this.onProviderPollQuestionChange); + } + }); + + this.#userAPI.on('providerAdded', this.listenToStatusEvents); + } + + /** + * Fetch the currently defined operator status poll question. When presented with a status poll question, all operators will reply with their current status. + * @returns {Promise<PollQuestion>} + */ + getPollQuestion() { + const provider = this.#userAPI.getProvider(); + + if (provider.getPollQuestion) { + return provider.getPollQuestion(); + } else { + this.#userAPI.error("User provider does not support polling questions"); + } + } + + /** + * Set a poll question for operators to respond to. When presented with a status poll question, all operators will reply with their current status. + * @param {String} questionText - The text of the question + * @returns {Promise<Boolean>} true if operation was successful, otherwise false. + */ + async setPollQuestion(questionText) { + const canSetPollQuestion = await this.canSetPollQuestion(); + + if (canSetPollQuestion) { + const provider = this.#userAPI.getProvider(); + + const result = await provider.setPollQuestion(questionText); + + try { + await this.resetAllStatuses(); + } catch (error) { + console.warn("Poll question set but unable to clear operator statuses."); + console.error(error); + } + + return result; + } else { + this.#userAPI.error("User provider does not support setting polling question"); + } + } + + /** + * Can the currently logged in user set the operator status poll question. + * @returns {Promise<Boolean>} + */ + canSetPollQuestion() { + const provider = this.#userAPI.getProvider(); + + if (provider.canSetPollQuestion) { + return provider.canSetPollQuestion(); + } else { + return Promise.resolve(false); + } + } + + /** + * @returns {Promise<Array<Status>>} the complete list of possible states that an operator can reply to a poll question with. + */ + async getPossibleStatuses() { + const provider = this.#userAPI.getProvider(); + + if (provider.getPossibleStatuses) { + const possibleStatuses = await provider.getPossibleStatuses() || []; + + return possibleStatuses.map(status => status); + } else { + this.#userAPI.error("User provider cannot provide statuses"); + } + } + + /** + * @param {import("./UserAPI").Role} role The role to fetch the current status for. + * @returns {Promise<Status>} the current status of the provided role + */ + async getStatusForRole(role) { + const provider = this.#userAPI.getProvider(); + + if (provider.getStatusForRole) { + const status = await provider.getStatusForRole(role); + + return status; + } else { + this.#userAPI.error("User provider does not support role status"); + } + } + + /** + * @param {import("./UserAPI").Role} role + * @returns {Promise<Boolean>} true if the configured UserProvider can provide status for the given role + * @see StatusUserProvider + */ + canProvideStatusForRole(role) { + const provider = this.#userAPI.getProvider(); + + if (provider.canProvideStatusForRole) { + return provider.canProvideStatusForRole(role); + } else { + return false; + } + } + + /** + * @param {import("./UserAPI").Role} role The role to set the status for. + * @param {Status} status The status to set for the provided role + * @returns {Promise<Boolean>} true if operation was successful, otherwise false. + */ + setStatusForRole(role, status) { + const provider = this.#userAPI.getProvider(); + + if (provider.setStatusForRole) { + return provider.setStatusForRole(role, status); + } else { + this.#userAPI.error("User provider does not support setting role status"); + } + } + + /** + * Resets the status of the provided role back to its default status. + * @param {import("./UserAPI").Role} role The role to set the status for. + * @returns {Promise<Boolean>} true if operation was successful, otherwise false. + */ + async resetStatusForRole(role) { + const provider = this.#userAPI.getProvider(); + const defaultStatus = await this.getDefaultStatusForRole(role); + + if (provider.setStatusForRole) { + return provider.setStatusForRole(role, defaultStatus); + } else { + this.#userAPI.error("User provider does not support resetting role status"); + } + } + + /** + * Resets the status of all operators to their default status + * @returns {Promise<Boolean>} true if operation was successful, otherwise false. + */ + async resetAllStatuses() { + const allStatusRoles = await this.getAllStatusRoles(); + + return Promise.all(allStatusRoles.map(role => this.resetStatusForRole(role))); + } + + /** + * The default status. This is the status that will be used before the user has selected any status. + * @param {import("./UserAPI").Role} role + * @returns {Promise<Status>} the default operator status if no other has been set. + */ + async getDefaultStatusForRole(role) { + const provider = this.#userAPI.getProvider(); + const defaultStatus = await provider.getDefaultStatusForRole(role); + + return defaultStatus; + } + + /** + * All possible status roles. A status role is a user role that can provide status. In some systems + * this may be all user roles, but there may be cases where some users are not are not polled + * for status if they do not have a real-time operational role. + * + * @returns {Promise<Array<import("./UserAPI").Role>>} the default operator status if no other has been set. + */ + getAllStatusRoles() { + const provider = this.#userAPI.getProvider(); + + if (provider.getAllStatusRoles) { + return provider.getAllStatusRoles(); + } else { + this.#userAPI.error("User provider cannot provide all status roles"); + } + } + + /** + * The status role of the current user. A user may have multiple roles, but will only have one role + * that provides status at any time. + * @returns {Promise<import("./UserAPI").Role>} the role for which the current user can provide status. + */ + getStatusRoleForCurrentUser() { + const provider = this.#userAPI.getProvider(); + + if (provider.getStatusRoleForCurrentUser) { + return provider.getStatusRoleForCurrentUser(); + } else { + this.#userAPI.error("User provider cannot provide role status for this user"); + } + } + + /** + * @returns {Promise<Boolean>} true if the configured UserProvider can provide status for the currently logged in user, false otherwise. + * @see StatusUserProvider + */ + async canProvideStatusForCurrentUser() { + const provider = this.#userAPI.getProvider(); + + if (provider.getStatusRoleForCurrentUser) { + const activeStatusRole = await this.#userAPI.getProvider().getStatusRoleForCurrentUser(); + const canProvideStatus = await this.canProvideStatusForRole(activeStatusRole); + + return canProvideStatus; + } else { + return false; + } + } + + /** + * Private internal function that cannot be made #private because it needs to be registered as a callback to the user provider + * @private + */ + listenToStatusEvents(provider) { + if (typeof provider.on === 'function') { + provider.on('statusChange', this.onProviderStatusChange); + provider.on('pollQuestionChange', this.onProviderPollQuestionChange); + } + } + + /** + * @private + */ + onProviderStatusChange(newStatus) { + this.emit('statusChange', newStatus); + } + + /** + * @private + */ + onProviderPollQuestionChange(pollQuestion) { + this.emit('pollQuestionChange', pollQuestion); + } +} + +/** + * @typedef {import('./UserProvider')} UserProvider + */ +/** + * @typedef {import('./StatusUserProvider')} StatusUserProvider + */ +/** + * The PollQuestion type + * @typedef {Object} PollQuestion + * @property {String} question - The question to be presented to users + * @property {Number} timestamp - The time that the poll question was set. + */ + +/** + * The Status type + * @typedef {Object} Status + * @property {String} key - A unique identifier for this status + * @property {Number} label - A human readable label for this status + */ |