You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2018/08/14 23:39:41 UTC
[03/13] guacamole-client git commit: GUACAMOLE-220: Add JavaScript
service for retrieving/manipulating user groups.
GUACAMOLE-220: Add JavaScript service for retrieving/manipulating user groups.
Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/9f01fcb1
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/9f01fcb1
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/9f01fcb1
Branch: refs/heads/master
Commit: 9f01fcb1558b11b52c78bcddee2ea601ab4b102c
Parents: c36d333
Author: Michael Jumper <mj...@apache.org>
Authored: Thu Apr 19 14:38:24 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Aug 8 09:00:06 2018 -0700
----------------------------------------------------------------------
.../webapp/app/rest/services/cacheService.js | 3 +-
.../app/rest/services/membershipService.js | 385 +++++++++++++++++++
.../app/rest/services/userGroupService.js | 223 +++++++++++
.../webapp/app/rest/types/RelatedObjectPatch.js | 85 ++++
.../src/main/webapp/app/rest/types/UserGroup.js | 59 +++
5 files changed, 754 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/9f01fcb1/guacamole/src/main/webapp/app/rest/services/cacheService.js
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/app/rest/services/cacheService.js b/guacamole/src/main/webapp/app/rest/services/cacheService.js
index 55b7fc1..9a32004 100644
--- a/guacamole/src/main/webapp/app/rest/services/cacheService.js
+++ b/guacamole/src/main/webapp/app/rest/services/cacheService.js
@@ -60,7 +60,8 @@ angular.module('rest').factory('cacheService', ['$injector',
service.schema = $cacheFactory('API-SCHEMA');
/**
- * Shared cache used by both userService and permissionService.
+ * Shared cache used by userService, userGroupService, permissionService,
+ * and membershipService.
*
* @type $cacheFactory.Cache
*/
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/9f01fcb1/guacamole/src/main/webapp/app/rest/services/membershipService.js
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/app/rest/services/membershipService.js b/guacamole/src/main/webapp/app/rest/services/membershipService.js
new file mode 100644
index 0000000..58181c8
--- /dev/null
+++ b/guacamole/src/main/webapp/app/rest/services/membershipService.js
@@ -0,0 +1,385 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * Service for operating on user group memberships via the REST API.
+ */
+angular.module('rest').factory('membershipService', ['$injector',
+ function membershipService($injector) {
+
+ // Required services
+ var requestService = $injector.get('requestService');
+ var authenticationService = $injector.get('authenticationService');
+ var cacheService = $injector.get('cacheService');
+
+ // Required types
+ var RelatedObjectPatch = $injector.get('RelatedObjectPatch');
+
+ var service = {};
+
+ /**
+ * Creates a new array of patches which represents the given changes to an
+ * arbitrary set of objects sharing some common relation.
+ *
+ * @param {String[]} [identifiersToAdd]
+ * The identifiers of all objects which should be added to the
+ * relation, if any.
+ *
+ * @param {String[]} [identifiersToRemove]
+ * The identifiers of all objects which should be removed from the
+ * relation, if any.
+ *
+ * @returns {RelatedObjectPatch[]}
+ * A new array of patches which represents the given changes.
+ */
+ var getRelatedObjectPatch = function getRelatedObjectPatch(identifiersToAdd, identifiersToRemove) {
+
+ var patch = [];
+
+ angular.forEach(identifiersToAdd, function addIdentifier(identifier) {
+ patch.push(new RelatedObjectPatch({
+ op : RelatedObjectPatch.Operation.ADD,
+ value : identifier
+ }));
+ });
+
+ angular.forEach(identifiersToRemove, function removeIdentifier(identifier) {
+ patch.push(new RelatedObjectPatch({
+ op : RelatedObjectPatch.Operation.REMOVE,
+ value : identifier
+ }));
+ });
+
+ return patch;
+
+ };
+
+ /**
+ * Returns the URL for the REST resource most appropriate for accessing
+ * the parent user groups of the user or group having the given identifier.
+ *
+ * It is important to note that a particular data source can authenticate
+ * and provide user groups for a user, even if that user does not exist
+ * within that data source (and thus cannot be found beneath
+ * "api/session/data/{dataSource}/users")
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user or
+ * group whose parent user groups should be retrieved. This identifier
+ * corresponds to an AuthenticationProvider within the Guacamole web
+ * application.
+ *
+ * @param {String} identifier
+ * The identifier of the user or group for which the URL of the proper
+ * REST resource should be derived.
+ *
+ * @param {Boolean} [group]
+ * Whether the provided identifier refers to a user group. If false or
+ * omitted, the identifier given is assumed to refer to a user.
+ *
+ * @returns {String}
+ * The URL for the REST resource representing the parent user groups of
+ * the user or group having the given identifier.
+ */
+ var getUserGroupsResourceURL = function getUserGroupsResourceURL(dataSource, identifier, group) {
+
+ // Create base URL for data source
+ var base = 'api/session/data/' + encodeURIComponent(dataSource);
+
+ // Access parent groups directly (there is no "self" for user groups
+ // as there is for users)
+ if (group)
+ return base + '/userGroups/' + encodeURIComponent(identifier) + '/userGroups';
+
+ // If the username is that of the current user, do not rely on the
+ // user actually existing (they may not). Access their parent groups via
+ // "self" rather than the collection of defined users.
+ if (identifier === authenticationService.getCurrentUsername())
+ return base + '/self/userGroups';
+
+ // Otherwise, the user must exist for their parent groups to be
+ // accessible. Use the collection of defined users.
+ return base + '/users/' + encodeURIComponent(identifier) + '/userGroups';
+
+ };
+
+ /**
+ * Makes a request to the REST API to retrieve the identifiers of all
+ * parent user groups of which a given user or group is a member, returning
+ * a promise that can be used for processing the results of the call.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user or
+ * group whose parent user groups should be retrieved. This identifier
+ * corresponds to an AuthenticationProvider within the Guacamole web
+ * application.
+ *
+ * @param {String} identifier
+ * The identifier of the user or group to retrieve the parent user
+ * groups of.
+ *
+ * @param {Boolean} [group]
+ * Whether the provided identifier refers to a user group. If false or
+ * omitted, the identifier given is assumed to refer to a user.
+ *
+ * @returns {Promise.<String[]>}
+ * A promise for the HTTP call which will resolve with an array
+ * containing the requested identifiers upon success.
+ */
+ service.getUserGroups = function getUserGroups(dataSource, identifier, group) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Retrieve parent groups
+ return requestService({
+ cache : cacheService.users,
+ method : 'GET',
+ url : getUserGroupsResourceURL(dataSource, identifier, group),
+ params : httpParameters
+ });
+
+ };
+
+ /**
+ * Makes a request to the REST API to modify the parent user groups of
+ * which a given user or group is a member, returning a promise that can be
+ * used for processing the results of the call.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user or
+ * group whose parent user groups should be modified. This identifier
+ * corresponds to an AuthenticationProvider within the Guacamole web
+ * application.
+ *
+ * @param {String} identifier
+ * The identifier of the user or group to modify the parent user
+ * groups of.
+ *
+ * @param {String[]} [addToUserGroups]
+ * The identifier of all parent user groups to which the given user or
+ * group should be added as a member, if any.
+ *
+ * @param {String[]} [removeFromUserGroups]
+ * The identifier of all parent user groups from which the given member
+ * user or group should be removed, if any.
+ *
+ * @param {Boolean} [group]
+ * Whether the provided identifier refers to a user group. If false or
+ * omitted, the identifier given is assumed to refer to a user.
+ *
+ * @returns {Promise}
+ * A promise for the HTTP call which will succeed if and only if the
+ * patch operation is successful.
+ */
+ service.patchUserGroups = function patchUserGroups(dataSource, identifier,
+ addToUserGroups, removeFromUserGroups, group) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Update parent user groups
+ return requestService({
+ method : 'PATCH',
+ url : getUserGroupsResourceURL(dataSource, identifier, group),
+ params : httpParameters,
+ data : getRelatedObjectPatch(addToUserGroups, removeFromUserGroups)
+ })
+
+ // Clear the cache
+ .then(function parentUserGroupsChanged(){
+ cacheService.users.removeAll();
+ });
+
+ };
+
+ /**
+ * Makes a request to the REST API to retrieve the identifiers of all
+ * users which are members of the given user group, returning a promise
+ * that can be used for processing the results of the call.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user group
+ * whose member users should be retrieved. This identifier corresponds
+ * to an AuthenticationProvider within the Guacamole web application.
+ *
+ * @param {String} identifier
+ * The identifier of the user group to retrieve the member users of.
+ *
+ * @returns {Promise.<String[]>}
+ * A promise for the HTTP call which will resolve with an array
+ * containing the requested identifiers upon success.
+ */
+ service.getMemberUsers = function getMemberUsers(dataSource, identifier) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Retrieve member users
+ return requestService({
+ cache : cacheService.users,
+ method : 'GET',
+ url : 'api/session/data/' + encodeURIComponent(dataSource) + '/userGroups/' + encodeURIComponent(identifier) + '/memberUsers',
+ params : httpParameters
+ });
+
+ };
+
+ /**
+ * Makes a request to the REST API to modify the member users of a given
+ * user group, returning a promise that can be used for processing the
+ * results of the call.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user group
+ * whose member users should be modified. This identifier corresponds
+ * to an AuthenticationProvider within the Guacamole web application.
+ *
+ * @param {String} identifier
+ * The identifier of the user group to modify the member users of.
+ *
+ * @param {String[]} [usersToAdd]
+ * The identifier of all users to add as members of the given user
+ * group, if any.
+ *
+ * @param {String[]} [usersToRemove]
+ * The identifier of all users to remove from the given user group,
+ * if any.
+ *
+ * @returns {Promise}
+ * A promise for the HTTP call which will succeed if and only if the
+ * patch operation is successful.
+ */
+ service.patchMemberUsers = function patchMemberUsers(dataSource, identifier,
+ usersToAdd, usersToRemove) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Update member users
+ return requestService({
+ method : 'PATCH',
+ url : 'api/session/data/' + encodeURIComponent(dataSource) + '/userGroups/' + encodeURIComponent(identifier) + '/memberUsers',
+ params : httpParameters,
+ data : getRelatedObjectPatch(usersToAdd, usersToRemove)
+ })
+
+ // Clear the cache
+ .then(function memberUsersChanged(){
+ cacheService.users.removeAll();
+ });
+
+ };
+
+ /**
+ * Makes a request to the REST API to retrieve the identifiers of all
+ * user groups which are members of the given user group, returning a
+ * promise that can be used for processing the results of the call.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user group
+ * whose member user groups should be retrieved. This identifier
+ * corresponds to an AuthenticationProvider within the Guacamole web
+ * application.
+ *
+ * @param {String} identifier
+ * The identifier of the user group to retrieve the member user
+ * groups of.
+ *
+ * @returns {Promise.<String[]>}
+ * A promise for the HTTP call which will resolve with an array
+ * containing the requested identifiers upon success.
+ */
+ service.getMemberUserGroups = function getMemberUserGroups(dataSource, identifier) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Retrieve member user groups
+ return requestService({
+ cache : cacheService.users,
+ method : 'GET',
+ url : 'api/session/data/' + encodeURIComponent(dataSource) + '/userGroups/' + encodeURIComponent(identifier) + '/memberUserGroups',
+ params : httpParameters
+ });
+
+ };
+
+ /**
+ * Makes a request to the REST API to modify the member user groups of a
+ * given user group, returning a promise that can be used for processing
+ * the results of the call.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user group
+ * whose member user groups should be modified. This identifier
+ * corresponds to an AuthenticationProvider within the Guacamole web
+ * application.
+ *
+ * @param {String} identifier
+ * The identifier of the user group to modify the member user groups of.
+ *
+ * @param {String[]} [userGroupsToAdd]
+ * The identifier of all user groups to add as members of the given
+ * user group, if any.
+ *
+ * @param {String[]} [userGroupsToRemove]
+ * The identifier of all member user groups to remove from the given
+ * user group, if any.
+ *
+ * @returns {Promise}
+ * A promise for the HTTP call which will succeed if and only if the
+ * patch operation is successful.
+ */
+ service.patchMemberUserGroups = function patchMemberUserGroups(dataSource,
+ identifier, userGroupsToAdd, userGroupsToRemove) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Update member user groups
+ return requestService({
+ method : 'PATCH',
+ url : 'api/session/data/' + encodeURIComponent(dataSource) + '/userGroups/' + encodeURIComponent(identifier) + '/memberUserGroups',
+ params : httpParameters,
+ data : getRelatedObjectPatch(userGroupsToAdd, userGroupsToRemove)
+ })
+
+ // Clear the cache
+ .then(function memberUserGroupsChanged(){
+ cacheService.users.removeAll();
+ });
+
+ };
+
+ return service;
+
+}]);
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/9f01fcb1/guacamole/src/main/webapp/app/rest/services/userGroupService.js
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/app/rest/services/userGroupService.js b/guacamole/src/main/webapp/app/rest/services/userGroupService.js
new file mode 100644
index 0000000..ad29837
--- /dev/null
+++ b/guacamole/src/main/webapp/app/rest/services/userGroupService.js
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * Service for operating on user groups via the REST API.
+ */
+angular.module('rest').factory('userGroupService', ['$injector',
+ function userGroupService($injector) {
+
+ // Required services
+ var requestService = $injector.get('requestService');
+ var authenticationService = $injector.get('authenticationService');
+ var cacheService = $injector.get('cacheService');
+
+ var service = {};
+
+ /**
+ * Makes a request to the REST API to get the list of user groups,
+ * returning a promise that provides an array of @link{UserGroup} objects if
+ * successful.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user groups
+ * to be retrieved. This identifier corresponds to an
+ * AuthenticationProvider within the Guacamole web application.
+ *
+ * @param {String[]} [permissionTypes]
+ * The set of permissions to filter with. A user group must have one or
+ * more of these permissions for a user group to appear in the result.
+ * If null, no filtering will be performed. Valid values are listed
+ * within PermissionSet.ObjectType.
+ *
+ * @returns {Promise.<Object.<String, UserGroup>>}
+ * A promise which will resolve with a map of @link{UserGroup} objects
+ * where each key is the identifier of the corresponding user group.
+ */
+ service.getUserGroups = function getUserGroups(dataSource, permissionTypes) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Add permission filter if specified
+ if (permissionTypes)
+ httpParameters.permission = permissionTypes;
+
+ // Retrieve user groups
+ return requestService({
+ cache : cacheService.users,
+ method : 'GET',
+ url : 'api/session/data/' + encodeURIComponent(dataSource) + '/userGroups',
+ params : httpParameters
+ });
+
+ };
+
+ /**
+ * Makes a request to the REST API to get the user group having the given
+ * identifier, returning a promise that provides the corresponding
+ * @link{UserGroup} if successful.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user group to
+ * be retrieved. This identifier corresponds to an
+ * AuthenticationProvider within the Guacamole web application.
+ *
+ * @param {String} identifier
+ * The identifier of the user group to retrieve.
+ *
+ * @returns {Promise.<UserGroup>}
+ * A promise which will resolve with a @link{UserGroup} upon success.
+ */
+ service.getUserGroup = function getUserGroup(dataSource, identifier) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Retrieve user group
+ return requestService({
+ cache : cacheService.users,
+ method : 'GET',
+ url : 'api/session/data/' + encodeURIComponent(dataSource) + '/userGroups/' + encodeURIComponent(identifier),
+ params : httpParameters
+ });
+
+ };
+
+ /**
+ * Makes a request to the REST API to delete a user group, returning a
+ * promise that can be used for processing the results of the call.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user group to
+ * be deleted. This identifier corresponds to an AuthenticationProvider
+ * within the Guacamole web application.
+ *
+ * @param {UserGroup} userGroup
+ * The user group to delete.
+ *
+ * @returns {Promise}
+ * A promise for the HTTP call which will succeed if and only if the
+ * delete operation is successful.
+ */
+ service.deleteUserGroup = function deleteUserGroup(dataSource, userGroup) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Delete user group
+ return requestService({
+ method : 'DELETE',
+ url : 'api/session/data/' + encodeURIComponent(dataSource) + '/userGroups/' + encodeURIComponent(userGroup.identifier),
+ params : httpParameters
+ })
+
+ // Clear the cache
+ .then(function userGroupDeleted(){
+ cacheService.users.removeAll();
+ });
+
+
+ };
+
+ /**
+ * Makes a request to the REST API to create a user group, returning a promise
+ * that can be used for processing the results of the call.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source in which the user group
+ * should be created. This identifier corresponds to an
+ * AuthenticationProvider within the Guacamole web application.
+ *
+ * @param {UserGroup} userGroup
+ * The user group to create.
+ *
+ * @returns {Promise}
+ * A promise for the HTTP call which will succeed if and only if the
+ * create operation is successful.
+ */
+ service.createUserGroup = function createUserGroup(dataSource, userGroup) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Create user group
+ return requestService({
+ method : 'POST',
+ url : 'api/session/data/' + encodeURIComponent(dataSource) + '/userGroups',
+ params : httpParameters,
+ data : userGroup
+ })
+
+ // Clear the cache
+ .then(function userGroupCreated(){
+ cacheService.users.removeAll();
+ });
+
+ };
+
+ /**
+ * Makes a request to the REST API to save a user group, returning a
+ * promise that can be used for processing the results of the call.
+ *
+ * @param {String} dataSource
+ * The unique identifier of the data source containing the user group to
+ * be updated. This identifier corresponds to an AuthenticationProvider
+ * within the Guacamole web application.
+ *
+ * @param {UserGroup} userGroup
+ * The user group to update.
+ *
+ * @returns {Promise}
+ * A promise for the HTTP call which will succeed if and only if the
+ * save operation is successful.
+ */
+ service.saveUserGroup = function saveUserGroup(dataSource, userGroup) {
+
+ // Build HTTP parameters set
+ var httpParameters = {
+ token : authenticationService.getCurrentToken()
+ };
+
+ // Update user group
+ return requestService({
+ method : 'PUT',
+ url : 'api/session/data/' + encodeURIComponent(dataSource) + '/userGroups/' + encodeURIComponent(userGroup.identifier),
+ params : httpParameters,
+ data : userGroup
+ })
+
+ // Clear the cache
+ .then(function userGroupUpdated(){
+ cacheService.users.removeAll();
+ });
+
+ };
+
+ return service;
+
+}]);
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/9f01fcb1/guacamole/src/main/webapp/app/rest/types/RelatedObjectPatch.js
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/app/rest/types/RelatedObjectPatch.js b/guacamole/src/main/webapp/app/rest/types/RelatedObjectPatch.js
new file mode 100644
index 0000000..bb82def
--- /dev/null
+++ b/guacamole/src/main/webapp/app/rest/types/RelatedObjectPatch.js
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * Service which defines the RelatedObjectPatch class.
+ */
+angular.module('rest').factory('RelatedObjectPatch', [function defineRelatedObjectPatch() {
+
+ /**
+ * The object returned by REST API calls when representing changes to an
+ * arbitrary set of objects which share some common relation.
+ *
+ * @constructor
+ * @param {RelatedObjectPatch|Object} [template={}]
+ * The object whose properties should be copied within the new
+ * RelatedObjectPatch.
+ */
+ var RelatedObjectPatch = function RelatedObjectPatch(template) {
+
+ // Use empty object by default
+ template = template || {};
+
+ /**
+ * The operation to apply to the objects indicated by the path. Valid
+ * operation values are defined within RelatedObjectPatch.Operation.
+ *
+ * @type String
+ */
+ this.op = template.op;
+
+ /**
+ * The path of the objects to modify. This will always be "/".
+ *
+ * @type String
+ * @default '/'
+ */
+ this.path = template.path || '/';
+
+ /**
+ * The identifier of the object being added or removed from the
+ * relation.
+ *
+ * @type String
+ */
+ this.value = template.value;
+
+ };
+
+ /**
+ * All valid patch operations for objects sharing some common relation.
+ * Currently, only add and remove are supported.
+ */
+ RelatedObjectPatch.Operation = {
+
+ /**
+ * Adds the specified object to the relation.
+ */
+ ADD : "add",
+
+ /**
+ * Removes the specified object from the relation.
+ */
+ REMOVE : "remove"
+
+ };
+
+ return RelatedObjectPatch;
+
+}]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/9f01fcb1/guacamole/src/main/webapp/app/rest/types/UserGroup.js
----------------------------------------------------------------------
diff --git a/guacamole/src/main/webapp/app/rest/types/UserGroup.js b/guacamole/src/main/webapp/app/rest/types/UserGroup.js
new file mode 100644
index 0000000..03b73e2
--- /dev/null
+++ b/guacamole/src/main/webapp/app/rest/types/UserGroup.js
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * Service which defines the UserGroup class.
+ */
+angular.module('rest').factory('UserGroup', [function defineUserGroup() {
+
+ /**
+ * The object returned by REST API calls when representing the data
+ * associated with a user group.
+ *
+ * @constructor
+ * @param {UserGroup|Object} [template={}]
+ * The object whose properties should be copied within the new
+ * UserGroup.
+ */
+ var UserGroup = function UserGroup(template) {
+
+ // Use empty object by default
+ template = template || {};
+
+ /**
+ * The name which uniquely identifies this user group.
+ *
+ * @type String
+ */
+ this.identifier = template.identifier;
+
+ /**
+ * Arbitrary name/value pairs which further describe this user group.
+ * The semantics and validity of these attributes are dictated by the
+ * extension which defines them.
+ *
+ * @type Object.<String, String>
+ */
+ this.attributes = {};
+
+ };
+
+ return UserGroup;
+
+}]);
\ No newline at end of file