gpii-universal
Version:
Cross platform, core components of the GPII personalization infrastructure.
380 lines (356 loc) • 17.2 kB
JavaScript
/*!
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;
};
})();