diff --git a/guacamole/src/main/webapp/app/client/controllers/clientController.js b/guacamole/src/main/webapp/app/client/controllers/clientController.js index dc39fc28b..be93a559b 100644 --- a/guacamole/src/main/webapp/app/client/controllers/clientController.js +++ b/guacamole/src/main/webapp/app/client/controllers/clientController.js @@ -134,7 +134,7 @@ angular.module('home').controller('clientController', ['$scope', '$routeParams', // Get DAO for reading connections and groups var connectionGroupDAO = $injector.get('connectionGroupDAO'); - var connectionDAO = $injector.get('connectionDAO'); + var connectionService = $injector.get('connectionService'); var ClientProperties = $injector.get('ClientProperties'); // Client settings and state @@ -169,7 +169,7 @@ angular.module('home').controller('clientController', ['$scope', '$routeParams', // Connection case 'c': - connectionDAO.getConnection($routeParams.id).success(function (connection) { + connectionService.getConnection($routeParams.id).success(function (connection) { $scope.connectionName = $scope.page.title = connection.name; }); break; diff --git a/guacamole/src/main/webapp/app/connection/service/connectionDAO.js b/guacamole/src/main/webapp/app/connection/service/connectionService.js similarity index 65% rename from guacamole/src/main/webapp/app/connection/service/connectionDAO.js rename to guacamole/src/main/webapp/app/connection/service/connectionService.js index 94797b964..42a93fb7a 100644 --- a/guacamole/src/main/webapp/app/connection/service/connectionDAO.js +++ b/guacamole/src/main/webapp/app/connection/service/connectionService.js @@ -21,19 +21,26 @@ */ /** - * The DAO for connection operations agains the REST API. + * Service for operating on connections via the REST API. */ -angular.module('connection').factory('connectionDAO', ['$http', 'authenticationService', - function connectionDAO($http, authenticationService) { +angular.module('connection').factory('connectionService', ['$http', 'authenticationService', + function connectionService($http, authenticationService) { var service = {}; /** * Makes a request to the REST API to get a single connection, returning a - * promise that can be used for processing the results of the call. + * promise that provides the corresponding @link{Connection} if successful. * - * @param {string} id The ID of the connection. - * @returns {promise} A promise for the HTTP call. + * @param {String} id The ID of the connection. + * @returns {Promise.} + * A promise which will resolve with a @link{Connection} upon success. + * + * @example + * + * connectionService.getConnection('myConnection').success(function(connection) { + * // Do something with the connection + * }); */ service.getConnection = function getConnection(id) { return $http.get("api/connection/" + id + "?token=" + authenticationService.getCurrentToken()); @@ -41,13 +48,16 @@ angular.module('connection').factory('connectionDAO', ['$http', 'authenticationS /** * Makes a request to the REST API to get the list of connections, - * returning a promise that can be used for processing the results of the call. + * returning a promise that can be used for processing the results of the + * call. * * @param {string} parentID The parent ID for the connection. * If not passed in, it will query a list of the * connections in the root group. * - * @returns {promise} A promise for the HTTP call. + * @returns {Promise.} + * A promise which will resolve with an array of @link{Connection} + * objects upon success. */ service.getConnections = function getConnections(parentID) { @@ -59,15 +69,22 @@ angular.module('connection').factory('connectionDAO', ['$http', 'authenticationS }; /** - * Makes a request to the REST API to save a connection, - * returning a promise that can be used for processing the results of the call. + * Makes a request to the REST API to save a connection, returning a + * promise that can be used for processing the results of the call. * - * @param {object} connection The connection to update + * @param {Connection} connection The connection to update * - * @returns {promise} A promise for the HTTP call. + * @returns {Promise} + * A promise for the HTTP call which will succeed if and only if the + * save operation is successful. */ service.saveConnection = function saveConnection(connection) { + /* + * FIXME: This should not be necessary. Perhaps the need for this is a + * sign that history should be queried separately, and not reside as + * part of the connection object? + */ // Do not try to save the connection history records var connectionToSave = angular.copy(connection); delete connectionToSave.history; @@ -77,8 +94,8 @@ angular.module('connection').factory('connectionDAO', ['$http', 'authenticationS return $http.post("api/connection/?token=" + authenticationService.getCurrentToken(), connectionToSave).success( function setConnectionID(connectionID){ // Set the identifier on the new connection - connection.identifier = connectionID; - return connectionID; + connection.identifier = connectionID; // FIXME: Functions with side effects = bad + return connectionID; // FIXME: Why? Where does this value go? }); } else { return $http.post( @@ -89,12 +106,17 @@ angular.module('connection').factory('connectionDAO', ['$http', 'authenticationS }; /** - * Makes a request to the REST API to move a connection to a different group, - * returning a promise that can be used for processing the results of the call. + * FIXME: Why is this different from save? * - * @param {object} connection The connection to move. + * Makes a request to the REST API to move a connection to a different + * group, returning a promise that can be used for processing the results + * of the call. + * + * @param {Connection} connection The connection to move. * - * @returns {promise} A promise for the HTTP call. + * @returns {Promise} + * A promise for the HTTP call which will succeed if and only if the + * move operation is successful. */ service.moveConnection = function moveConnection(connection) { @@ -110,9 +132,11 @@ angular.module('connection').factory('connectionDAO', ['$http', 'authenticationS * Makes a request to the REST API to delete a connection, * returning a promise that can be used for processing the results of the call. * - * @param {object} connection The connection to delete + * @param {Connection} connection The connection to delete * - * @returns {promise} A promise for the HTTP call. + * @returns {Promise} + * A promise for the HTTP call which will succeed if and only if the + * delete operation is successful. */ service.deleteConnection = function deleteConnection(connection) { return $http['delete']( diff --git a/guacamole/src/main/webapp/app/connection/types/Connection.js b/guacamole/src/main/webapp/app/connection/types/Connection.js new file mode 100644 index 000000000..59ed68c91 --- /dev/null +++ b/guacamole/src/main/webapp/app/connection/types/Connection.js @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * Service which defines the Connection class. + */ +angular.module('connection').factory('Connection', [function defineConnection() { + + /** + * The object returned by REST API calls when representing the data + * associated with a connection. + * + * @constructor + * @param {Connection|Object} [template={}] + * The object whose properties should be copied within the new + * Connection. + */ + var Connection = function Connection(template) { + + // Use empty object by default + template = template || {}; + + /** + * The unique identifier associated with this connection. + * + * @type String + */ + this.identifier = template.identifier; + + /** + * The unique identifier of the connection group that contains this + * connection. + * + * @type String + */ + this.parentIdentifier = template.parentIdentifier; + + /** + * The human-readable name of this connection, which is not necessarily + * unique. + * + * @type String + */ + this.name = template.name; + + /** + * The name of the protocol associated with this connection, such as + * "vnc" or "rdp". + * + * @type String + */ + this.protocol = template.protocol; + + /** + * All previous and current usages of this connection, along with + * associated users. + * + * @type ConnectionHistoryEntry[] + */ + this.history = template.history || []; + + /** + * Connection configuration parameters, as dictated by the protocol in + * use, arranged as name/value pairs. This information may not be + * available if the current user lacks permission to update + * connection parameters, even if they otherwise have permission to + * read and use the connection. + * + * @type Object. + */ + this.parameters = template.parameters || {}; + + }; + + return Connection; + +}]); \ No newline at end of file diff --git a/guacamole/src/main/webapp/app/connection/types/ConnectionHistoryEntry.js b/guacamole/src/main/webapp/app/connection/types/ConnectionHistoryEntry.js new file mode 100644 index 000000000..7409e52b9 --- /dev/null +++ b/guacamole/src/main/webapp/app/connection/types/ConnectionHistoryEntry.js @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * Service which defines the ConnectionHistoryEntry class. + */ +angular.module('connection').factory('ConnectionHistoryEntry', [function defineConnectionHistoryEntry() { + + /** + * The object returned by REST API calls when representing the data + * associated with an entry in a connection's usage history. Each history + * entry represents the time at which a particular started using a + * connection and, if applicable, the time that usage stopped. + * + * @constructor + * @param {ConnectionHistoryEntry|Object} [template={}] + * The object whose properties should be copied within the new + * ConnectionHistoryEntry. + */ + var ConnectionHistoryEntry = function ConnectionHistoryEntry(template) { + + // Use empty object by default + template = template || {}; + + /** + * The time that usage began, in seconds since 1970-01-01 00:00:00 UTC. + * + * @type Number + */ + this.startDate = template.startDate; + + /** + * The time that usage ended, in seconds since 1970-01-01 00:00:00 UTC. + * The absence of an endDate does NOT necessarily indicate that the + * connection is still in use, particularly if the server was shutdown + * or restarted before the history entry could be updated. To determine + * whether a connection is still active, check the active property of + * this history entry. + * + * @type Number + */ + this.endDate = template.endDate; + + /** + * The username of the user associated with this particular usage of + * the connection. + * + * @type String + */ + this.username = template.username; + + /** + * Whether this usage of the connection is still active. Note that this + * is the only accurate way to check for connection activity; the + * absence of endDate does not necessarily imply the connection is + * active, as the history entry may simply be incomplete. + * + * @type Boolean + */ + this.active = template.active; + + }; + + return ConnectionHistoryEntry; + +}]); \ No newline at end of file diff --git a/guacamole/src/main/webapp/app/connectionGroup/service/connectionGroupService.js b/guacamole/src/main/webapp/app/connectionGroup/service/connectionGroupService.js index 92bb8c2a7..36f358760 100644 --- a/guacamole/src/main/webapp/app/connectionGroup/service/connectionGroupService.js +++ b/guacamole/src/main/webapp/app/connectionGroup/service/connectionGroupService.js @@ -26,7 +26,7 @@ angular.module('connectionGroup').factory('connectionGroupService', ['$injector', function connectionGroupService($injector) { var connectionGroupDAO = $injector.get('connectionGroupDAO'); - var connectionDAO = $injector.get('connectionDAO'); + var connectionService = $injector.get('connectionService'); var permissionCheckService = $injector.get('permissionCheckService'); var $q = $injector.get('$q'); var displayObjectPreparationService = $injector.get('displayObjectPreparationService'); @@ -48,7 +48,7 @@ angular.module('connectionGroup').factory('connectionGroupService', ['$injector' if(includeConnections) { // Get all connections in the group and add them under this connection group context.openRequest(); - connectionDAO.getConnections(connectionGroup.identifier).success(function fetchConnections(connections) { + connectionService.getConnections(connectionGroup.identifier).success(function fetchConnections(connections) { for(var i = 0; i < connections.length; i++) { connections[i].isConnection = true; connectionGroup.children.push(connections[i]); @@ -148,7 +148,7 @@ angular.module('connectionGroup').factory('connectionGroupService', ['$injector' if(includeConnections) { // Get all connections in the root group and add them under this connection group context.openRequest(); - connectionDAO.getConnections().success(function fetchRootConnections(connections) { + connectionService.getConnections().success(function fetchRootConnections(connections) { for(var i = 0; i < connections.length; i++) { // Prepare this connection for display diff --git a/guacamole/src/main/webapp/app/manage/controllers/connectionEditModalController.js b/guacamole/src/main/webapp/app/manage/controllers/connectionEditModalController.js index 87f8598b8..3364dfcb0 100644 --- a/guacamole/src/main/webapp/app/manage/controllers/connectionEditModalController.js +++ b/guacamole/src/main/webapp/app/manage/controllers/connectionEditModalController.js @@ -27,7 +27,7 @@ angular.module('manage').controller('connectionEditModalController', ['$scope', function connectionEditModalController($scope, $injector) { var connectionEditModal = $injector.get('connectionEditModal'); - var connectionDAO = $injector.get('connectionDAO'); + var connectionService = $injector.get('connectionService'); var displayObjectPreparationService = $injector.get('displayObjectPreparationService'); // Make a copy of the old connection so that we can copy over the changes when done @@ -56,7 +56,7 @@ angular.module('manage').controller('connectionEditModalController', ['$scope', * Save the connection and close the modal. */ $scope.save = function save() { - connectionDAO.saveConnection($scope.connection).success(function successfullyUpdatedConnection() { + connectionService.saveConnection($scope.connection).success(function successfullyUpdatedConnection() { var oldParentID = oldConnection.parentIdentifier; var newParentID = $scope.connection.parentIdentifier; @@ -71,7 +71,7 @@ angular.module('manage').controller('connectionEditModalController', ['$scope', if(newConnection && newParentID === $scope.rootGroup.identifier) { $scope.moveItem($scope.connection, oldParentID, newParentID); } else { - connectionDAO.moveConnection($scope.connection).then(function moveConnection() { + connectionService.moveConnection($scope.connection).then(function moveConnection() { $scope.moveItem($scope.connection, oldParentID, newParentID); }); } @@ -94,7 +94,7 @@ angular.module('manage').controller('connectionEditModalController', ['$scope', return; } - connectionDAO.deleteConnection($scope.connection).success(function successfullyDeletedConnection() { + connectionService.deleteConnection($scope.connection).success(function successfullyDeletedConnection() { var oldParentID = oldConnection.parentIdentifier; // We have to remove this connection from the heirarchy