gpii-universal
Version:
Cross platform, core components of the GPII personalization infrastructure.
208 lines (183 loc) • 8.31 kB
JavaScript
/*!
* User Logon Request
*
* Copyright 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
*/
"use strict";
var fluid = fluid || require("infusion"),
gpii = fluid.registerNamespace("gpii");
// One dynamic component of this type is constructed for each user logon request on the LifecycleManager.
fluid.defaults("gpii.lifecycleManager.userLogonRequest", {
gradeNames: ["fluid.component"],
logonState: null, // "login" or "logout". Supplied at defining inherited request handler grades
gpiiKey: null, // A GPII key. Supplied at creating dynamic request instances
requestPromise: null, // A promise. Supplied at creating dynamic request instances
events: {
onSuccess: null,
onError: null
},
invokers: {
handleRequest: {
funcName: "gpii.lifecycleManager.userLogonRequest.handleRequest",
args: ["{that}", "{lifecycleManager}", "{arguments}.0"]
// logonState
}
},
listeners: {
"onCreate.handleRequest": {
listener: "{that}.handleRequest",
args: ["{that}.options.logonState"]
},
"onSuccess.handleSuccessRequest": {
listener: "gpii.lifecycleManager.userLogonRequest.handleSuccessRequest",
args: ["{that}", "{arguments}.0"]
},
"onError.handleFailedRequest": {
listener: "gpii.lifecycleManager.userLogonRequest.handleFailedRequest",
args: ["{that}", "{lifecycleManager}.userErrors.events.userError", "{arguments}.0"],
priority: "after:handleErrors"
}
}
});
gpii.lifecycleManager.userLogonRequest.handleRequest = function (that, lifecycleManager, logonState) {
var gpiiKey = that.options.gpiiKey;
var activeGpiiKey = lifecycleManager.getActiveSessionGpiiKey(); // find currently logged in user:
// keep track of the last non-noUser key for /proximityTriggered endpoint to verify its debounce rule
// even when the the current active key is "noUser".
if (gpiiKey && gpiiKey !== "noUser") {
gpii.lifecycleManager.userLogonHandling.updateCurrentUserLogon(lifecycleManager, gpiiKey, logonState);
}
// handle reset requests
if (gpiiKey === "reset") {
that.handleResetGpiiKey();
return;
}
// handle keyin requests
if (logonState === "login") {
that.loginUser(gpiiKey);
}
// handle keyout requests
if (logonState === "logout") {
if (activeGpiiKey !== gpiiKey) {
var ignoreUserErrors = activeGpiiKey === "noUser" ? true : false;
lifecycleManager.errorResponse(that, "Got logout request from user " + gpiiKey + ", but the user " +
activeGpiiKey + " is logged in. So ignoring the request.", 409, ignoreUserErrors);
} else {
that.logoutUser(gpiiKey);
}
}
};
gpii.lifecycleManager.userLogonRequest.handleSuccessRequest = function (that, payload) {
fluid.log("UserLogonRequest completes successfully with the payload: ", payload);
that.options.requestPromise.resolve(payload);
that.destroy();
};
gpii.lifecycleManager.userLogonRequest.handleFailedRequest = function (that, userErrorEvent, err) {
fluid.log("UserLogonRequest fails with the error: ", err);
if (gpii.userErrors.isConnectionError(err.code)) {
userErrorEvent.fire({
isError: true,
messageKey: "NoConnection",
originalError: err
});
} else if (!err.ignoreUserErrors) {
userErrorEvent.fire({
isError: true,
messageKey: "KeyInFail",
originalError: err.message
});
}
that.options.requestPromise.reject(err);
that.destroy();
};
// Define the grade to be used for key-in and key-out
gpii.lifecycleManager.userLogonRequest.handlerGrades = {
login: "gpii.lifecycleManager.loginRequest",
logout: "gpii.lifecycleManager.logoutRequest"
};
// A variant of user logon request to handle key-in requests.
// Note: The gradename that handles the logon state change will be distributed down:
// 1. When GPII runs in the all-in-local config, the handler grade
// "gpii.lifecycleManager.userLogonHandling.matchMakingStateChangeHandler" is distributed by "gpii.flowManager.local";
// 2. When GPII runs in the untrusted config, the handler grade
// "gpii.lifecycleManager.untrusted.stateChangeHandler" is distributed by "gpii.flowManager.untrusted".
fluid.defaults("gpii.lifecycleManager.loginRequest", {
gradeNames: [
"gpii.lifecycleManager.userLogonRequest"
],
logonState: "login"
});
// A variant of user logon request to handle key-out requests.
fluid.defaults("gpii.lifecycleManager.logoutRequest", {
gradeNames: [
"gpii.lifecycleManager.userLogonRequest",
"gpii.lifecycleManager.userLogonHandling.stateChangeHandler"
],
logonState: "logout"
});
/*
* The lifecycleManager logon request queue is used to hold the key-in and key-out requests.
* The entries in the action queue are of the format:
* {
* gpiiKey: {String},
* logonState: {String} // enum: ["login", "logout"]
* }
* The action queue is run sequentially, and an item is considered "done" once the promise returned by the request
* is resolved.
*/
gpii.lifecycleManager.addToUserLogonRequestQueue = function (that, queue, item) {
var newItem = fluid.copy(item);
newItem.requestPromise = fluid.promise();
queue.push(newItem);
if (queue.length === 1) {
that.processUserLogonRequestQueue();
}
return newItem.requestPromise;
};
gpii.lifecycleManager.processUserLogonRequestQueue = function (that, queue) {
// Pick the first item and process. This item will be removed from the queue once the processing completes.
var item = queue[0];
var gradeName = gpii.lifecycleManager.userLogonRequest.handlerGrades[item.logonState];
if (!gradeName) {
fluid.fail("No handler grade found for user logon action - " + item.logonState);
};
that.events.onUserLogonRequestReceived.fire(gradeName, item.gpiiKey, item.requestPromise);
item.requestPromise.then(that.endProcessOneUserLogonRequest, that.endProcessOneUserLogonRequest);
};
gpii.lifecycleManager.endProcessOneUserLogonRequest = function (lifecycleManager) {
// TODO: fluid.invokeLater() is to work around an issue that kettle reports the error "Failing to resume callback for
// request xxx which has already concluded". The request that fails to resume callback is the user logon request that
// the current "endProcessOneUserLogonRequest" callback is attached with. It appears that starting the process of
// "noUser" keyin before the current callback completes triggers this error. fluid.invokeLater() helps to pull the
// "noUser" keyin into a separate process. The request failure needs to be further investigated.
fluid.invokeLater(function () {
var queue = lifecycleManager.userLogonRequestQueue;
// The processing on the first item completes. Remove it from the queue.
queue.shift();
if (queue.length > 0) {
// process next item in the queue if it exists
lifecycleManager.processUserLogonRequestQueue(queue);
} else {
// if no actual user is logged in, login with "noUser"
var activeGpiiKey = lifecycleManager.getActiveSessionGpiiKey(); // find currently logged in user:
// Checking lifecycleManager.model.logonChange.inProgress is to make sure during the period to finish
// this request handling, there isn't another user logon request being added to the queue and in process.
if (!activeGpiiKey) {
fluid.log("No active keys in GPII. Key in noUser");
lifecycleManager.addToUserLogonRequestQueue({
gpiiKey: "noUser",
logonState: "login"
});
}
else {
lifecycleManager.events.onQueueEmpty.fire(activeGpiiKey);
}
}
});
};