UNPKG

gpii-universal

Version:

Cross platform, core components of the GPII personalization infrastructure.

380 lines (356 loc) 17.2 kB
/*! Copyright 2017-2018 OCAD university Licensed under the New BSD license. You may not use this file except in compliance with this License. You may obtain a copy of the License at https://github.com/GPII/universal/blob/master/LICENSE.txt */ /* eslint-env browser */ /* eslint strict: ["error", "function"] */ var fluid = fluid || require("infusion"); (function () { "use strict"; var gpii = fluid.registerNamespace("gpii"); fluid.defaults("gpii.preferencesServer.preferencesService", { gradeNames: ["fluid.component"], components: { dataStore: { type: "gpii.dbOperation.dataStore" } }, invokers: { getPrefsSafeByGpiiKey: "{dataStore}.findPrefsSafeByGpiiKey", getPreferencesByGpiiKey: { funcName: "gpii.preferencesServer.preferencesService.getPreferencesByGpiiKey", args: ["{dataStore}.findPrefsSafeByGpiiKey", "{arguments}.0"] // gpiiKey }, createPreferences: { funcName: "gpii.preferencesServer.preferencesService.createPreferences", args: ["{that}", "{arguments}.0", "{arguments}.1"] // preferences, gpiiKey }, updatePreferences: { funcName: "gpii.preferencesServer.preferencesService.updatePreferences", args: ["{that}", "{arguments}.0", "{arguments}.1", "{arguments}.2"] // preferences, gpiiKey, merge }, isLive: { funcName: "gpii.preferencesServer.preferencesService.isLive", args: ["{dataStore}.findAllViews"] } }, events: { onCreatePreferences: null, onAssociatePreferences: null }, listeners: { onCreatePreferences: [{ listener: "gpii.preferencesServer.preferencesService.verifyGpiiKey", args: ["{dataStore}.findGpiiKey", "{arguments}.0"], namespace: "verifyGpiiKey" }, { listener: "gpii.preferencesServer.preferencesService.createPrefsSafe", args: ["{dataStore}.addPrefsSafe", "{arguments}.0"], namespace: "createPrefsSafe" }, { listener: "gpii.preferencesServer.preferencesService.createGpiiKey", args: ["{dataStore}.addGpiiKey", "{arguments}.0"], namespace: "createGpiiKey" }], onAssociatePreferences: [{ listener: "gpii.preferencesServer.preferencesService.createPrefsSafe", args: ["{dataStore}.addPrefsSafe", "{arguments}.0"], namespace: "createPrefsSafe" }, { listener: "gpii.preferencesServer.preferencesService.updateGpiiKey", args: ["{dataStore}.updateGpiiKey", "{arguments}.0"], namespace: "updateGpiiKey" }] } }); // APIs for Preferences and Preferences Safes /** * Grant an authorization for the give GPII app installation. The gpii key will be verified before the access token is returned. * @param {Component} findPrefsSafeByGpiiKey - An instance of gpii.preferencesServer.preferencesService. * @param {String} gpiiKey - A GPII key. * @return {Promise} A promise object whose resolved value is the entire preferences associated with the GPII key. * An error will be returned if the GPII key is not found or there is no preferences defined for the GPII key. */ gpii.preferencesServer.preferencesService.getPreferencesByGpiiKey = function (findPrefsSafeByGpiiKey, gpiiKey) { var promiseTogo = fluid.promise(); var dataPromise = findPrefsSafeByGpiiKey(gpiiKey); dataPromise.then(function (data) { if (data === undefined) { fluid.log("Preferences Service, getPreferencesByGpiiKey() rejected: missing GPII key: " + gpiiKey); promiseTogo.reject(gpii.preferencesServer.errors.missingGpiiKey); } else { promiseTogo.resolve(data.prefsSafe ? fluid.get(data, ["prefsSafe", "preferences"]) : undefined); } }, function (err) { promiseTogo.reject(err); }); return promiseTogo; }; /** * The entry point of createPreferences() API. Fires the transforming promise workflow by triggering onCreatePreferences event. * It handles: * 1. If no GPII key is provided, auto generate and create a GPII key. Also create a new prefs safe to associate with this key; * 2. If a GPII key is provided and does not exist, create it. Also create a new prefs safe to associate with this key; * 3. If a GPII key is provided and already exists, reject with an error. * @param {Component} that - An instance of gpii.preferencesServer.preferencesService component. * @param {Object} preferences - The prefs safe data * { * prefsSafeType: {String} * name: {String} * password: {String} * email: {String} * preferences: {Object} // must be provided * } * @param {String} [gpiiKey] - [optional] The new GPII key, an UUID will be generated if it's not provided * @return {Promise} A promise that will be resolved with the results of the transform event. */ gpii.preferencesServer.preferencesService.createPreferences = function (that, preferences, gpiiKey) { return fluid.promise.fireTransformEvent(that.events.onCreatePreferences, { gpiiKey: gpiiKey, prefsSafeData: { preferences: preferences } }); }; /** * The first step in the promise transforming chain for implementing createPreferences() API. * Verify the provided GPII key. Reject the creation if the key already exists. * @param {Function} findGpiiKey - The findGpiiKey() API provided by preferencesServer.preferencesService. * @param {Object} input - The data passed on from the entry function gpii.preferencesServer.preferencesService.createPreferences(). Its structure: * { * gpiiKey: {String}, // Optional * prefsSafeData: { * prefsSafeType: {String} * name: {String} * password: {String} * email: {String} * preferences: {Object} // must be provided * } * } * @return {Promise} A promise object that carries the given input value with the created prefsSafeId being added. */ gpii.preferencesServer.preferencesService.verifyGpiiKey = function (findGpiiKey, input) { var promiseTogo = fluid.promise(); var gpiiKey = input.gpiiKey; if (gpiiKey) { // verify the uniqueness of the provided GPII key var gpiiKeyPromise = findGpiiKey(gpiiKey); gpiiKeyPromise.then(function (data) { if (data) { // reject if the GPII key already exists var gpiiKeyExistsMsg = fluid.stringTemplate(gpii.preferencesServer.errors.gpiiKeyExists.message, { gpiiKey: gpiiKey }); fluid.log("Preferences Service, verifyGpiiKey() rejected: ", gpiiKeyExistsMsg); promiseTogo.reject({ errorCode: gpii.preferencesServer.errors.gpiiKeyExists.errorCode, message: gpiiKeyExistsMsg }); } else { promiseTogo.resolve(input); } }, function (err) { promiseTogo.reject(err); }); } else { promiseTogo.resolve(input); } return promiseTogo; }; /** * Shared function in the promise transforming chain for implementing createPreferences() and updatePreferences() API. * Create a prefsSafe record with the provided prefsSafeData. * @param {Function} addPrefsSafe - The addPrefsSafe() API provided by gpii.oauth2.dbDataStore. * @param {Object} input - The data passed on from the entry function gpii.preferencesServer.preferencesService.createPreferences(). Its structure: * { * gpiiKey: {String} or {Object}, // {String} for createPreferences(), {Object} for updatePreferences() * prefsSafeData: { * prefsSafeType: {String}, // optional * name: {String}, // optional * password: {String}, // optional * email: {String}, // optional * preferences: {Object} // must be provided * } * } * @return {Promise} A promise object that carries the given input value with the created prefsSafeId being added. */ gpii.preferencesServer.preferencesService.createPrefsSafe = function (addPrefsSafe, input) { var promiseTogo = fluid.promise(); var prefsSafeData = input.prefsSafeData; var prefsSafeDataAdded = { prefsSafeType: prefsSafeData.prefsSafeType || gpii.preferencesServer.prefsSafeType.user, name: prefsSafeData.name || null, password: prefsSafeData.password || null, email: prefsSafeData.email || null, preferences: prefsSafeData.preferences }; var addPrefsSafePromise = addPrefsSafe(prefsSafeDataAdded); addPrefsSafePromise.then(function (addPrefsSafeResponse) { fluid.log("Preferences Service, created a new prefs safe with id: ", addPrefsSafeResponse.id); promiseTogo.resolve({ gpiiKey: input.gpiiKey, prefsSafeId: addPrefsSafeResponse.id, prefsSafeDataAdded: prefsSafeDataAdded }); }, function (err) { promiseTogo.reject(err); }); return promiseTogo; }; /** * The last step in the promise transforming chain for implementing createPreferences() API. * Create a gpiiKey record with the provided input. * @param {Function} addGpiiKey - The addGpiiKey() API provided by gpii.oauth2.dbDataStore. * @param {Object} input - The data passed on from the previous step. Its structure: * { * gpiiKey: {String}, * prefsSafeId: {String}, * prefsSafeDataAdded: { * prefsSafeType: {String} * name: {String} * password: {String} * email: {String} * preferences: {Object} // must be provided * } * } * @return {Promise} A promise object whose resolved value is: * { * gpiiKey: {String}, * preferences: {Object} * } */ gpii.preferencesServer.preferencesService.createGpiiKey = function (addGpiiKey, input) { var addGpiiKeyPromise = addGpiiKey({ gpiiKey: input.gpiiKey, prefsSafeId: input.prefsSafeId, prefsSetId: gpii.preferencesServer.defaultPrefsSetId }); var mapper = function (addGpiiKeyResponse) { fluid.log("Preferences Service, created a new GPII key with id: ", addGpiiKeyResponse.id); return { gpiiKey: addGpiiKeyResponse.id, preferences: input.prefsSafeDataAdded.preferences }; }; return fluid.promise.map(addGpiiKeyPromise, mapper); }; /** * The entry point of updatePreferences() API. * It handles: * 1. If an existing prefs safe already associates with the GPII key, update the prefs safe; * 2. If no prefs safe is associated with the GPII key, create the prefs safe and associate with the GPII key. * @param {Component} that - An instance of gpii.preferencesServer.preferencesService * @param {Object} preferences - The preferences to be updated * @param {String} [gpiiKey] - [optional] The new GPII key, an UUID will be generated if it's not provided * @param {Boolean} [merge] - [optional] A flag that indicates whether to merge the incoming preferences with the existing preferences * @return {Promise} A promise object whose resolved value is: * { * gpiiKey: {String}, * preferences: {Object} * } */ gpii.preferencesServer.preferencesService.updatePreferences = function (that, preferences, gpiiKey, merge) { var promiseTogo = fluid.promise(); var gpiiKeyPromise = that.dataStore.findPrefsSafeByGpiiKey(gpiiKey); gpiiKeyPromise.then(function (data) { var updatePromise = fluid.promise(); var prefsSafeId = fluid.get(data, ["gpiiKeyDetails", "prefsSafeId"]); if (prefsSafeId) { if (data.prefsSafe.prefsSafeType !== gpii.preferencesServer.prefsSafeType.user) { fluid.log("Preferences Service, reject the update request on a snapset key: ", gpiiKey); var readOnlyMsg = fluid.stringTemplate(gpii.preferencesServer.errors.readOnly.message, { gpiiKey: gpiiKey }); updatePromise.reject({ errorCode: gpii.preferencesServer.errors.readOnly.errorCode, message: readOnlyMsg }); } else { // The merge flag determines whether to merge the new preferences with the existing preferences var prefsSafeData = fluid.extend(merge, {}, data.prefsSafe, {preferences: preferences}); // Update the associated prefs safe var updatePrefsSafePromise = that.dataStore.updatePrefsSafe(prefsSafeId, prefsSafeData); var mapper = function () { return { gpiiKey: gpiiKey, preferences: preferences }; }; updatePromise = fluid.promise.map(updatePrefsSafePromise, mapper); } } else { // Create a prefs safe and associate it with the GPII key updatePromise = fluid.promise.fireTransformEvent(that.events.onAssociatePreferences, { gpiiKey: data.gpiiKeyDetails, prefsSafeData: { preferences: preferences } }); } fluid.promise.follow(updatePromise, promiseTogo); }, function (err) { promiseTogo.reject(err); }); return promiseTogo; }; /** * The last step in the promise transforming chain for implementing fireTransformEvent onAssociatePreferences event. * Update gpiiKey record with the created prefs safe id. * @param {Function} updateGpiiKey - The updateGpiiKey() API provided by gpii.oauth2.dbDataStore * @param {Object} input - The data passed on from the previous step. Its structure: * { * gpiiKey: {String}, * prefsSafeId: {String}, * prefsSafeDataAdded: { * prefsSafeType: {String} * name: {String} * password: {String} * email: {String} * preferences: {Object} // must be provided * } * } * @return {Promise} A promise object whose resolved value is: * { * gpiiKey: {String}, * preferences: {Object} * } */ gpii.preferencesServer.preferencesService.updateGpiiKey = function (updateGpiiKey, input) { var gpiiKeyRec = fluid.copy(input.gpiiKey); fluid.set(gpiiKeyRec, ["prefsSafeId"], input.prefsSafeId); fluid.set(gpiiKeyRec, ["prefsSetId"], gpii.preferencesServer.defaultPrefsSetId); var updateGpiiKeyPromise = updateGpiiKey(fluid.get(input, ["gpiiKey", "id"]), gpiiKeyRec); var mapper = function (response) { fluid.log("Preferences Service, updated GPII key with id: ", response.id); return { gpiiKey: response.id, preferences: response.preferences }; }; return fluid.promise.map(updateGpiiKeyPromise, mapper); }; /** * Verify if the preference server is running and the database connection is * good. * @param {Function} findAllViews - The findAllViews() API provided by * gpii.oauth2.dbDataStore * @return {Promise} resolves to {isReady: true} if the database connection * is ok. Otherwise, resolves to {isReady: false}. */ gpii.preferencesServer.preferencesService.isLive = function (findAllViews) { var promiseTogo = fluid.promise(); var viewsPromise = findAllViews(); viewsPromise.then(function (views) { promiseTogo.resolve({isReady: fluid.isPlainObject(views)}); }, function () { promiseTogo.resolve({isReady: false}); }); return promiseTogo; }; })();