mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 00:53:21 +00:00 
			
		
		
		
	Merge pull request #22 from glyptodon/cleanup-angular
Rewrite an absolute ton of Angular and REST code
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,4 @@ | |||||||
| *~ | *~ | ||||||
| target/ | target/ | ||||||
| nb-configuration.xml | nb-configuration.xml | ||||||
|  | guacamole/customs.json | ||||||
|   | |||||||
| @@ -162,4 +162,31 @@ public class GuacamoleConfiguration implements Serializable { | |||||||
|         return Collections.unmodifiableSet(parameters.keySet()); |         return Collections.unmodifiableSet(parameters.keySet()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns a map which contains parameter name/value pairs as key/value | ||||||
|  |      * pairs. Changes to this map will affect the parameters stored within | ||||||
|  |      * this configuration. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A map which contains all parameter name/value pairs as key/value | ||||||
|  |      *     pairs. | ||||||
|  |      */ | ||||||
|  |     public Map<String, String> getParameters() { | ||||||
|  |         return parameters; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Replaces all current parameters with the parameters defined within the | ||||||
|  |      * given map. Key/value pairs within the map represent parameter name/value | ||||||
|  |      * pairs. | ||||||
|  |      * | ||||||
|  |      * @param parameters | ||||||
|  |      *     A map which contains all parameter name/value pairs as key/value | ||||||
|  |      *     pairs. | ||||||
|  |      */ | ||||||
|  |     public void setParameters(Map<String, String> parameters) { | ||||||
|  |         this.parameters.clear(); | ||||||
|  |         this.parameters.putAll(parameters); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -23,11 +23,7 @@ | |||||||
| package org.glyptodon.guacamole.net.basic.rest; | package org.glyptodon.guacamole.net.basic.rest; | ||||||
|  |  | ||||||
| import com.google.inject.AbstractModule; | import com.google.inject.AbstractModule; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionService; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupService; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.permission.PermissionService; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.protocol.ProtocolRetrievalService; | import org.glyptodon.guacamole.net.basic.rest.protocol.ProtocolRetrievalService; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.user.UserService; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * A Guice Module for setting up dependency injection for the  |  * A Guice Module for setting up dependency injection for the  | ||||||
| @@ -41,10 +37,6 @@ public class RESTModule extends AbstractModule { | |||||||
|     protected void configure() { |     protected void configure() { | ||||||
|  |  | ||||||
|         // Bind generic low-level services |         // Bind generic low-level services | ||||||
|         bind(ConnectionService.class); |  | ||||||
|         bind(ConnectionGroupService.class); |  | ||||||
|         bind(PermissionService.class); |  | ||||||
|         bind(UserService.class); |  | ||||||
|         bind(ProtocolRetrievalService.class); |         bind(ProtocolRetrievalService.class); | ||||||
|          |          | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -30,7 +30,6 @@ import org.glyptodon.guacamole.net.basic.rest.auth.TokenRESTService; | |||||||
| import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService; | import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService; | import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupRESTService; | import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupRESTService; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.permission.PermissionRESTService; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.protocol.ProtocolRESTService; | import org.glyptodon.guacamole.net.basic.rest.protocol.ProtocolRESTService; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.user.UserRESTService; | import org.glyptodon.guacamole.net.basic.rest.user.UserRESTService; | ||||||
|  |  | ||||||
| @@ -48,7 +47,6 @@ public class RESTServletModule extends ServletModule { | |||||||
|         bind(ClipboardRESTService.class); |         bind(ClipboardRESTService.class); | ||||||
|         bind(ConnectionRESTService.class); |         bind(ConnectionRESTService.class); | ||||||
|         bind(ConnectionGroupRESTService.class); |         bind(ConnectionGroupRESTService.class); | ||||||
|         bind(PermissionRESTService.class); |  | ||||||
|         bind(ProtocolRESTService.class); |         bind(ProtocolRESTService.class); | ||||||
|         bind(UserRESTService.class); |         bind(UserRESTService.class); | ||||||
|         bind(TokenRESTService.class); |         bind(TokenRESTService.class); | ||||||
|   | |||||||
| @@ -48,7 +48,7 @@ import org.slf4j.LoggerFactory; | |||||||
|  *  |  *  | ||||||
|  * @author James Muehlner |  * @author James Muehlner | ||||||
|  */ |  */ | ||||||
| @Path("/token") | @Path("/tokens") | ||||||
| @Produces(MediaType.APPLICATION_JSON) | @Produces(MediaType.APPLICATION_JSON) | ||||||
| public class TokenRESTService { | public class TokenRESTService { | ||||||
|      |      | ||||||
|   | |||||||
| @@ -22,14 +22,11 @@ | |||||||
|  |  | ||||||
| package org.glyptodon.guacamole.net.basic.rest.connection; | package org.glyptodon.guacamole.net.basic.rest.connection; | ||||||
|  |  | ||||||
| import java.util.HashMap; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import org.codehaus.jackson.annotate.JsonIgnoreProperties; | import org.codehaus.jackson.annotate.JsonIgnoreProperties; | ||||||
| import org.glyptodon.guacamole.GuacamoleException; | import org.glyptodon.guacamole.GuacamoleException; | ||||||
| import org.glyptodon.guacamole.net.auth.Connection; | import org.glyptodon.guacamole.net.auth.Connection; | ||||||
| import org.glyptodon.guacamole.net.auth.ConnectionRecord; | import org.glyptodon.guacamole.net.basic.rest.connectiongroup.APIConnectionGroup; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.APIConstants; |  | ||||||
| import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; | import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -60,15 +57,10 @@ public class APIConnection { | |||||||
|      */ |      */ | ||||||
|     private String protocol; |     private String protocol; | ||||||
|      |      | ||||||
|     /** |  | ||||||
|      * The history records associated with this connection. |  | ||||||
|      */ |  | ||||||
|     private List<? extends ConnectionRecord> history; |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Map of all associated parameter values, indexed by parameter name. |      * Map of all associated parameter values, indexed by parameter name. | ||||||
|      */ |      */ | ||||||
|     private Map<String, String> parameters = new HashMap<String, String>(); |     private Map<String, String> parameters; | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * Create an empty APIConnection. |      * Create an empty APIConnection. | ||||||
| @@ -76,7 +68,9 @@ public class APIConnection { | |||||||
|     public APIConnection() {} |     public APIConnection() {} | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * Create an APIConnection from a Connection record. |      * Create an APIConnection from a Connection record. Parameters for the | ||||||
|  |      * connection will not be included. | ||||||
|  |      * | ||||||
|      * @param connection The connection to create this APIConnection from. |      * @param connection The connection to create this APIConnection from. | ||||||
|      * @throws GuacamoleException If a problem is encountered while |      * @throws GuacamoleException If a problem is encountered while | ||||||
|      *                            instantiating this new APIConnection. |      *                            instantiating this new APIConnection. | ||||||
| @@ -84,22 +78,19 @@ public class APIConnection { | |||||||
|     public APIConnection(Connection connection)  |     public APIConnection(Connection connection)  | ||||||
|             throws GuacamoleException { |             throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         // Set identifying information | ||||||
|         this.name = connection.getName(); |         this.name = connection.getName(); | ||||||
|         this.identifier = connection.getIdentifier(); |         this.identifier = connection.getIdentifier(); | ||||||
|  |          | ||||||
|  |         // Set proper parent identifier, using root identifier if needed | ||||||
|         this.parentIdentifier = connection.getParentIdentifier(); |         this.parentIdentifier = connection.getParentIdentifier(); | ||||||
|         this.history = connection.getHistory(); |  | ||||||
|          |  | ||||||
|         // Use the explicit ROOT group ID |  | ||||||
|         if (this.parentIdentifier == null) |         if (this.parentIdentifier == null) | ||||||
|             this.parentIdentifier = APIConstants.ROOT_CONNECTION_GROUP_IDENTIFIER; |             this.parentIdentifier = APIConnectionGroup.ROOT_IDENTIFIER; | ||||||
|  |  | ||||||
|  |         // Set protocol from configuration | ||||||
|         GuacamoleConfiguration configuration = connection.getConfiguration(); |         GuacamoleConfiguration configuration = connection.getConfiguration(); | ||||||
|          |  | ||||||
|         this.protocol = configuration.getProtocol(); |         this.protocol = configuration.getProtocol(); | ||||||
|  |  | ||||||
|         for (String key: configuration.getParameterNames()) |  | ||||||
|             this.parameters.put(key, configuration.getParameter(key)); |  | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -151,14 +142,6 @@ public class APIConnection { | |||||||
|         this.parentIdentifier = parentIdentifier; |         this.parentIdentifier = parentIdentifier; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Returns the history records associated with this connection. |  | ||||||
|      * @return The history records associated with this connection. |  | ||||||
|      */ |  | ||||||
|     public List<? extends ConnectionRecord> getHistory() { |  | ||||||
|         return history; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Returns the parameter map for this connection. |      * Returns the parameter map for this connection. | ||||||
|      * @return The parameter map for this connection. |      * @return The parameter map for this connection. | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ | |||||||
|  |  | ||||||
| package org.glyptodon.guacamole.net.basic.rest.connection; | package org.glyptodon.guacamole.net.basic.rest.connection; | ||||||
|  |  | ||||||
|  | import java.util.Collections; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import org.glyptodon.guacamole.GuacamoleException; | import org.glyptodon.guacamole.GuacamoleException; | ||||||
| @@ -78,29 +79,25 @@ public class APIConnectionWrapper implements Connection { | |||||||
|     @Override |     @Override | ||||||
|     public GuacamoleConfiguration getConfiguration() { |     public GuacamoleConfiguration getConfiguration() { | ||||||
|          |          | ||||||
|         // Create the GuacamoleConfiguration from the parameter map |         // Create the GuacamoleConfiguration with current protocol | ||||||
|         GuacamoleConfiguration configuration = new GuacamoleConfiguration(); |         GuacamoleConfiguration configuration = new GuacamoleConfiguration(); | ||||||
|          |  | ||||||
|         Map<String, String> parameters = apiConnection.getParameters(); |  | ||||||
|          |  | ||||||
|         for(Map.Entry<String, String> entry : parameters.entrySet()) |  | ||||||
|             configuration.setParameter(entry.getKey(), entry.getValue()); |  | ||||||
|          |  | ||||||
|         configuration.setProtocol(apiConnection.getProtocol()); |         configuration.setProtocol(apiConnection.getProtocol()); | ||||||
|  |  | ||||||
|  |         // Add parameters, if available | ||||||
|  |         Map<String, String> parameters = apiConnection.getParameters(); | ||||||
|  |         if (parameters != null) | ||||||
|  |             configuration.setParameters(parameters); | ||||||
|  |          | ||||||
|         return configuration; |         return configuration; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void setConfiguration(GuacamoleConfiguration config) { |     public void setConfiguration(GuacamoleConfiguration config) { | ||||||
|          |          | ||||||
|         // Create a parameter map from the GuacamoleConfiguration |         // Set protocol and parameters | ||||||
|         Map<String, String> parameters = apiConnection.getParameters(); |  | ||||||
|         for(String key : config.getParameterNames()) |  | ||||||
|             parameters.put(key, config.getParameter(key)); |  | ||||||
|          |  | ||||||
|         // Set the protocol |  | ||||||
|         apiConnection.setProtocol(config.getProtocol()); |         apiConnection.setProtocol(config.getProtocol()); | ||||||
|  |         apiConnection.setParameters(config.getParameters()); | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -110,7 +107,7 @@ public class APIConnectionWrapper implements Connection { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<? extends ConnectionRecord> getHistory() throws GuacamoleException { |     public List<? extends ConnectionRecord> getHistory() throws GuacamoleException { | ||||||
|         return apiConnection.getHistory(); |         return Collections.EMPTY_LIST; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| } | } | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ package org.glyptodon.guacamole.net.basic.rest.connection; | |||||||
|  |  | ||||||
| import com.google.inject.Inject; | import com.google.inject.Inject; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
| import javax.ws.rs.Consumes; | import javax.ws.rs.Consumes; | ||||||
| import javax.ws.rs.DELETE; | import javax.ws.rs.DELETE; | ||||||
| import javax.ws.rs.GET; | import javax.ws.rs.GET; | ||||||
| @@ -34,16 +35,18 @@ import javax.ws.rs.PathParam; | |||||||
| import javax.ws.rs.Produces; | import javax.ws.rs.Produces; | ||||||
| import javax.ws.rs.QueryParam; | import javax.ws.rs.QueryParam; | ||||||
| import javax.ws.rs.core.MediaType; | import javax.ws.rs.core.MediaType; | ||||||
| import javax.ws.rs.core.Response.Status; |  | ||||||
| import org.glyptodon.guacamole.GuacamoleClientException; | import org.glyptodon.guacamole.GuacamoleClientException; | ||||||
| import org.glyptodon.guacamole.GuacamoleException; | import org.glyptodon.guacamole.GuacamoleException; | ||||||
|  | import org.glyptodon.guacamole.GuacamoleResourceNotFoundException; | ||||||
| import org.glyptodon.guacamole.net.auth.Connection; | import org.glyptodon.guacamole.net.auth.Connection; | ||||||
| import org.glyptodon.guacamole.net.auth.ConnectionGroup; | import org.glyptodon.guacamole.net.auth.ConnectionGroup; | ||||||
|  | import org.glyptodon.guacamole.net.auth.ConnectionRecord; | ||||||
| import org.glyptodon.guacamole.net.auth.Directory; | import org.glyptodon.guacamole.net.auth.Directory; | ||||||
| import org.glyptodon.guacamole.net.auth.UserContext; | import org.glyptodon.guacamole.net.auth.UserContext; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; | import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.HTTPException; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; | import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; | ||||||
|  | import org.glyptodon.guacamole.net.basic.rest.connectiongroup.APIConnectionGroup; | ||||||
|  | import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| @@ -52,7 +55,7 @@ import org.slf4j.LoggerFactory; | |||||||
|  *  |  *  | ||||||
|  * @author James Muehlner |  * @author James Muehlner | ||||||
|  */ |  */ | ||||||
| @Path("/connection") | @Path("/connections") | ||||||
| @Produces(MediaType.APPLICATION_JSON) | @Produces(MediaType.APPLICATION_JSON) | ||||||
| @Consumes(MediaType.APPLICATION_JSON) | @Consumes(MediaType.APPLICATION_JSON) | ||||||
| public class ConnectionRESTService { | public class ConnectionRESTService { | ||||||
| @@ -69,59 +72,20 @@ public class ConnectionRESTService { | |||||||
|     private AuthenticationService authenticationService; |     private AuthenticationService authenticationService; | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * A service for managing the REST endpoint APIConnection objects.  |      * Retrieves an individual connection. | ||||||
|      */ |  | ||||||
|     @Inject |  | ||||||
|     private ConnectionService connectionService; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Gets a list of connections with the given ConnectionGroup parentID. |  | ||||||
|      * If no parentID is provided, returns the connections from the root group. |  | ||||||
|      *  |      *  | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param authToken | ||||||
|      *                  the user performing the operation. |      *     The authentication token that is used to authenticate the user | ||||||
|      * @param parentID The ID of the ConnectionGroup the connections |      *     performing the operation. | ||||||
|      *                 belong to. If null, the root connection group will be used. |  | ||||||
|      * @return The connection list. |  | ||||||
|      * @throws GuacamoleException If a problem is encountered while listing connections. |  | ||||||
|      */ |  | ||||||
|     @GET |  | ||||||
|     @AuthProviderRESTExposure |  | ||||||
|     public List<APIConnection> getConnections(@QueryParam("token") String authToken, @QueryParam("parentID") String parentID)  |  | ||||||
|             throws GuacamoleException { |  | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |  | ||||||
|          |  | ||||||
|         // If the parent connection group is passed in, try to find it. |  | ||||||
|         ConnectionGroup parentConnectionGroup; |  | ||||||
|         if (parentID == null) |  | ||||||
|             parentConnectionGroup = userContext.getRootConnectionGroup(); |  | ||||||
|  |  | ||||||
|         else { |  | ||||||
|             ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); |  | ||||||
|             Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory(); |  | ||||||
|             parentConnectionGroup = connectionGroupDirectory.get(parentID); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (parentConnectionGroup == null) |  | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID."); |  | ||||||
|  |  | ||||||
|         Directory<String, Connection> connectionDirectory =  |  | ||||||
|                 parentConnectionGroup.getConnectionDirectory(); |  | ||||||
|  |  | ||||||
|         // Return the converted connection directory |  | ||||||
|         return connectionService.convertConnectionList(connectionDirectory); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Gets an individual connection. |  | ||||||
|      * |      * | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param connectionID | ||||||
|      *                  the user performing the operation. |      *     The identifier of the connection to retrieve. | ||||||
|      * @param connectionID The ID of the Connection.. |      * | ||||||
|      * @return The connection. |      * @return | ||||||
|      * @throws GuacamoleException If a problem is encountered while retrieving the connection. |      *     The connection having the given identifier. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while retrieving the connection. | ||||||
|      */ |      */ | ||||||
|     @GET |     @GET | ||||||
|     @Path("/{connectionID}") |     @Path("/{connectionID}") | ||||||
| @@ -139,19 +103,105 @@ public class ConnectionRESTService { | |||||||
|         // Get the connection |         // Get the connection | ||||||
|         Connection connection = connectionDirectory.get(connectionID); |         Connection connection = connectionDirectory.get(connectionID); | ||||||
|         if (connection == null) |         if (connection == null) | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID."); |             throw new GuacamoleResourceNotFoundException("No such connection: \"" + connectionID + "\""); | ||||||
|  |  | ||||||
|         return new APIConnection(connection); |         return new APIConnection(connection); | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Retrieves the parameters associated with a single connection. | ||||||
|  |      *  | ||||||
|  |      * @param authToken | ||||||
|  |      *     The authentication token that is used to authenticate the user | ||||||
|  |      *     performing the operation. | ||||||
|  |      * | ||||||
|  |      * @param connectionID | ||||||
|  |      *     The identifier of the connection. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A map of parameter name/value pairs. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while retrieving the connection parameters. | ||||||
|  |      */ | ||||||
|  |     @GET | ||||||
|  |     @Path("/{connectionID}/parameters") | ||||||
|  |     @AuthProviderRESTExposure | ||||||
|  |     public Map<String, String> getConnectionParameters(@QueryParam("token") String authToken,  | ||||||
|  |             @PathParam("connectionID") String connectionID) throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|  |  | ||||||
|  |         // Get the connection directory | ||||||
|  |         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); | ||||||
|  |         Directory<String, Connection> connectionDirectory = | ||||||
|  |                 rootGroup.getConnectionDirectory(); | ||||||
|  |  | ||||||
|  |         // Get the connection | ||||||
|  |         Connection connection = connectionDirectory.get(connectionID); | ||||||
|  |         if (connection == null) | ||||||
|  |             throw new GuacamoleResourceNotFoundException("No such connection: \"" + connectionID + "\""); | ||||||
|  |  | ||||||
|  |         // Retrieve connection configuration | ||||||
|  |         GuacamoleConfiguration config = connection.getConfiguration(); | ||||||
|  |  | ||||||
|  |         // Return parameter map | ||||||
|  |         return config.getParameters(); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Retrieves the usage history of a single connection. | ||||||
|  |      *  | ||||||
|  |      * @param authToken | ||||||
|  |      *     The authentication token that is used to authenticate the user | ||||||
|  |      *     performing the operation. | ||||||
|  |      * | ||||||
|  |      * @param connectionID | ||||||
|  |      *     The identifier of the connection. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A list of connection records, describing the start and end times of | ||||||
|  |      *     various usages of this connection. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while retrieving the connection history. | ||||||
|  |      */ | ||||||
|  |     @GET | ||||||
|  |     @Path("/{connectionID}/history") | ||||||
|  |     @AuthProviderRESTExposure | ||||||
|  |     public List<? extends ConnectionRecord> getConnectionHistory(@QueryParam("token") String authToken,  | ||||||
|  |             @PathParam("connectionID") String connectionID) throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|  |          | ||||||
|  |         // Get the connection directory | ||||||
|  |         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); | ||||||
|  |         Directory<String, Connection> connectionDirectory = | ||||||
|  |                 rootGroup.getConnectionDirectory(); | ||||||
|  |  | ||||||
|  |         // Get the connection | ||||||
|  |         Connection connection = connectionDirectory.get(connectionID); | ||||||
|  |         if (connection == null) | ||||||
|  |             throw new GuacamoleResourceNotFoundException("No such connection: \"" + connectionID + "\""); | ||||||
|  |  | ||||||
|  |         return connection.getHistory(); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Deletes an individual connection. |      * Deletes an individual connection. | ||||||
|      *  |      *  | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param authToken | ||||||
|      *                  the user performing the operation. |      *     The authentication token that is used to authenticate the user | ||||||
|      * @param connectionID The ID of the Connection to delete. |      *     performing the operation. | ||||||
|      * @throws GuacamoleException If a problem is encountered while deleting the connection. |      * | ||||||
|  |      * @param connectionID | ||||||
|  |      *     The identifier of the connection to delete. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while deleting the connection. | ||||||
|      */ |      */ | ||||||
|     @DELETE |     @DELETE | ||||||
|     @Path("/{connectionID}") |     @Path("/{connectionID}") | ||||||
| @@ -168,7 +218,7 @@ public class ConnectionRESTService { | |||||||
|  |  | ||||||
|         // Make sure the connection is there before trying to delete |         // Make sure the connection is there before trying to delete | ||||||
|         if (connectionDirectory.get(connectionID) == null) |         if (connectionDirectory.get(connectionID) == null) | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID."); |             throw new GuacamoleResourceNotFoundException("No such connection: \"" + connectionID + "\""); | ||||||
|  |  | ||||||
|         // Delete the connection |         // Delete the connection | ||||||
|         connectionDirectory.remove(connectionID); |         connectionDirectory.remove(connectionID); | ||||||
| @@ -176,47 +226,78 @@ public class ConnectionRESTService { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Creates a new connection and returns the identifier of the new connection. |      * Retrieves a single connection group from the given user context. If | ||||||
|      * If a parentID is provided, the connection will be created in the |      * the given identifier is null or the root identifier, the root connection | ||||||
|      * connection group with the parentID. Otherwise, the root connection group |      * group will be returned. | ||||||
|      * will be used. |  | ||||||
|      * |      * | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param userContext | ||||||
|      *                  the user performing the operation. |      *     The user context to retrieve the connection group from. | ||||||
|      * @param parentID The ID of the ConnectionGroup the connections |      * | ||||||
|      *                 belong to. If null, the root connection group will be used. |      * @param identifier | ||||||
|      * @param connection The connection to create. |      *     The identifier of the connection group to retrieve. | ||||||
|      * @return The identifier of the new connection. |      * | ||||||
|      * @throws GuacamoleException If a problem is encountered while creating the connection. |      * @return | ||||||
|  |      *     The connection group having the given identifier, or the root | ||||||
|  |      *     connection group if the identifier is null or the root identifier. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException  | ||||||
|  |      *     If an error occurs while retrieving the connection group, or if the | ||||||
|  |      *     connection group does not exist. | ||||||
|  |      */ | ||||||
|  |     private ConnectionGroup retrieveConnectionGroup(UserContext userContext, | ||||||
|  |             String identifier) throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); | ||||||
|  |  | ||||||
|  |         // Use root group if identifier is null (or the standard root identifier) | ||||||
|  |         if (identifier == null || identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER)) | ||||||
|  |             return rootGroup; | ||||||
|  |  | ||||||
|  |         // Pull specified connection group otherwise | ||||||
|  |         Directory<String, ConnectionGroup> directory = rootGroup.getConnectionGroupDirectory(); | ||||||
|  |         ConnectionGroup connectionGroup = directory.get(identifier); | ||||||
|  |  | ||||||
|  |         if (connectionGroup == null) | ||||||
|  |             throw new GuacamoleResourceNotFoundException("No such connection group: \"" + identifier + "\""); | ||||||
|  |  | ||||||
|  |         return connectionGroup; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new connection and returns the identifier of the new | ||||||
|  |      * connection. | ||||||
|  |      *  | ||||||
|  |      * @param authToken | ||||||
|  |      *     The authentication token that is used to authenticate the user | ||||||
|  |      *     performing the operation. | ||||||
|  |      * | ||||||
|  |      * @param connection | ||||||
|  |      *     The connection to create. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     The identifier of the new connection. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while creating the connection. | ||||||
|      */ |      */ | ||||||
|     @POST |     @POST | ||||||
|     @AuthProviderRESTExposure |     @AuthProviderRESTExposure | ||||||
|     public String createConnection(@QueryParam("token") String authToken, |     public String createConnection(@QueryParam("token") String authToken, | ||||||
|             @QueryParam("parentID") String parentID, APIConnection connection) throws GuacamoleException { |             APIConnection connection) throws GuacamoleException { | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|          |          | ||||||
|  |         // Validate that connection data was provided | ||||||
|         if (connection == null) |         if (connection == null) | ||||||
|             throw new GuacamoleClientException("A connection is required for this request."); |             throw new GuacamoleClientException("Connection JSON must be submitted when creating connections."); | ||||||
|  |  | ||||||
|         // If the parent connection group is passed in, try to find it. |         // Retrieve parent group | ||||||
|         ConnectionGroup parentConnectionGroup; |         String parentID = connection.getParentIdentifier(); | ||||||
|         if (parentID == null) |         ConnectionGroup parentConnectionGroup = retrieveConnectionGroup(userContext, parentID); | ||||||
|             parentConnectionGroup = userContext.getRootConnectionGroup(); |  | ||||||
|  |  | ||||||
|         else { |         // Add the new connection | ||||||
|             ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); |         Directory<String, Connection> connectionDirectory = parentConnectionGroup.getConnectionDirectory(); | ||||||
|             Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory(); |  | ||||||
|             parentConnectionGroup = connectionGroupDirectory.get(parentID); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (parentConnectionGroup == null) |  | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID."); |  | ||||||
|  |  | ||||||
|         Directory<String, Connection> connectionDirectory =  |  | ||||||
|                 parentConnectionGroup.getConnectionDirectory(); |  | ||||||
|  |  | ||||||
|         // Create the connection |  | ||||||
|         connectionDirectory.add(new APIConnectionWrapper(connection)); |         connectionDirectory.add(new APIConnectionWrapper(connection)); | ||||||
|  |  | ||||||
|         // Return the new connection identifier |         // Return the new connection identifier | ||||||
| @@ -225,15 +306,24 @@ public class ConnectionRESTService { | |||||||
|     } |     } | ||||||
|    |    | ||||||
|     /** |     /** | ||||||
|      * Updates a connection. |      * Updates an existing connection. If the parent identifier of the | ||||||
|  |      * connection is changed, the connection will also be moved to the new | ||||||
|  |      * parent group. | ||||||
|      *  |      *  | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param authToken | ||||||
|      *                  the user performing the operation. |      *     The authentication token that is used to authenticate the user | ||||||
|      * @param connectionID The ID of the Connection to move. |      *     performing the operation. | ||||||
|      * @param connection The connection to update. |      * | ||||||
|      * @throws GuacamoleException If a problem is encountered while updating the connection. |      * @param connectionID | ||||||
|  |      *     The identifier of the connection to update. | ||||||
|  |      * | ||||||
|  |      * @param connection | ||||||
|  |      *     The connection data to update the specified connection with. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while updating the connection. | ||||||
|      */ |      */ | ||||||
|     @POST |     @PUT | ||||||
|     @Path("/{connectionID}") |     @Path("/{connectionID}") | ||||||
|     @AuthProviderRESTExposure |     @AuthProviderRESTExposure | ||||||
|     public void updateConnection(@QueryParam("token") String authToken,  |     public void updateConnection(@QueryParam("token") String authToken,  | ||||||
| @@ -241,62 +331,30 @@ public class ConnectionRESTService { | |||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|          |          | ||||||
|  |         // Validate that connection data was provided | ||||||
|         if (connection == null) |         if (connection == null) | ||||||
|             throw new GuacamoleClientException("A connection is required for this request."); |             throw new GuacamoleClientException("Connection JSON must be submitted when updating connections."); | ||||||
|  |  | ||||||
|         // Get the connection directory |         // Get the connection directory | ||||||
|         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); |         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); | ||||||
|         Directory<String, Connection> connectionDirectory = |         Directory<String, Connection> connectionDirectory = | ||||||
|                 rootGroup.getConnectionDirectory(); |                 rootGroup.getConnectionDirectory(); | ||||||
|          |          | ||||||
|         Connection connectionFromAuthProvider = connectionDirectory.get(connectionID); |  | ||||||
|  |  | ||||||
|         // Make sure the connection is there before trying to update |         // Make sure the connection is there before trying to update | ||||||
|         if (connectionFromAuthProvider == null) |         Connection existingConnection = connectionDirectory.get(connectionID); | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID."); |         if (existingConnection == null) | ||||||
|  |             throw new GuacamoleResourceNotFoundException("No such connection: \"" + connectionID + "\""); | ||||||
|          |          | ||||||
|         // Copy the information from this connection over to an object from the Auth Provider |         // Retrieve connection configuration | ||||||
|         APIConnectionWrapper wrappedConnection = new APIConnectionWrapper(connection); |         GuacamoleConfiguration config = new GuacamoleConfiguration(); | ||||||
|         connectionFromAuthProvider.setConfiguration(wrappedConnection.getConfiguration()); |         config.setProtocol(connection.getProtocol()); | ||||||
|         connectionFromAuthProvider.setName(wrappedConnection.getName()); |         config.setParameters(connection.getParameters()); | ||||||
|  |  | ||||||
|         // Update the connection |         // Update the connection | ||||||
|         connectionDirectory.update(connectionFromAuthProvider); |         existingConnection.setConfiguration(config); | ||||||
|  |         existingConnection.setName(connection.getName()); | ||||||
|  |         connectionDirectory.update(existingConnection); | ||||||
|  |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     /** |  | ||||||
|      * Moves an individual connection to a different connection group. |  | ||||||
|      *  |  | ||||||
|      * @param authToken The authentication token that is used to authenticate |  | ||||||
|      *                  the user performing the operation. |  | ||||||
|      * @param connectionID The ID of the Connection to move. |  | ||||||
|      * @param parentID The ID of the ConnectionGroup the connection is to be moved to. |  | ||||||
|      * @throws GuacamoleException If a problem is encountered while moving the connection. |  | ||||||
|      */ |  | ||||||
|     @PUT |  | ||||||
|     @Path("/{connectionID}") |  | ||||||
|     @AuthProviderRESTExposure |  | ||||||
|     public void moveConnection(@QueryParam("token") String authToken,  |  | ||||||
|             @PathParam("connectionID") String connectionID, @QueryParam("parentID") String parentID)  |  | ||||||
|             throws GuacamoleException { |  | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |  | ||||||
|  |  | ||||||
|         // Get the connection directory |  | ||||||
|         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); |  | ||||||
|         Directory<String, Connection> connectionDirectory = |  | ||||||
|                 rootGroup.getConnectionDirectory(); |  | ||||||
|  |  | ||||||
|         // Find the new parent connection group |  | ||||||
|         Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory(); |  | ||||||
|         ConnectionGroup parentConnectionGroup = connectionGroupDirectory.get(parentID); |  | ||||||
|  |  | ||||||
|         if (parentConnectionGroup == null) |  | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID."); |  | ||||||
|  |  | ||||||
|         // Move the connection |  | ||||||
|         connectionDirectory.move(connectionID, parentConnectionGroup.getConnectionDirectory()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,59 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| package org.glyptodon.guacamole.net.basic.rest.connection; |  | ||||||
|  |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.List; |  | ||||||
| import org.glyptodon.guacamole.GuacamoleException; |  | ||||||
| import org.glyptodon.guacamole.net.auth.Connection; |  | ||||||
| import org.glyptodon.guacamole.net.auth.Directory; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * A service for performing useful manipulations on REST Connections. |  | ||||||
|  *  |  | ||||||
|  * @author James Muehlner |  | ||||||
|  */ |  | ||||||
| public class ConnectionService { |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Converts a Connection Directory to a list of APIConnection objects for  |  | ||||||
|      * exposing with the REST endpoints. |  | ||||||
|      *  |  | ||||||
|      * @param connectionDirectory The Connection Directory to convert for REST endpoint use. |  | ||||||
|      * @return A List of APIConnection objects for use with the REST endpoint. |  | ||||||
|      * @throws GuacamoleException If an error occurs while converting the  |  | ||||||
|      *                            connection directory. |  | ||||||
|      */ |  | ||||||
|     public List<APIConnection> convertConnectionList(Directory<String, Connection> connectionDirectory)  |  | ||||||
|             throws GuacamoleException { |  | ||||||
|  |  | ||||||
|         List<APIConnection> restConnections = new ArrayList<APIConnection>(); |  | ||||||
|          |  | ||||||
|         for (String connectionID : connectionDirectory.getIdentifiers()) |  | ||||||
|             restConnections.add(new APIConnection(connectionDirectory.get(connectionID))); |  | ||||||
|              |  | ||||||
|         return restConnections; |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -22,10 +22,11 @@ | |||||||
|  |  | ||||||
| package org.glyptodon.guacamole.net.basic.rest.connectiongroup; | package org.glyptodon.guacamole.net.basic.rest.connectiongroup; | ||||||
|  |  | ||||||
|  | import java.util.Collection; | ||||||
| import org.codehaus.jackson.annotate.JsonIgnoreProperties; | import org.codehaus.jackson.annotate.JsonIgnoreProperties; | ||||||
| import org.glyptodon.guacamole.net.auth.ConnectionGroup; | import org.glyptodon.guacamole.net.auth.ConnectionGroup; | ||||||
| import org.glyptodon.guacamole.net.auth.ConnectionGroup.Type; | import org.glyptodon.guacamole.net.auth.ConnectionGroup.Type; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.APIConstants; | import org.glyptodon.guacamole.net.basic.rest.connection.APIConnection; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * A simple connection group to expose through the REST endpoints. |  * A simple connection group to expose through the REST endpoints. | ||||||
| @@ -35,6 +36,11 @@ import org.glyptodon.guacamole.net.basic.rest.APIConstants; | |||||||
| @JsonIgnoreProperties(ignoreUnknown = true) | @JsonIgnoreProperties(ignoreUnknown = true) | ||||||
| public class APIConnectionGroup { | public class APIConnectionGroup { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The identifier of the root connection group. | ||||||
|  |      */ | ||||||
|  |     public static final String ROOT_IDENTIFIER = "ROOT"; | ||||||
|  |   | ||||||
|     /** |     /** | ||||||
|      * The name of this connection group. |      * The name of this connection group. | ||||||
|      */ |      */ | ||||||
| @@ -55,6 +61,18 @@ public class APIConnectionGroup { | |||||||
|      */ |      */ | ||||||
|     private Type type; |     private Type type; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * All child connection groups. If children are not being queried, this may | ||||||
|  |      * be omitted. | ||||||
|  |      */ | ||||||
|  |     private Collection<APIConnectionGroup> childConnectionGroups; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * All child connections. If children are not being queried, this may be | ||||||
|  |      * omitted. | ||||||
|  |      */ | ||||||
|  |     private Collection<APIConnection> childConnections; | ||||||
|  |      | ||||||
|     /** |     /** | ||||||
|      * Create an empty APIConnectionGroup. |      * Create an empty APIConnectionGroup. | ||||||
|      */ |      */ | ||||||
| @@ -73,7 +91,7 @@ public class APIConnectionGroup { | |||||||
|          |          | ||||||
|         // Use the explicit ROOT group ID |         // Use the explicit ROOT group ID | ||||||
|         if (this.parentIdentifier == null) |         if (this.parentIdentifier == null) | ||||||
|             this.parentIdentifier = APIConstants.ROOT_CONNECTION_GROUP_IDENTIFIER; |             this.parentIdentifier = ROOT_IDENTIFIER; | ||||||
|          |          | ||||||
|         this.name = connectionGroup.getName(); |         this.name = connectionGroup.getName(); | ||||||
|         this.type = connectionGroup.getType(); |         this.type = connectionGroup.getType(); | ||||||
| @@ -144,4 +162,52 @@ public class APIConnectionGroup { | |||||||
|         this.type = type; |         this.type = type; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns a collection of all child connection groups, or null if children | ||||||
|  |      * have not been queried. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A collection of all child connection groups, or null if children | ||||||
|  |      *     have not been queried. | ||||||
|  |      */ | ||||||
|  |     public Collection<APIConnectionGroup> getChildConnectionGroups() { | ||||||
|  |         return childConnectionGroups; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the collection of all child connection groups to the given | ||||||
|  |      * collection, which may be null if children have not been queried. | ||||||
|  |      * | ||||||
|  |      * @param childConnectionGroups | ||||||
|  |      *     The collection containing all child connection groups of this | ||||||
|  |      *     connection group, or null if children have not been queried. | ||||||
|  |      */ | ||||||
|  |     public void setChildConnectionGroups(Collection<APIConnectionGroup> childConnectionGroups) { | ||||||
|  |         this.childConnectionGroups = childConnectionGroups; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns a collection of all child connections, or null if children have | ||||||
|  |      * not been queried. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A collection of all child connections, or null if children have not | ||||||
|  |      *     been queried. | ||||||
|  |      */ | ||||||
|  |     public Collection<APIConnection> getChildConnections() { | ||||||
|  |         return childConnections; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the collection of all child connections to the given collection, | ||||||
|  |      * which may be null if children have not been queried. | ||||||
|  |      * | ||||||
|  |      * @param childConnections | ||||||
|  |      *     The collection containing all child connections of this connection | ||||||
|  |      *     group, or null if children have not been queried. | ||||||
|  |      */ | ||||||
|  |     public void setChildConnections(Collection<APIConnection> childConnections) { | ||||||
|  |         this.childConnections = childConnections; | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -23,7 +23,8 @@ | |||||||
| package org.glyptodon.guacamole.net.basic.rest.connectiongroup; | package org.glyptodon.guacamole.net.basic.rest.connectiongroup; | ||||||
|  |  | ||||||
| import com.google.inject.Inject; | import com.google.inject.Inject; | ||||||
| import java.util.List; | import java.util.ArrayList; | ||||||
|  | import java.util.Collection; | ||||||
| import javax.ws.rs.Consumes; | import javax.ws.rs.Consumes; | ||||||
| import javax.ws.rs.DELETE; | import javax.ws.rs.DELETE; | ||||||
| import javax.ws.rs.GET; | import javax.ws.rs.GET; | ||||||
| @@ -34,15 +35,19 @@ import javax.ws.rs.PathParam; | |||||||
| import javax.ws.rs.Produces; | import javax.ws.rs.Produces; | ||||||
| import javax.ws.rs.QueryParam; | import javax.ws.rs.QueryParam; | ||||||
| import javax.ws.rs.core.MediaType; | import javax.ws.rs.core.MediaType; | ||||||
| import javax.ws.rs.core.Response.Status; |  | ||||||
| import org.glyptodon.guacamole.GuacamoleClientException; | import org.glyptodon.guacamole.GuacamoleClientException; | ||||||
| import org.glyptodon.guacamole.GuacamoleException; | import org.glyptodon.guacamole.GuacamoleException; | ||||||
|  | import org.glyptodon.guacamole.GuacamoleResourceNotFoundException; | ||||||
|  | import org.glyptodon.guacamole.net.auth.Connection; | ||||||
| import org.glyptodon.guacamole.net.auth.ConnectionGroup; | import org.glyptodon.guacamole.net.auth.ConnectionGroup; | ||||||
| import org.glyptodon.guacamole.net.auth.Directory; | import org.glyptodon.guacamole.net.auth.Directory; | ||||||
|  | import org.glyptodon.guacamole.net.auth.User; | ||||||
| import org.glyptodon.guacamole.net.auth.UserContext; | import org.glyptodon.guacamole.net.auth.UserContext; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; | import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.HTTPException; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; | import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; | ||||||
|  | import org.glyptodon.guacamole.net.basic.rest.connection.APIConnection; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| @@ -51,7 +56,7 @@ import org.slf4j.LoggerFactory; | |||||||
|  *  |  *  | ||||||
|  * @author James Muehlner |  * @author James Muehlner | ||||||
|  */ |  */ | ||||||
| @Path("/connectionGroup") | @Path("/connectionGroups") | ||||||
| @Produces(MediaType.APPLICATION_JSON) | @Produces(MediaType.APPLICATION_JSON) | ||||||
| @Consumes(MediaType.APPLICATION_JSON) | @Consumes(MediaType.APPLICATION_JSON) | ||||||
| public class ConnectionGroupRESTService { | public class ConnectionGroupRESTService { | ||||||
| @@ -68,63 +73,124 @@ public class ConnectionGroupRESTService { | |||||||
|     private AuthenticationService authenticationService; |     private AuthenticationService authenticationService; | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * A service for managing the REST endpoint APIConnection objects.  |      * Retrieves the given connection group from the user context, including | ||||||
|      */ |      * all descendant connections and groups if requested. | ||||||
|     @Inject |  | ||||||
|     private ConnectionGroupService connectionGroupService; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * The ID that will be guaranteed to refer to the root connection group. |  | ||||||
|      */ |  | ||||||
|     private static final String ROOT_CONNECTION_GROUP_ID = "ROOT"; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Gets a list of connection groups with the given ConnectionGroup parentID. |  | ||||||
|      * If no parentID is provided, returns the connection groups from the root group. |  | ||||||
|      * |      * | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param userContext | ||||||
|      *                  the user performing the operation. |      *     The user context from which to retrieve the connection group. | ||||||
|      * @param parentID The ID of the ConnectionGroup the connection groups |      * | ||||||
|      *                 belong to. If null, the root connection group will be used. |      * @param identifier | ||||||
|      * @return The connection list. |      *     The unique identifier of the connection group to retrieve. | ||||||
|      * @throws GuacamoleException If a problem is encountered while listing connection groups. |      * | ||||||
|  |      * @param includeDescendants | ||||||
|  |      *     Whether the descendant connections and groups of the given | ||||||
|  |      *     connection group should also be retrieved. | ||||||
|  |      *  | ||||||
|  |      * @param permission | ||||||
|  |      *     The permission the current user must have for a connection or | ||||||
|  |      *     connection group to be returned in the results, if any. If null | ||||||
|  |      *     is specified, no filtering by permission will be performed. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     The requested connection group, or null if no such connection group | ||||||
|  |      *     exists. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException  | ||||||
|  |      *     If an error occurs while retrieving the requested connection group | ||||||
|  |      *     or any of its descendants. | ||||||
|      */ |      */ | ||||||
|     @GET |     private APIConnectionGroup retrieveConnectionGroup(UserContext userContext, | ||||||
|     @AuthProviderRESTExposure |             String identifier, boolean includeDescendants, ObjectPermission.Type permission) | ||||||
|     public List<APIConnectionGroup> getConnectionGroups(@QueryParam("token") String authToken, @QueryParam("parentID") String parentID)  |  | ||||||
|             throws GuacamoleException { |             throws GuacamoleException { | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |         User self = userContext.self(); | ||||||
|          |  | ||||||
|         // If the parent connection group is passed in, try to find it. |  | ||||||
|         ConnectionGroup parentConnectionGroup; |  | ||||||
|         if (parentID == null) |  | ||||||
|             parentConnectionGroup = userContext.getRootConnectionGroup(); |  | ||||||
|  |  | ||||||
|         else { |  | ||||||
|         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); |         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); | ||||||
|             Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory(); |  | ||||||
|             parentConnectionGroup = connectionGroupDirectory.get(parentID); |  | ||||||
|         } |  | ||||||
|          |          | ||||||
|         if (parentConnectionGroup == null) |         ConnectionGroup connectionGroup; | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No connection group found with the provided parentID."); |          | ||||||
|  |         // Use root group if requested | ||||||
|  |         if (identifier == null || identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER)) | ||||||
|  |             connectionGroup = rootGroup; | ||||||
|  |  | ||||||
|  |         // Otherwise, query requested group using root group directory | ||||||
|  |         else { | ||||||
|  |  | ||||||
|             Directory<String, ConnectionGroup> connectionGroupDirectory = |             Directory<String, ConnectionGroup> connectionGroupDirectory = | ||||||
|                 parentConnectionGroup.getConnectionGroupDirectory(); |                     rootGroup.getConnectionGroupDirectory(); | ||||||
|  |  | ||||||
|  |             // Get the connection group from root directory | ||||||
|  |             connectionGroup = connectionGroupDirectory.get(identifier); | ||||||
|  |             if (connectionGroup == null) | ||||||
|  |                 return null; | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Wrap queried connection group | ||||||
|  |         APIConnectionGroup apiConnectionGroup = new APIConnectionGroup(connectionGroup); | ||||||
|  |  | ||||||
|  |         // Recursively query all descendants if necessary | ||||||
|  |         if (includeDescendants) { | ||||||
|  |  | ||||||
|  |             // Query all child connections | ||||||
|  |             Collection<APIConnection> apiConnections = new ArrayList<APIConnection>(); | ||||||
|  |             Directory<String, Connection> connectionDirectory = connectionGroup.getConnectionDirectory(); | ||||||
|  |  | ||||||
|  |             for (String childIdentifier : connectionDirectory.getIdentifiers()) { | ||||||
|  |  | ||||||
|  |                 // Pull current connection - silently ignore if connection was removed prior to read | ||||||
|  |                 Connection childConnection = connectionDirectory.get(childIdentifier); | ||||||
|  |                 if (childConnection == null) | ||||||
|  |                     continue; | ||||||
|  |  | ||||||
|  |                 // Filter based on permission, if requested | ||||||
|  |                 if (permission == null || self.hasPermission(new ConnectionPermission(permission, childIdentifier))) | ||||||
|  |                     apiConnections.add(new APIConnection(childConnection)); | ||||||
|  |  | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             // Associate child connections with current connection group | ||||||
|  |             apiConnectionGroup.setChildConnections(apiConnections); | ||||||
|  |  | ||||||
|  |             // Query all child connection groups | ||||||
|  |             Collection<APIConnectionGroup> apiConnectionGroups = new ArrayList<APIConnectionGroup>(); | ||||||
|  |             Directory<String, ConnectionGroup> groupDirectory = connectionGroup.getConnectionGroupDirectory(); | ||||||
|  |  | ||||||
|  |             for (String childIdentifier : groupDirectory.getIdentifiers()) { | ||||||
|  |  | ||||||
|  |                 // Pull current connection group - silently ignore if connection group was removed prior to read | ||||||
|  |                 APIConnectionGroup childConnectionGroup = retrieveConnectionGroup(userContext, childIdentifier, true, permission); | ||||||
|  |                 if (childConnectionGroup == null) | ||||||
|  |                     continue; | ||||||
|  |  | ||||||
|  |                 apiConnectionGroups.add(childConnectionGroup); | ||||||
|  |  | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             // Associate child groups with current connection group | ||||||
|  |             apiConnectionGroup.setChildConnectionGroups(apiConnectionGroups); | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Return the connectiion group | ||||||
|  |         return apiConnectionGroup; | ||||||
|  |  | ||||||
|         // Return the converted connection group list |  | ||||||
|         return connectionGroupService.convertConnectionGroupList(connectionGroupDirectory); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Gets an individual connection group. |      * Gets an individual connection group. | ||||||
|      *  |      *  | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param authToken | ||||||
|      *                  the user performing the operation. |      *     The authentication token that is used to authenticate the user | ||||||
|      * @param connectionGroupID The ID of the ConnectionGroup. |      *     performing the operation. | ||||||
|      * @return The connection group. |      *  | ||||||
|      * @throws GuacamoleException If a problem is encountered while retrieving the connection group. |      * @param connectionGroupID | ||||||
|  |      *     The ID of the connection group to retrieve. | ||||||
|  |      *  | ||||||
|  |      * @return | ||||||
|  |      *     The connection group, without any descendants. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If a problem is encountered while retrieving the connection group. | ||||||
|      */ |      */ | ||||||
|     @GET |     @GET | ||||||
|     @Path("/{connectionGroupID}") |     @Path("/{connectionGroupID}") | ||||||
| @@ -134,33 +200,69 @@ public class ConnectionGroupRESTService { | |||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|  |  | ||||||
|         // Get the connection group directory |         // Retrieve requested connection group only | ||||||
|         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); |         APIConnectionGroup connectionGroup = retrieveConnectionGroup(userContext, connectionGroupID, false, null); | ||||||
|          |  | ||||||
|         // Return the root group if it was asked for |  | ||||||
|         if (connectionGroupID != null && connectionGroupID.equals(ROOT_CONNECTION_GROUP_ID)) |  | ||||||
|             return new APIConnectionGroup(rootGroup); |  | ||||||
|          |  | ||||||
|         Directory<String, ConnectionGroup> connectionGroupDirectory = |  | ||||||
|                 rootGroup.getConnectionGroupDirectory(); |  | ||||||
|  |  | ||||||
|         // Get the connection group |  | ||||||
|         ConnectionGroup connectionGroup = connectionGroupDirectory.get(connectionGroupID); |  | ||||||
|         if (connectionGroup == null) |         if (connectionGroup == null) | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided ID."); |             throw new GuacamoleResourceNotFoundException("No such connection group: \"" + connectionGroupID + "\""); | ||||||
|  |  | ||||||
|         // Return the connectiion group |         return connectionGroup; | ||||||
|         return new APIConnectionGroup(connectionGroup); |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets an individual connection group and all children. | ||||||
|  |      *  | ||||||
|  |      * @param authToken | ||||||
|  |      *     The authentication token that is used to authenticate the user | ||||||
|  |      *     performing the operation. | ||||||
|  |      * | ||||||
|  |      * @param connectionGroupID | ||||||
|  |      *     The ID of the connection group to retrieve. | ||||||
|  |      * | ||||||
|  |      * @param permission | ||||||
|  |      *     If specified, limit the returned list to only those connections for | ||||||
|  |      *     which the current user has the given permission. Otherwise, all | ||||||
|  |      *     visible connections are returned. Connection groups are unaffected | ||||||
|  |      *     by this parameter. | ||||||
|  |      *  | ||||||
|  |      * @return | ||||||
|  |      *     The requested connection group, including all descendants. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If a problem is encountered while retrieving the connection group or | ||||||
|  |      *     its descendants. | ||||||
|  |      */ | ||||||
|  |     @GET | ||||||
|  |     @Path("/{connectionGroupID}/tree") | ||||||
|  |     @AuthProviderRESTExposure | ||||||
|  |     public APIConnectionGroup getConnectionGroupTree(@QueryParam("token") String authToken,  | ||||||
|  |             @PathParam("connectionGroupID") String connectionGroupID, | ||||||
|  |             @QueryParam("permission") ObjectPermission.Type permission) | ||||||
|  |             throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|  |  | ||||||
|  |         // Retrieve requested connection group and all descendants | ||||||
|  |         APIConnectionGroup connectionGroup = retrieveConnectionGroup(userContext, connectionGroupID, true, permission); | ||||||
|  |         if (connectionGroup == null) | ||||||
|  |             throw new GuacamoleResourceNotFoundException("No such connection group: \"" + connectionGroupID + "\""); | ||||||
|  |  | ||||||
|  |         return connectionGroup; | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Deletes an individual connection group. |      * Deletes an individual connection group. | ||||||
|      *  |      *  | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param authToken | ||||||
|      *                  the user performing the operation. |      *     The authentication token that is used to authenticate the user | ||||||
|      * @param connectionGroupID The ID of the ConnectionGroup to delete. |      *     performing the operation. | ||||||
|      * @throws GuacamoleException If a problem is encountered while deleting the connection group. |      * | ||||||
|  |      * @param connectionGroupID | ||||||
|  |      *     The identifier of the connection group to delete. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while deleting the connection group. | ||||||
|      */ |      */ | ||||||
|     @DELETE |     @DELETE | ||||||
|     @Path("/{connectionGroupID}") |     @Path("/{connectionGroupID}") | ||||||
| @@ -174,7 +276,7 @@ public class ConnectionGroupRESTService { | |||||||
|         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); |         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); | ||||||
|          |          | ||||||
|         // Use the root group if it was asked for |         // Use the root group if it was asked for | ||||||
|         if (connectionGroupID != null && connectionGroupID.equals(ROOT_CONNECTION_GROUP_ID)) |         if (connectionGroupID != null && connectionGroupID.equals(APIConnectionGroup.ROOT_IDENTIFIER)) | ||||||
|             connectionGroupID = rootGroup.getIdentifier(); |             connectionGroupID = rootGroup.getIdentifier(); | ||||||
|          |          | ||||||
|         Directory<String, ConnectionGroup> connectionGroupDirectory = |         Directory<String, ConnectionGroup> connectionGroupDirectory = | ||||||
| @@ -182,7 +284,7 @@ public class ConnectionGroupRESTService { | |||||||
|  |  | ||||||
|         // Make sure the connection is there before trying to delete |         // Make sure the connection is there before trying to delete | ||||||
|         if (connectionGroupDirectory.get(connectionGroupID) == null) |         if (connectionGroupDirectory.get(connectionGroupID) == null) | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided ID."); |             throw new GuacamoleResourceNotFoundException("No such connection group: \"" + connectionGroupID + "\""); | ||||||
|  |  | ||||||
|         // Delete the connection group |         // Delete the connection group | ||||||
|         connectionGroupDirectory.remove(connectionGroupID); |         connectionGroupDirectory.remove(connectionGroupID); | ||||||
| @@ -195,42 +297,49 @@ public class ConnectionGroupRESTService { | |||||||
|      * connection group with the parentID. Otherwise, the root connection group |      * connection group with the parentID. Otherwise, the root connection group | ||||||
|      * will be used. |      * will be used. | ||||||
|      *  |      *  | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param authToken | ||||||
|      *                  the user performing the operation. |      *     The authentication token that is used to authenticate the user | ||||||
|      * @param parentID The ID of the ConnectionGroup the connection groups |      *     performing the operation. | ||||||
|      *                 belong to. If null, the root connection group will be used. |      * | ||||||
|      * @param connectionGroup The connection group to create. |      * @param connectionGroup | ||||||
|      * @return The identifier of the new connection group. |      *     The connection group to create. | ||||||
|      * @throws GuacamoleException If a problem is encountered while creating the connection group. |      *  | ||||||
|  |      * @return | ||||||
|  |      *     The identifier of the new connection group. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while creating the connection group. | ||||||
|      */ |      */ | ||||||
|     @POST |     @POST | ||||||
|     @AuthProviderRESTExposure |     @AuthProviderRESTExposure | ||||||
|     public String createConnectionGroup(@QueryParam("token") String authToken, |     public String createConnectionGroup(@QueryParam("token") String authToken, | ||||||
|             @QueryParam("parentID") String parentID, APIConnectionGroup connectionGroup) throws GuacamoleException { |             APIConnectionGroup connectionGroup) throws GuacamoleException { | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|  |  | ||||||
|  |         // Validate that connection group data was provided | ||||||
|         if (connectionGroup == null) |         if (connectionGroup == null) | ||||||
|             throw new GuacamoleClientException("A connection group is required for this request."); |             throw new GuacamoleClientException("Connection group JSON must be submitted when creating connections groups."); | ||||||
|  |  | ||||||
|         // If the parent connection group is passed in, try to find it. |         String parentID = connectionGroup.getParentIdentifier(); | ||||||
|  |         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); | ||||||
|  |  | ||||||
|  |         // Use root group if no parent is specified | ||||||
|         ConnectionGroup parentConnectionGroup; |         ConnectionGroup parentConnectionGroup; | ||||||
|         if (parentID == null) |         if (parentID == null) | ||||||
|             parentConnectionGroup = userContext.getRootConnectionGroup(); |             parentConnectionGroup = rootGroup; | ||||||
|  |  | ||||||
|  |         // Pull specified connection group otherwise | ||||||
|         else { |         else { | ||||||
|             ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); |  | ||||||
|             Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory(); |             Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory(); | ||||||
|             parentConnectionGroup = connectionGroupDirectory.get(parentID); |             parentConnectionGroup = connectionGroupDirectory.get(parentID); | ||||||
|         } |  | ||||||
|  |  | ||||||
|             if (parentConnectionGroup == null) |             if (parentConnectionGroup == null) | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID."); |                 throw new GuacamoleResourceNotFoundException("No such connection group: \"" + parentID + "\""); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         Directory<String, ConnectionGroup> connectionGroupDirectory =  |         // Add the new connection group | ||||||
|                 parentConnectionGroup.getConnectionGroupDirectory(); |         Directory<String, ConnectionGroup> connectionGroupDirectory = parentConnectionGroup.getConnectionGroupDirectory(); | ||||||
|  |  | ||||||
|         // Create the connection group |  | ||||||
|         connectionGroupDirectory.add(new APIConnectionGroupWrapper(connectionGroup)); |         connectionGroupDirectory.add(new APIConnectionGroupWrapper(connectionGroup)); | ||||||
|  |  | ||||||
|         // Return the new connection group identifier |         // Return the new connection group identifier | ||||||
| @@ -239,15 +348,24 @@ public class ConnectionGroupRESTService { | |||||||
|     } |     } | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * Updates a connection group. |      * Updates a connection group. If the parent identifier of the | ||||||
|  |      * connection group is changed, the connection group will also be moved to | ||||||
|  |      * the new parent group. | ||||||
|      *  |      *  | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param authToken | ||||||
|      *                  the user performing the operation. |      *     The authentication token that is used to authenticate the user | ||||||
|      * @param connectionGroupID The ID of the ConnectionGroup to update. |      *     performing the operation. | ||||||
|      * @param connectionGroup The connection group to update. |      * | ||||||
|      * @throws GuacamoleException If a problem is encountered while updating the connection group. |      * @param connectionGroupID | ||||||
|  |      *     The identifier of the existing connection group to update. | ||||||
|  |      * | ||||||
|  |      * @param connectionGroup | ||||||
|  |      *     The data to update the existing connection group with. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while updating the connection group. | ||||||
|      */ |      */ | ||||||
|     @POST |     @PUT | ||||||
|     @Path("/{connectionGroupID}") |     @Path("/{connectionGroupID}") | ||||||
|     @AuthProviderRESTExposure |     @AuthProviderRESTExposure | ||||||
|     public void updateConnectionGroup(@QueryParam("token") String authToken,  |     public void updateConnectionGroup(@QueryParam("token") String authToken,  | ||||||
| @@ -256,14 +374,15 @@ public class ConnectionGroupRESTService { | |||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|          |          | ||||||
|  |         // Validate that connection group data was provided | ||||||
|         if (connectionGroup == null) |         if (connectionGroup == null) | ||||||
|             throw new GuacamoleClientException("A connection group is required for this request."); |             throw new GuacamoleClientException("Connection group JSON must be submitted when updating connection groups."); | ||||||
|  |  | ||||||
|         // Get the connection directory |         // Get the connection directory | ||||||
|         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); |         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); | ||||||
|          |          | ||||||
|         // Use the root group if it was asked for |         // Use the root group if it was asked for | ||||||
|         if (connectionGroupID != null && connectionGroupID.equals(ROOT_CONNECTION_GROUP_ID)) |         if (connectionGroupID != null && connectionGroupID.equals(APIConnectionGroup.ROOT_IDENTIFIER)) | ||||||
|             connectionGroupID = rootGroup.getIdentifier(); |             connectionGroupID = rootGroup.getIdentifier(); | ||||||
|          |          | ||||||
|         Directory<String, ConnectionGroup> connectionGroupDirectory = |         Directory<String, ConnectionGroup> connectionGroupDirectory = | ||||||
| @@ -271,51 +390,11 @@ public class ConnectionGroupRESTService { | |||||||
|  |  | ||||||
|         // Make sure the connection group is there before trying to update |         // Make sure the connection group is there before trying to update | ||||||
|         if (connectionGroupDirectory.get(connectionGroupID) == null) |         if (connectionGroupDirectory.get(connectionGroupID) == null) | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided ID."); |             throw new GuacamoleResourceNotFoundException("No such connection group: \"" + connectionGroupID + "\""); | ||||||
|  |  | ||||||
|         // Update the connection group |         // Update the connection group | ||||||
|         connectionGroupDirectory.update(new APIConnectionGroupWrapper(connectionGroup)); |         connectionGroupDirectory.update(new APIConnectionGroupWrapper(connectionGroup)); | ||||||
|  |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     /** |  | ||||||
|      * Moves an individual connection group to a different connection group. |  | ||||||
|      *  |  | ||||||
|      * @param authToken The authentication token that is used to authenticate |  | ||||||
|      *                  the user performing the operation. |  | ||||||
|      * @param connectionGroupID The ID of the ConnectionGroup to move. |  | ||||||
|      * @param parentID The ID of the ConnectionGroup the connection group is to be moved to. |  | ||||||
|      * @throws GuacamoleException If a problem is encountered while moving the connection group. |  | ||||||
|      */ |  | ||||||
|     @PUT |  | ||||||
|     @Path("/{connectionGroupID}") |  | ||||||
|     @AuthProviderRESTExposure |  | ||||||
|     public void moveConnectionGroup(@QueryParam("token") String authToken,  |  | ||||||
|             @PathParam("connectionGroupID") String connectionGroupID,  |  | ||||||
|             @QueryParam("parentID") String parentID) throws GuacamoleException { |  | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |  | ||||||
|          |  | ||||||
|         // Get the connection group directory |  | ||||||
|         ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); |  | ||||||
|          |  | ||||||
|         // Use the root group if it was asked for |  | ||||||
|         if (connectionGroupID != null && connectionGroupID.equals(ROOT_CONNECTION_GROUP_ID)) |  | ||||||
|             connectionGroupID = rootGroup.getIdentifier(); |  | ||||||
|          |  | ||||||
|         Directory<String, ConnectionGroup> connectionGroupDirectory = |  | ||||||
|                 rootGroup.getConnectionGroupDirectory(); |  | ||||||
|  |  | ||||||
|         // Find the new parent connection group |  | ||||||
|         Directory<String, ConnectionGroup> newConnectionGroupDirectory = rootGroup.getConnectionGroupDirectory(); |  | ||||||
|         ConnectionGroup parentConnectionGroup = newConnectionGroupDirectory.get(parentID); |  | ||||||
|  |  | ||||||
|         if (parentConnectionGroup == null) |  | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID."); |  | ||||||
|  |  | ||||||
|         // Move the connection group |  | ||||||
|         connectionGroupDirectory.move(connectionGroupID, parentConnectionGroup.getConnectionGroupDirectory()); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,59 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| package org.glyptodon.guacamole.net.basic.rest.connectiongroup; |  | ||||||
|  |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.List; |  | ||||||
| import org.glyptodon.guacamole.GuacamoleException; |  | ||||||
| import org.glyptodon.guacamole.net.auth.ConnectionGroup; |  | ||||||
| import org.glyptodon.guacamole.net.auth.Directory; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * A service for performing useful manipulations on REST ConnectionGroups. |  | ||||||
|  *  |  | ||||||
|  * @author James Muehlner |  | ||||||
|  */ |  | ||||||
| public class ConnectionGroupService { |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Converts a ConnectionGroup directory to a list of APIConnectionGroup |  | ||||||
|      * objects for exposing with the REST endpoints. |  | ||||||
|      *  |  | ||||||
|      * @param connectionGroupDirectory The ConnectionGroup Directory to convert for REST endpoint use. |  | ||||||
|      * @return A List of APIConnectionGroup objects for use with the REST endpoint. |  | ||||||
|      * @throws GuacamoleException If an error occurs while converting the  |  | ||||||
|      *                            connection group directory. |  | ||||||
|      */ |  | ||||||
|     public List<APIConnectionGroup> convertConnectionGroupList( |  | ||||||
|             Directory<String, ConnectionGroup> connectionGroupDirectory) throws GuacamoleException { |  | ||||||
|  |  | ||||||
|         List<APIConnectionGroup> restConnectionGroups = new ArrayList<APIConnectionGroup>(); |  | ||||||
|          |  | ||||||
|         for (String connectionGroupID : connectionGroupDirectory.getIdentifiers()) |  | ||||||
|             restConnectionGroups.add(new APIConnectionGroup(connectionGroupDirectory.get(connectionGroupID))); |  | ||||||
|              |  | ||||||
|         return restConnectionGroups; |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,228 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| package org.glyptodon.guacamole.net.basic.rest.permission; |  | ||||||
|  |  | ||||||
| import org.codehaus.jackson.annotate.JsonIgnoreProperties; |  | ||||||
| import org.codehaus.jackson.map.annotate.JsonSerialize; |  | ||||||
| import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission; |  | ||||||
| import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission; |  | ||||||
| import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; |  | ||||||
| import org.glyptodon.guacamole.net.auth.permission.Permission; |  | ||||||
| import org.glyptodon.guacamole.net.auth.permission.SystemPermission; |  | ||||||
| import org.glyptodon.guacamole.net.auth.permission.UserPermission; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * A simple user permission to expose through the REST endpoints. |  | ||||||
|  *  |  | ||||||
|  * @author James Muehlner |  | ||||||
|  */ |  | ||||||
| @JsonIgnoreProperties(ignoreUnknown = true) |  | ||||||
| @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) |  | ||||||
| public class APIPermission { |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Create an empty APIPermission. |  | ||||||
|      */ |  | ||||||
|     public APIPermission() {} |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * The type of object that this permission refers to. |  | ||||||
|      */ |  | ||||||
|     private ObjectType objectType; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * The type of object that a permission can refer to. |  | ||||||
|      */ |  | ||||||
|     public enum ObjectType { |  | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * A normal connection. |  | ||||||
|          */ |  | ||||||
|         CONNECTION, |  | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * A connection group. |  | ||||||
|          */ |  | ||||||
|         CONNECTION_GROUP, |  | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * A Guacamole user. |  | ||||||
|          */ |  | ||||||
|         USER, |  | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * The Guacamole system itself. |  | ||||||
|          */ |  | ||||||
|         SYSTEM |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * The identifier of the object that this permission refers to. |  | ||||||
|      */ |  | ||||||
|     private String objectIdentifier; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * The object permission type for this APIPermission, if relevant. This is |  | ||||||
|      * only used if this.objectType is CONNECTION, CONNECTION_GROUP, or USER. |  | ||||||
|      */ |  | ||||||
|     private ObjectPermission.Type objectPermissionType; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * The system permission type for this APIPermission, if relevant. This is |  | ||||||
|      * only used if this.objectType is SYSTEM. |  | ||||||
|      */ |  | ||||||
|     private SystemPermission.Type systemPermissionType; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Create an APIConnection from a Connection record. |  | ||||||
|      *  |  | ||||||
|      * @param permission The permission to create this APIPermission from. |  | ||||||
|      */ |  | ||||||
|     public APIPermission(Permission permission) { |  | ||||||
|  |  | ||||||
|         // Connection permission |  | ||||||
|         if (permission instanceof ConnectionPermission) { |  | ||||||
|             this.objectType = ObjectType.CONNECTION; |  | ||||||
|             this.objectPermissionType = ((ConnectionPermission) permission).getType(); |  | ||||||
|             this.objectIdentifier = ((ConnectionPermission) permission).getObjectIdentifier(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Connection group permission |  | ||||||
|         else if (permission instanceof ConnectionGroupPermission) { |  | ||||||
|             this.objectType = ObjectType.CONNECTION_GROUP; |  | ||||||
|             this.objectPermissionType = ((ConnectionGroupPermission) permission).getType(); |  | ||||||
|             this.objectIdentifier = ((ConnectionGroupPermission) permission).getObjectIdentifier(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // User permission |  | ||||||
|         else if (permission instanceof UserPermission) { |  | ||||||
|             this.objectType = ObjectType.USER; |  | ||||||
|             this.objectPermissionType = ((UserPermission) permission).getType(); |  | ||||||
|             this.objectIdentifier = ((UserPermission) permission).getObjectIdentifier(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // System permission |  | ||||||
|         else if (permission instanceof SystemPermission) { |  | ||||||
|             this.objectType = ObjectType.SYSTEM; |  | ||||||
|             this.systemPermissionType = ((SystemPermission) permission).getType(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Returns the type of object that this permission refers to. |  | ||||||
|      *  |  | ||||||
|      * @return The type of object that this permission refers to.  |  | ||||||
|      */ |  | ||||||
|     public ObjectType getObjectType() { |  | ||||||
|         return objectType; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Set the type of object that this permission refers to. |  | ||||||
|      * @param objectType The type of object that this permission refers to.  |  | ||||||
|      */ |  | ||||||
|     public void setObjectType(ObjectType objectType) { |  | ||||||
|         this.objectType = objectType; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Returns a string representation of the permission type. |  | ||||||
|      *  |  | ||||||
|      * @return A string representation of the permission type.  |  | ||||||
|      */ |  | ||||||
|     public String getPermissionType() { |  | ||||||
|         switch(this.objectType) { |  | ||||||
|             case CONNECTION: |  | ||||||
|             case CONNECTION_GROUP: |  | ||||||
|             case USER: |  | ||||||
|                 return this.objectPermissionType.toString(); |  | ||||||
|             case SYSTEM: |  | ||||||
|                 return this.systemPermissionType.toString(); |  | ||||||
|             default: |  | ||||||
|                 return null; |  | ||||||
|         }  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Set the permission type from a string representation of that type. |  | ||||||
|      * Since it's not clear at this point whether this is an object permission or |  | ||||||
|      * system permission, try to set both of them. |  | ||||||
|      *  |  | ||||||
|      * @param permissionType The string representation of the permission type. |  | ||||||
|      */ |  | ||||||
|     public void setPermissionType(String permissionType) { |  | ||||||
|         try { |  | ||||||
|             this.objectPermissionType = ObjectPermission.Type.valueOf(permissionType); |  | ||||||
|         } catch(IllegalArgumentException e) {} |  | ||||||
|          |  | ||||||
|         try { |  | ||||||
|             this.systemPermissionType = SystemPermission.Type.valueOf(permissionType); |  | ||||||
|         } catch(IllegalArgumentException e) {} |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Returns the identifier of the object that this permission refers to. |  | ||||||
|      *  |  | ||||||
|      * @return The identifier of the object that this permission refers to.  |  | ||||||
|      */ |  | ||||||
|     public String getObjectIdentifier() { |  | ||||||
|         return objectIdentifier; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Set the identifier of the object that this permission refers to. |  | ||||||
|      *  |  | ||||||
|      * @param objectIdentifier The identifier of the object that this permission refers to.  |  | ||||||
|      */ |  | ||||||
|     public void setObjectIdentifier(String objectIdentifier) { |  | ||||||
|         this.objectIdentifier = objectIdentifier; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Returns an org.glyptodon.guacamole.net.auth.permission.Permission  |  | ||||||
|      * representation of this APIPermission. |  | ||||||
|      *  |  | ||||||
|      * @return An org.glyptodon.guacamole.net.auth.permission.Permission |  | ||||||
|      * representation of this APIPermission. |  | ||||||
|      */ |  | ||||||
|     public Permission toPermission() { |  | ||||||
|         switch(this.objectType) { |  | ||||||
|             case CONNECTION: |  | ||||||
|                 return new ConnectionPermission |  | ||||||
|                         (this.objectPermissionType, this.objectIdentifier); |  | ||||||
|             case CONNECTION_GROUP: |  | ||||||
|                 return new ConnectionGroupPermission |  | ||||||
|                         (this.objectPermissionType, this.objectIdentifier); |  | ||||||
|             case USER: |  | ||||||
|                 return new UserPermission |  | ||||||
|                         (this.objectPermissionType, this.objectIdentifier); |  | ||||||
|             case SYSTEM: |  | ||||||
|                 return new SystemPermission(this.systemPermissionType); |  | ||||||
|             default: |  | ||||||
|                 return null; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -0,0 +1,293 @@ | |||||||
|  | /* | ||||||
|  |  * 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. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package org.glyptodon.guacamole.net.basic.rest.permission; | ||||||
|  |  | ||||||
|  | import java.util.EnumSet; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.HashSet; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Set; | ||||||
|  | import org.glyptodon.guacamole.GuacamoleException; | ||||||
|  | import org.glyptodon.guacamole.GuacamoleServerException; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.Permission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.SystemPermission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.UserPermission; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The set of permissions which are granted to a specific user, organized by | ||||||
|  |  * object type and, if applicable, identifier. This object can be constructed | ||||||
|  |  * with arbitrary permissions present, or manipulated after creation through | ||||||
|  |  * the manipulation or replacement of its collections of permissions, but is | ||||||
|  |  * otherwise not intended for internal use as a data structure for permissions. | ||||||
|  |  * Its primary purpose is as a hierarchical format for exchanging granted | ||||||
|  |  * permissions with REST clients. | ||||||
|  |  */ | ||||||
|  | public class APIPermissionSet { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Map of connection ID to the set of granted permissions. | ||||||
|  |      */ | ||||||
|  |     private Map<String, EnumSet<ObjectPermission.Type>> connectionPermissions = new HashMap<String, EnumSet<ObjectPermission.Type>>(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Map of connection group ID to the set of granted permissions. | ||||||
|  |      */ | ||||||
|  |     private Map<String, EnumSet<ObjectPermission.Type>> connectionGroupPermissions = new HashMap<String, EnumSet<ObjectPermission.Type>>(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Map of user ID to the set of granted permissions. | ||||||
|  |      */ | ||||||
|  |     private Map<String, EnumSet<ObjectPermission.Type>> userPermissions = new HashMap<String, EnumSet<ObjectPermission.Type>>(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set of all granted system-level permissions. | ||||||
|  |      */ | ||||||
|  |     private EnumSet<SystemPermission.Type> systemPermissions = EnumSet.noneOf(SystemPermission.Type.class); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Adds the given object permission to the given map of object identifier | ||||||
|  |      * to permission set. | ||||||
|  |      * | ||||||
|  |      * @param permissions | ||||||
|  |      *     The map to add the given permission to. | ||||||
|  |      * | ||||||
|  |      * @param permission | ||||||
|  |      *     The permission to add. | ||||||
|  |      */ | ||||||
|  |     private void addPermission(Map<String, EnumSet<ObjectPermission.Type>> permissions, ObjectPermission<String> permission) { | ||||||
|  |  | ||||||
|  |         // Pull set of permissions for given object | ||||||
|  |         String id = permission.getObjectIdentifier(); | ||||||
|  |         EnumSet<ObjectPermission.Type> types = permissions.get(id); | ||||||
|  |  | ||||||
|  |         // If set does not yet exist, create it | ||||||
|  |         if (types == null) { | ||||||
|  |             types = EnumSet.of(permission.getType()); | ||||||
|  |             permissions.put(id, types); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Otherwise, add the specified permission | ||||||
|  |         else | ||||||
|  |             types.add(permission.getType()); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Adds the given system-level permission to the given set of granted | ||||||
|  |      * system permissions. | ||||||
|  |      * | ||||||
|  |      * @param permissions | ||||||
|  |      *     The set of system permissions to add the given permission to. | ||||||
|  |      * | ||||||
|  |      * @param permission | ||||||
|  |      *     The permission to add. | ||||||
|  |      */ | ||||||
|  |     private void addPermission(EnumSet<SystemPermission.Type> permissions, SystemPermission permission) { | ||||||
|  |         permissions.add(permission.getType()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Adds the given permission to the appropriate type-specific set or map of | ||||||
|  |      * permissions based on the permission class. Only connection, connection | ||||||
|  |      * group, user, and system permissions are supported. Unsupported | ||||||
|  |      * permission types will result in a GuacamoleException being thrown. | ||||||
|  |      * | ||||||
|  |      * @param permission The permission to add. | ||||||
|  |      * @throws GuacamoleException If the permission is of an unsupported type. | ||||||
|  |      */ | ||||||
|  |     private void addPermission(Permission<?> permission) throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         // Connection permissions | ||||||
|  |         if (permission instanceof ConnectionPermission) | ||||||
|  |             addPermission(connectionPermissions, (ConnectionPermission) permission); | ||||||
|  |  | ||||||
|  |         // Connection group permissions | ||||||
|  |         else if (permission instanceof ConnectionGroupPermission) | ||||||
|  |             addPermission(connectionGroupPermissions, (ConnectionGroupPermission) permission); | ||||||
|  |  | ||||||
|  |         // User permissions | ||||||
|  |         else if (permission instanceof UserPermission) | ||||||
|  |             addPermission(userPermissions, (UserPermission) permission); | ||||||
|  |  | ||||||
|  |         // System permissions | ||||||
|  |         else if (permission instanceof SystemPermission) | ||||||
|  |             addPermission(systemPermissions, (SystemPermission) permission); | ||||||
|  |  | ||||||
|  |         // Unknown / unsupported permission type | ||||||
|  |         else | ||||||
|  |             throw new GuacamoleServerException("Serialization of permission type \"" + permission.getClass() + "\" not implemented."); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new permission set which contains no granted permissions. Any | ||||||
|  |      * permissions must be added by manipulating or replacing the applicable | ||||||
|  |      * permission collection. | ||||||
|  |      */ | ||||||
|  |     public APIPermissionSet() { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new permission set having the given permissions. | ||||||
|  |      * | ||||||
|  |      * @param permissions | ||||||
|  |      *     The permissions to initially store within the permission set. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If any of the given permissions are of an unsupported type. | ||||||
|  |      */ | ||||||
|  |     public APIPermissionSet(Iterable<Permission> permissions) throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         // Add all provided permissions  | ||||||
|  |         for (Permission permission : permissions) | ||||||
|  |             addPermission(permission); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new permission set having the given permissions. | ||||||
|  |      * | ||||||
|  |      * @param permissions | ||||||
|  |      *     The permissions to initially store within the permission set. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If any of the given permissions are of an unsupported type. | ||||||
|  |      */ | ||||||
|  |     public APIPermissionSet(Permission... permissions) throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         // Add all provided permissions  | ||||||
|  |         for (Permission permission : permissions) | ||||||
|  |             addPermission(permission); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns a map of connection IDs to the set of permissions granted for | ||||||
|  |      * that connection. If no permissions are granted to a particular | ||||||
|  |      * connection, its ID will not be present as a key in the map. This map is | ||||||
|  |      * mutable, and changes to this map will affect the permission set | ||||||
|  |      * directly. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A map of connection IDs to the set of permissions granted for that | ||||||
|  |      *     connection. | ||||||
|  |      */ | ||||||
|  |     public Map<String, EnumSet<ObjectPermission.Type>> getConnectionPermissions() { | ||||||
|  |         return connectionPermissions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns a map of connection group IDs to the set of permissions granted | ||||||
|  |      * for that connection group. If no permissions are granted to a particular | ||||||
|  |      * connection group, its ID will not be present as a key in the map. This | ||||||
|  |      * map is mutable, and changes to this map will affect the permission set | ||||||
|  |      * directly. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A map of connection group IDs to the set of permissions granted for | ||||||
|  |      *     that connection group. | ||||||
|  |      */ | ||||||
|  |     public Map<String, EnumSet<ObjectPermission.Type>> getConnectionGroupPermissions() { | ||||||
|  |         return connectionGroupPermissions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns a map of user IDs to the set of permissions granted for that | ||||||
|  |      * user. If no permissions are granted to a particular user, its ID will | ||||||
|  |      * not be present as a key in the map. This map is mutable, and changes to | ||||||
|  |      * to this map will affect the permission set directly. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A map of user IDs to the set of permissions granted for that user. | ||||||
|  |      */ | ||||||
|  |     public Map<String, EnumSet<ObjectPermission.Type>> getUserPermissions() { | ||||||
|  |         return userPermissions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns the set of granted system-level permissions. If no permissions | ||||||
|  |      * are granted at the system level, this will be an empty set. This set is | ||||||
|  |      * mutable, and changes to this set will affect the permission set | ||||||
|  |      * directly. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     The set of granted system-level permissions. | ||||||
|  |      */ | ||||||
|  |     public EnumSet<SystemPermission.Type> getSystemPermissions() { | ||||||
|  |         return systemPermissions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Replaces the current map of connection permissions with the given map, | ||||||
|  |      * which must map connection ID to its corresponding set of granted | ||||||
|  |      * permissions. If a connection has no permissions, its ID must not be | ||||||
|  |      * present as a key in the map. | ||||||
|  |      * | ||||||
|  |      * @param connectionPermissions | ||||||
|  |      *     The map which must replace the currently-stored map of permissions. | ||||||
|  |      */ | ||||||
|  |     public void setConnectionPermissions(Map<String, EnumSet<ObjectPermission.Type>> connectionPermissions) { | ||||||
|  |         this.connectionPermissions = connectionPermissions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Replaces the current map of connection group permissions with the given | ||||||
|  |      * map, which must map connection group ID to its corresponding set of | ||||||
|  |      * granted permissions. If a connection group has no permissions, its ID | ||||||
|  |      * must not be present as a key in the map. | ||||||
|  |      * | ||||||
|  |      * @param connectionGroupPermissions | ||||||
|  |      *     The map which must replace the currently-stored map of permissions. | ||||||
|  |      */ | ||||||
|  |     public void setConnectionGroupPermissions(Map<String, EnumSet<ObjectPermission.Type>> connectionGroupPermissions) { | ||||||
|  |         this.connectionGroupPermissions = connectionGroupPermissions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Replaces the current map of user permissions with the given map, which | ||||||
|  |      * must map user ID to its corresponding set of granted permissions. If a | ||||||
|  |      * user has no permissions, its ID must not be present as a key in the map. | ||||||
|  |      * | ||||||
|  |      * @param userPermissions | ||||||
|  |      *     The map which must replace the currently-stored map of permissions. | ||||||
|  |      */ | ||||||
|  |     public void setUserPermissions(Map<String, EnumSet<ObjectPermission.Type>> userPermissions) { | ||||||
|  |         this.userPermissions = userPermissions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Replaces the current set of system-level permissions with the given set. | ||||||
|  |      * If no system-level permissions are granted, the empty set must be | ||||||
|  |      * specified. | ||||||
|  |      * | ||||||
|  |      * @param systemPermissions | ||||||
|  |      *     The set which must replace the currently-stored set of permissions. | ||||||
|  |      */ | ||||||
|  |     public void setSystemPermissions(EnumSet<SystemPermission.Type> systemPermissions) { | ||||||
|  |         this.systemPermissions = systemPermissions; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  | } | ||||||
| @@ -1,217 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| package org.glyptodon.guacamole.net.basic.rest.permission; |  | ||||||
|  |  | ||||||
| import com.google.inject.Inject; |  | ||||||
| import java.util.HashMap; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import javax.ws.rs.Consumes; |  | ||||||
| import javax.ws.rs.GET; |  | ||||||
| import javax.ws.rs.POST; |  | ||||||
| import javax.ws.rs.Path; |  | ||||||
| import javax.ws.rs.PathParam; |  | ||||||
| import javax.ws.rs.Produces; |  | ||||||
| import javax.ws.rs.QueryParam; |  | ||||||
| import javax.ws.rs.core.MediaType; |  | ||||||
| import javax.ws.rs.core.Response.Status; |  | ||||||
| import org.glyptodon.guacamole.GuacamoleException; |  | ||||||
| import org.glyptodon.guacamole.net.auth.Directory; |  | ||||||
| import org.glyptodon.guacamole.net.auth.User; |  | ||||||
| import org.glyptodon.guacamole.net.auth.UserContext; |  | ||||||
| import org.glyptodon.guacamole.net.auth.permission.Permission; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.APIPatch; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.HTTPException; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.PATCH; |  | ||||||
| import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; |  | ||||||
| import org.slf4j.Logger; |  | ||||||
| import org.slf4j.LoggerFactory; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * A REST Service for handling connection CRUD operations. |  | ||||||
|  *  |  | ||||||
|  * @author James Muehlner |  | ||||||
|  */ |  | ||||||
| @Path("/permission") |  | ||||||
| @Produces(MediaType.APPLICATION_JSON) |  | ||||||
| @Consumes(MediaType.APPLICATION_JSON) |  | ||||||
| public class PermissionRESTService { |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Logger for this class. |  | ||||||
|      */ |  | ||||||
|     private static final Logger logger = LoggerFactory.getLogger(PermissionRESTService.class); |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * A service for authenticating users from auth tokens. |  | ||||||
|      */ |  | ||||||
|     @Inject |  | ||||||
|     private AuthenticationService authenticationService; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * A service for managing the REST endpoint APIPermission objects.  |  | ||||||
|      */ |  | ||||||
|     @Inject |  | ||||||
|     private PermissionService permissionService; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Gets a list of permissions for the user with the given userID. |  | ||||||
|      *  |  | ||||||
|      * @param authToken The authentication token that is used to authenticate |  | ||||||
|      *                  the user performing the operation. |  | ||||||
|      * @param userID The ID of the user to retrieve permissions for. |  | ||||||
|      * @return The permission list. |  | ||||||
|      * @throws GuacamoleException If a problem is encountered while listing permissions. |  | ||||||
|      */ |  | ||||||
|     @GET |  | ||||||
|     @Path("/{userID}") |  | ||||||
|     @AuthProviderRESTExposure |  | ||||||
|     public List<APIPermission> getPermissions(@QueryParam("token") String authToken, @PathParam("userID") String userID)  |  | ||||||
|             throws GuacamoleException { |  | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |  | ||||||
|  |  | ||||||
|         // Get the user |  | ||||||
|         User user = userContext.getUserDirectory().get(userID); |  | ||||||
|         if (user == null) |  | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "User not found with the provided userID."); |  | ||||||
|  |  | ||||||
|         return permissionService.convertPermissionList(user.getPermissions()); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Adds a permissions for a user with the given userID. |  | ||||||
|      *  |  | ||||||
|      * @param authToken The authentication token that is used to authenticate |  | ||||||
|      *                  the user performing the operation. |  | ||||||
|      * @param userID The user ID to add the permission for. |  | ||||||
|      * @param permission The permission to add for the user with the given userID. |  | ||||||
|      * @throws GuacamoleException If a problem is encountered while adding the permission. |  | ||||||
|      */ |  | ||||||
|     @POST |  | ||||||
|     @Path("/{userID}") |  | ||||||
|     @AuthProviderRESTExposure |  | ||||||
|     public void addPermission(@QueryParam("token") String authToken,  |  | ||||||
|             @PathParam("userID") String userID, APIPermission permission)  |  | ||||||
|             throws GuacamoleException { |  | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |  | ||||||
|  |  | ||||||
|         // Get the user |  | ||||||
|         User user = userContext.getUserDirectory().get(userID); |  | ||||||
|         if (user == null) |  | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "User not found with the provided userID."); |  | ||||||
|  |  | ||||||
|         // Add the new permission |  | ||||||
|         user.addPermission(permission.toPermission()); |  | ||||||
|         userContext.getUserDirectory().update(user); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Removes a permissions for a user with the given userID. |  | ||||||
|      *  |  | ||||||
|      * @param authToken The authentication token that is used to authenticate |  | ||||||
|      *                  the user performing the operation. |  | ||||||
|      * @param userID The user ID to remove the permission for. |  | ||||||
|      * @param permission The permission to remove for the user with the given userID. |  | ||||||
|      * @throws GuacamoleException If a problem is encountered while removing the permission. |  | ||||||
|      */ |  | ||||||
|     @POST |  | ||||||
|     @Path("/remove/{userID}/") |  | ||||||
|     @AuthProviderRESTExposure |  | ||||||
|     public void removePermission(@QueryParam("token") String authToken,  |  | ||||||
|             @PathParam("userID") String userID, APIPermission permission)  |  | ||||||
|             throws GuacamoleException { |  | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |  | ||||||
|          |  | ||||||
|         // Get the user |  | ||||||
|         User user = userContext.getUserDirectory().get(userID); |  | ||||||
|         if (user == null) |  | ||||||
|             throw new HTTPException(Status.NOT_FOUND, "User not found with the provided userID."); |  | ||||||
|  |  | ||||||
|         // Remove the permission |  | ||||||
|         user.removePermission(permission.toPermission()); |  | ||||||
|         userContext.getUserDirectory().update(user); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Applies a given list of permission patches. |  | ||||||
|      *  |  | ||||||
|      * @param authToken The authentication token that is used to authenticate |  | ||||||
|      *                  the user performing the operation. |  | ||||||
|      * @param patches   The permission patches to apply for this request. |  | ||||||
|      * @throws GuacamoleException If a problem is encountered while removing the permission. |  | ||||||
|      */ |  | ||||||
|     @PATCH |  | ||||||
|     @AuthProviderRESTExposure |  | ||||||
|     public void patchPermissions(@QueryParam("token") String authToken,  |  | ||||||
|             List<APIPatch<APIPermission>> patches) throws GuacamoleException { |  | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |  | ||||||
|          |  | ||||||
|         // Get the user directory |  | ||||||
|         Directory<String, User> userDirectory = userContext.getUserDirectory(); |  | ||||||
|          |  | ||||||
|         // All users who have had permissions added or removed |  | ||||||
|         Map<String, User> modifiedUsers = new HashMap<String, User>(); |  | ||||||
|          |  | ||||||
|         for (APIPatch<APIPermission> patch : patches) { |  | ||||||
|  |  | ||||||
|             String userID = patch.getPath(); |  | ||||||
|             Permission permission = patch.getValue().toPermission(); |  | ||||||
|              |  | ||||||
|             // See if we've already modified this user in this request |  | ||||||
|             User user = modifiedUsers.get(userID); |  | ||||||
|             if (user == null) |  | ||||||
|                 user = userDirectory.get(userID); |  | ||||||
|              |  | ||||||
|             if (user == null) |  | ||||||
|                 throw new HTTPException(Status.NOT_FOUND, "User not found with userID " + userID + "."); |  | ||||||
|              |  | ||||||
|             // Only the add and remove operations are supported for permissions |  | ||||||
|             switch(patch.getOp()) { |  | ||||||
|                 case add: |  | ||||||
|                     user.addPermission(permission); |  | ||||||
|                     modifiedUsers.put(userID, user); |  | ||||||
|                     break; |  | ||||||
|                 case remove: |  | ||||||
|                     user.removePermission(permission); |  | ||||||
|                     modifiedUsers.put(userID, user); |  | ||||||
|                     break; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         // Save the permission changes for all modified users |  | ||||||
|         for (User user : modifiedUsers.values()) |  | ||||||
|             userDirectory.update(user); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -1,74 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| package org.glyptodon.guacamole.net.basic.rest.permission; |  | ||||||
|  |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.HashSet; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Set; |  | ||||||
| import org.glyptodon.guacamole.net.auth.permission.Permission; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * A service for performing useful manipulations on REST Permissions. |  | ||||||
|  *  |  | ||||||
|  * @author James Muehlner |  | ||||||
|  */ |  | ||||||
| public class PermissionService { |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Converts a list of Permission to a list of APIPermission objects for  |  | ||||||
|      * exposing with the REST endpoints. |  | ||||||
|      *  |  | ||||||
|      * @param permissions The Connections to convert for REST endpoint use. |  | ||||||
|      * @return A List of APIPermission objects for use with the REST endpoint. |  | ||||||
|      */ |  | ||||||
|     public List<APIPermission> convertPermissionList(Iterable<? extends Permission> permissions) { |  | ||||||
|  |  | ||||||
|         List<APIPermission> restPermissions = new ArrayList<APIPermission>(); |  | ||||||
|          |  | ||||||
|         for(Permission permission : permissions) |  | ||||||
|             restPermissions.add(new APIPermission(permission)); |  | ||||||
|              |  | ||||||
|         return restPermissions; |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Converts a list of APIPermission to a set of Permission objects for internal |  | ||||||
|      * Guacamole use. |  | ||||||
|      *  |  | ||||||
|      * @param restPermissions The APIPermission objects from the REST endpoints. |  | ||||||
|      * @return a List of Permission objects for internal Guacamole use. |  | ||||||
|      */ |  | ||||||
|     public Set<Permission> convertAPIPermissionList(Iterable<APIPermission> restPermissions) { |  | ||||||
|  |  | ||||||
|         Set<Permission> permissions = new HashSet<Permission>(); |  | ||||||
|          |  | ||||||
|         for(APIPermission restPermission : restPermissions) |  | ||||||
|             permissions.add(restPermission.toPermission()); |  | ||||||
|          |  | ||||||
|         return permissions; |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -24,14 +24,15 @@ package org.glyptodon.guacamole.net.basic.rest.protocol; | |||||||
|  |  | ||||||
| import com.google.inject.Inject; | import com.google.inject.Inject; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import javax.ws.rs.Consumes; |  | ||||||
| import javax.ws.rs.GET; | import javax.ws.rs.GET; | ||||||
| import javax.ws.rs.Path; | import javax.ws.rs.Path; | ||||||
| import javax.ws.rs.Produces; | import javax.ws.rs.Produces; | ||||||
|  | import javax.ws.rs.QueryParam; | ||||||
| import javax.ws.rs.core.MediaType; | import javax.ws.rs.core.MediaType; | ||||||
| import org.glyptodon.guacamole.GuacamoleException; | import org.glyptodon.guacamole.GuacamoleException; | ||||||
| import org.glyptodon.guacamole.net.basic.ProtocolInfo; | import org.glyptodon.guacamole.net.basic.ProtocolInfo; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; | import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; | ||||||
|  | import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| @@ -40,9 +41,8 @@ import org.slf4j.LoggerFactory; | |||||||
|  *  |  *  | ||||||
|  * @author James Muehlner |  * @author James Muehlner | ||||||
|  */ |  */ | ||||||
| @Path("/protocol") | @Path("/protocols") | ||||||
| @Produces(MediaType.APPLICATION_JSON) | @Produces(MediaType.APPLICATION_JSON) | ||||||
| @Consumes(MediaType.APPLICATION_JSON) |  | ||||||
| public class ProtocolRESTService { | public class ProtocolRESTService { | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -50,6 +50,12 @@ public class ProtocolRESTService { | |||||||
|      */ |      */ | ||||||
|     private static final Logger logger = LoggerFactory.getLogger(ProtocolRESTService.class); |     private static final Logger logger = LoggerFactory.getLogger(ProtocolRESTService.class); | ||||||
|      |      | ||||||
|  |     /** | ||||||
|  |      * A service for authenticating users from auth tokens. | ||||||
|  |      */ | ||||||
|  |     @Inject | ||||||
|  |     private AuthenticationService authenticationService; | ||||||
|  |      | ||||||
|     /** |     /** | ||||||
|      * Service for retrieving protocol definitions. |      * Service for retrieving protocol definitions. | ||||||
|      */ |      */ | ||||||
| @@ -59,15 +65,27 @@ public class ProtocolRESTService { | |||||||
|     /** |     /** | ||||||
|      * Gets a map of protocols defined in the system - protocol name to protocol. |      * Gets a map of protocols defined in the system - protocol name to protocol. | ||||||
|      *  |      *  | ||||||
|      * @return The protocol map. |      * @param authToken | ||||||
|      * @throws GuacamoleException If a problem is encountered while listing protocols. |      *     The authentication token that is used to authenticate the user | ||||||
|  |      *     performing the operation. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A map of protocol information, where each key is the unique name | ||||||
|  |      *     associated with that protocol. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while retrieving the available protocols. | ||||||
|      */ |      */ | ||||||
|     @GET |     @GET | ||||||
|     @AuthProviderRESTExposure |     @AuthProviderRESTExposure | ||||||
|     public Map<String, ProtocolInfo> getProtocols() throws GuacamoleException { |     public Map<String, ProtocolInfo> getProtocols(@QueryParam("token") String authToken) throws GuacamoleException { | ||||||
|  |          | ||||||
|  |         // Verify the given auth token is valid | ||||||
|  |         authenticationService.getUserContext(authToken); | ||||||
|  |  | ||||||
|         // Get and return a map of all protocols. |         // Get and return a map of all protocols. | ||||||
|         return protocolRetrievalservice.getProtocolMap(); |         return protocolRetrievalservice.getProtocolMap(); | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -23,25 +23,40 @@ | |||||||
| package org.glyptodon.guacamole.net.basic.rest.user; | package org.glyptodon.guacamole.net.basic.rest.user; | ||||||
|  |  | ||||||
| import com.google.inject.Inject; | import com.google.inject.Inject; | ||||||
|  | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
| import javax.ws.rs.Consumes; | import javax.ws.rs.Consumes; | ||||||
| import javax.ws.rs.DELETE; | import javax.ws.rs.DELETE; | ||||||
| import javax.ws.rs.GET; | import javax.ws.rs.GET; | ||||||
| import javax.ws.rs.POST; | import javax.ws.rs.POST; | ||||||
|  | import javax.ws.rs.PUT; | ||||||
| import javax.ws.rs.Path; | import javax.ws.rs.Path; | ||||||
| import javax.ws.rs.PathParam; | import javax.ws.rs.PathParam; | ||||||
| import javax.ws.rs.Produces; | import javax.ws.rs.Produces; | ||||||
| import javax.ws.rs.QueryParam; | import javax.ws.rs.QueryParam; | ||||||
| import javax.ws.rs.core.MediaType; | import javax.ws.rs.core.MediaType; | ||||||
| import javax.ws.rs.core.Response; | import javax.ws.rs.core.Response; | ||||||
|  | import javax.ws.rs.core.Response.Status; | ||||||
| import org.glyptodon.guacamole.GuacamoleException; | import org.glyptodon.guacamole.GuacamoleException; | ||||||
|  | import org.glyptodon.guacamole.GuacamoleResourceNotFoundException; | ||||||
| import org.glyptodon.guacamole.net.auth.Directory; | import org.glyptodon.guacamole.net.auth.Directory; | ||||||
| import org.glyptodon.guacamole.net.auth.User; | import org.glyptodon.guacamole.net.auth.User; | ||||||
| import org.glyptodon.guacamole.net.auth.UserContext; | import org.glyptodon.guacamole.net.auth.UserContext; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.Permission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.SystemPermission; | ||||||
|  | import org.glyptodon.guacamole.net.auth.permission.UserPermission; | ||||||
|  | import org.glyptodon.guacamole.net.basic.rest.APIPatch; | ||||||
|  | import static org.glyptodon.guacamole.net.basic.rest.APIPatch.Operation.add; | ||||||
|  | import static org.glyptodon.guacamole.net.basic.rest.APIPatch.Operation.remove; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; | import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.HTTPException; | import org.glyptodon.guacamole.net.basic.rest.HTTPException; | ||||||
|  | import org.glyptodon.guacamole.net.basic.rest.PATCH; | ||||||
| import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; | import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; | ||||||
|  | import org.glyptodon.guacamole.net.basic.rest.permission.APIPermissionSet; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| @@ -50,7 +65,7 @@ import org.slf4j.LoggerFactory; | |||||||
|  *  |  *  | ||||||
|  * @author James Muehlner |  * @author James Muehlner | ||||||
|  */ |  */ | ||||||
| @Path("/user") | @Path("/users") | ||||||
| @Produces(MediaType.APPLICATION_JSON) | @Produces(MediaType.APPLICATION_JSON) | ||||||
| @Consumes(MediaType.APPLICATION_JSON) | @Consumes(MediaType.APPLICATION_JSON) | ||||||
| public class UserRESTService { | public class UserRESTService { | ||||||
| @@ -60,6 +75,30 @@ public class UserRESTService { | |||||||
|      */ |      */ | ||||||
|     private static final Logger logger = LoggerFactory.getLogger(UserRESTService.class); |     private static final Logger logger = LoggerFactory.getLogger(UserRESTService.class); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The prefix of any path within an operation of a JSON patch which | ||||||
|  |      * modifies the permissions of a user regarding a specific connection. | ||||||
|  |      */ | ||||||
|  |     private static final String CONNECTION_PERMISSION_PATCH_PATH_PREFIX = "/connectionPermissions/"; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * The prefix of any path within an operation of a JSON patch which | ||||||
|  |      * modifies the permissions of a user regarding a specific connection group. | ||||||
|  |      */ | ||||||
|  |     private static final String CONNECTION_GROUP_PERMISSION_PATCH_PATH_PREFIX = "/connectionGroupPermissions/"; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The prefix of any path within an operation of a JSON patch which | ||||||
|  |      * modifies the permissions of a user regarding another, specific user. | ||||||
|  |      */ | ||||||
|  |     private static final String USER_PERMISSION_PATCH_PATH_PREFIX = "/userPermissions/"; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The path of any operation within a JSON patch which modifies the | ||||||
|  |      * permissions of a user regarding the entire system. | ||||||
|  |      */ | ||||||
|  |     private static final String SYSTEM_PERMISSION_PATCH_PATH = "/systemPermissions"; | ||||||
|  |      | ||||||
|     /** |     /** | ||||||
|      * A service for authenticating users from auth tokens. |      * A service for authenticating users from auth tokens. | ||||||
|      */ |      */ | ||||||
| @@ -67,44 +106,73 @@ public class UserRESTService { | |||||||
|     private AuthenticationService authenticationService; |     private AuthenticationService authenticationService; | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * A service for managing the REST endpoint APIPermission objects.  |      * Gets a list of users in the system, filtering the returned list by the | ||||||
|      */ |      * given permission, if specified. | ||||||
|     @Inject |      *  | ||||||
|     private UserService userService; |      * @param authToken | ||||||
|      |      *     The authentication token that is used to authenticate the user | ||||||
|     /** |      *     performing the operation. | ||||||
|      * Gets a list of users in the system. |      * | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * @param permission | ||||||
|      *                  the user performing the operation. |      *     If specified, limit the returned list to only those users for whom | ||||||
|      * @return The user list. |      *     the current user has the given permission. Otherwise, all visible | ||||||
|      * @throws GuacamoleException If a problem is encountered while listing users. |      *     users are returned. | ||||||
|  |      *  | ||||||
|  |      * @return | ||||||
|  |      *     A list of all visible users. If a permission was specified, this | ||||||
|  |      *     list will contain only those users for whom the current user has | ||||||
|  |      *     that permission. | ||||||
|  |      *  | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error is encountered while retrieving users. | ||||||
|      */ |      */ | ||||||
|     @GET |     @GET | ||||||
|     @AuthProviderRESTExposure |     @AuthProviderRESTExposure | ||||||
|     public List<APIUser> getUsers(@QueryParam("token") String authToken) throws GuacamoleException { |     public List<APIUser> getUsers(@QueryParam("token") String authToken, | ||||||
|  |             @QueryParam("permission") UserPermission.Type permission) | ||||||
|  |             throws GuacamoleException { | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|  |         User self = userContext.self(); | ||||||
|  |  | ||||||
|         // Get the directory |         // Get the directory | ||||||
|         Directory<String, User> userDirectory = userContext.getUserDirectory(); |         Directory<String, User> userDirectory = userContext.getUserDirectory(); | ||||||
|  |  | ||||||
|         // Convert and return the user directory listing |         List<APIUser> users = new ArrayList<APIUser>(); | ||||||
|         return userService.convertUserList(userDirectory); |  | ||||||
|  |         // Add all users matching the given permission filter | ||||||
|  |         for (String username : userDirectory.getIdentifiers()) { | ||||||
|  |  | ||||||
|  |             if (permission == null || self.hasPermission(new UserPermission(permission, username))) | ||||||
|  |                 users.add(new APIUser(userDirectory.get(username))); | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Return the user directory listing | ||||||
|  |         return users; | ||||||
|  |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * Gets an individual user. |      * Retrieves an individual user. | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * | ||||||
|      *                  the user performing the operation. |      * @param authToken | ||||||
|      * @param userID    The ID of the user to retrieve. |      *     The authentication token that is used to authenticate the user | ||||||
|      * @return user The user. |      *     performing the operation. | ||||||
|      * @throws GuacamoleException If a problem is encountered while retrieving the user. |      * | ||||||
|  |      * @param username | ||||||
|  |      *     The username of the user to retrieve. | ||||||
|  |      * | ||||||
|  |      * @return user | ||||||
|  |      *     The user having the given username. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while retrieving the user. | ||||||
|      */ |      */ | ||||||
|     @GET |     @GET | ||||||
|     @Path("/{userID}") |     @Path("/{username}") | ||||||
|     @AuthProviderRESTExposure |     @AuthProviderRESTExposure | ||||||
|     public APIUser getUser(@QueryParam("token") String authToken, @PathParam("userID") String userID)  |     public APIUser getUser(@QueryParam("token") String authToken, @PathParam("username") String username)  | ||||||
|             throws GuacamoleException { |             throws GuacamoleException { | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
| @@ -113,9 +181,9 @@ public class UserRESTService { | |||||||
|         Directory<String, User> userDirectory = userContext.getUserDirectory(); |         Directory<String, User> userDirectory = userContext.getUserDirectory(); | ||||||
|  |  | ||||||
|         // Get the user |         // Get the user | ||||||
|         User user = userDirectory.get(userID); |         User user = userDirectory.get(username); | ||||||
|         if (user == null) |         if (user == null) | ||||||
|             throw new HTTPException(Response.Status.NOT_FOUND, "User not found with the provided userID."); |             throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\""); | ||||||
|  |  | ||||||
|         // Return the user |         // Return the user | ||||||
|         return new APIUser(user); |         return new APIUser(user); | ||||||
| @@ -154,16 +222,25 @@ public class UserRESTService { | |||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * Updates an individual existing user. |      * Updates an individual existing user. | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * | ||||||
|      *                  the user performing the operation. |      * @param authToken | ||||||
|      * @param userID The unique identifier of the user to update. |      *     The authentication token that is used to authenticate the user | ||||||
|      * @param user The updated user. |      *     performing the operation. | ||||||
|      * @throws GuacamoleException If a problem is encountered while updating the user. |      * | ||||||
|  |      * @param username | ||||||
|  |      *     The username of the user to update. | ||||||
|  |      * | ||||||
|  |      * @param user | ||||||
|  |      *     The data to update the user with. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while updating the user. | ||||||
|      */ |      */ | ||||||
|     @POST |     @PUT | ||||||
|     @Path("/{userID}") |     @Path("/{username}") | ||||||
|     @AuthProviderRESTExposure |     @AuthProviderRESTExposure | ||||||
|     public void updateUser(@QueryParam("token") String authToken, @PathParam("userID") String userID, APIUser user)  |     public void updateUser(@QueryParam("token") String authToken, | ||||||
|  |             @PathParam("username") String username, APIUser user)  | ||||||
|             throws GuacamoleException { |             throws GuacamoleException { | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
| @@ -171,37 +248,43 @@ public class UserRESTService { | |||||||
|         // Get the directory |         // Get the directory | ||||||
|         Directory<String, User> userDirectory = userContext.getUserDirectory(); |         Directory<String, User> userDirectory = userContext.getUserDirectory(); | ||||||
|  |  | ||||||
|         if (!user.getUsername().equals(userID)) |         // Validate data and path are sane | ||||||
|             throw new HTTPException(Response.Status.BAD_REQUEST, "Username does not match provided userID."); |         if (!user.getUsername().equals(username)) | ||||||
|  |             throw new HTTPException(Response.Status.BAD_REQUEST, | ||||||
|  |                     "Username in path does not match username provided JSON data."); | ||||||
|  |  | ||||||
|         // Get the user |         // Get the user | ||||||
|         User existingUser = userDirectory.get(userID); |         User existingUser = userDirectory.get(username); | ||||||
|         if (existingUser == null) |         if (existingUser == null) | ||||||
|             throw new HTTPException(Response.Status.NOT_FOUND, "User not found with the provided userID."); |             throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\""); | ||||||
|  |  | ||||||
|         // Do not update the user password if no password was provided |         // Do not update the user password if no password was provided | ||||||
|         if (user.getPassword() != null) { |         if (user.getPassword() != null) | ||||||
|             /* |  | ||||||
|              * Update the user with the permission set from the existing user |  | ||||||
|              * since the user REST endpoints do not expose permissions. |  | ||||||
|              */ |  | ||||||
|             existingUser.setPassword(user.getPassword()); |             existingUser.setPassword(user.getPassword()); | ||||||
|  |  | ||||||
|  |         // Update the user | ||||||
|         userDirectory.update(existingUser); |         userDirectory.update(existingUser); | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * Deletes an individual existing user. |      * Deletes an individual existing user. | ||||||
|      * @param authToken The authentication token that is used to authenticate |      * | ||||||
|      *                  the user performing the operation. |      * @param authToken | ||||||
|      * @param userID The unique identifier of the user to delete. |      *     The authentication token that is used to authenticate the user | ||||||
|      * @throws GuacamoleException If a problem is encountered while deleting the user. |      *     performing the operation. | ||||||
|  |      * | ||||||
|  |      * @param username | ||||||
|  |      *     The username of the user to delete. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while deleting the user. | ||||||
|      */ |      */ | ||||||
|     @DELETE |     @DELETE | ||||||
|     @Path("/{userID}") |     @Path("/{username}") | ||||||
|     @AuthProviderRESTExposure |     @AuthProviderRESTExposure | ||||||
|     public void deleteUser(@QueryParam("token") String authToken, @PathParam("userID") String userID)  |     public void deleteUser(@QueryParam("token") String authToken, | ||||||
|  |             @PathParam("username") String username)  | ||||||
|             throws GuacamoleException { |             throws GuacamoleException { | ||||||
|  |  | ||||||
|         UserContext userContext = authenticationService.getUserContext(authToken); |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
| @@ -210,12 +293,168 @@ public class UserRESTService { | |||||||
|         Directory<String, User> userDirectory = userContext.getUserDirectory(); |         Directory<String, User> userDirectory = userContext.getUserDirectory(); | ||||||
|  |  | ||||||
|         // Get the user |         // Get the user | ||||||
|         User existingUser = userDirectory.get(userID); |         User existingUser = userDirectory.get(username); | ||||||
|         if (existingUser == null) |         if (existingUser == null) | ||||||
|             throw new HTTPException(Response.Status.NOT_FOUND, "User not found with the provided userID."); |             throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\""); | ||||||
|  |  | ||||||
|         // Delete the user |         // Delete the user | ||||||
|         userDirectory.remove(userID); |         userDirectory.remove(username); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets a list of permissions for the user with the given username. | ||||||
|  |      *  | ||||||
|  |      * @param authToken | ||||||
|  |      *     The authentication token that is used to authenticate the user | ||||||
|  |      *     performing the operation. | ||||||
|  |      * | ||||||
|  |      * @param username | ||||||
|  |      *     The username of the user to retrieve permissions for. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A list of all permissions granted to the specified user. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If an error occurs while retrieving permissions. | ||||||
|  |      */ | ||||||
|  |     @GET | ||||||
|  |     @Path("/{username}/permissions") | ||||||
|  |     @AuthProviderRESTExposure | ||||||
|  |     public APIPermissionSet getPermissions(@QueryParam("token") String authToken, | ||||||
|  |             @PathParam("username") String username)  | ||||||
|  |             throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|  |  | ||||||
|  |         // Get the user | ||||||
|  |         User user = userContext.getUserDirectory().get(username); | ||||||
|  |         if (user == null) | ||||||
|  |             throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\""); | ||||||
|  |  | ||||||
|  |         return new APIPermissionSet(user.getPermissions()); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Applies a given list of permission patches. Each patch specifies either | ||||||
|  |      * an "add" or a "remove" operation for a permission type, represented by | ||||||
|  |      * a string. Valid permission types depend on the path of each patch | ||||||
|  |      * operation, as the path dictates the permission being modified, such as | ||||||
|  |      * "/connectionPermissions/42" or "/systemPermissions". | ||||||
|  |      *  | ||||||
|  |      * @param authToken | ||||||
|  |      *     The authentication token that is used to authenticate the user | ||||||
|  |      *     performing the operation. | ||||||
|  |      *  | ||||||
|  |      * @param username | ||||||
|  |      *     The username of the user to modify the permissions of. | ||||||
|  |      * | ||||||
|  |      * @param patches | ||||||
|  |      *     The permission patches to apply for this request. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If a problem is encountered while modifying permissions. | ||||||
|  |      */ | ||||||
|  |     @PATCH | ||||||
|  |     @Path("/{username}/permissions") | ||||||
|  |     @AuthProviderRESTExposure | ||||||
|  |     public void patchPermissions(@QueryParam("token") String authToken, | ||||||
|  |             @PathParam("username") String username, | ||||||
|  |             List<APIPatch<String>> patches) throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         UserContext userContext = authenticationService.getUserContext(authToken); | ||||||
|  |          | ||||||
|  |         // Get the user directory | ||||||
|  |         Directory<String, User> userDirectory = userContext.getUserDirectory(); | ||||||
|  |  | ||||||
|  |         // Get the user | ||||||
|  |         User user = userContext.getUserDirectory().get(username); | ||||||
|  |         if (user == null) | ||||||
|  |             throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\""); | ||||||
|  |  | ||||||
|  |         // Apply all patch operations individually | ||||||
|  |         for (APIPatch<String> patch : patches) { | ||||||
|  |  | ||||||
|  |             Permission permission; | ||||||
|  |  | ||||||
|  |             String path = patch.getPath(); | ||||||
|  |  | ||||||
|  |             // Create connection permission if path has connection prefix | ||||||
|  |             if (path.startsWith(CONNECTION_PERMISSION_PATCH_PATH_PREFIX)) { | ||||||
|  |  | ||||||
|  |                 // Get identifier and type from patch operation | ||||||
|  |                 String identifier = path.substring(CONNECTION_PERMISSION_PATCH_PATH_PREFIX.length()); | ||||||
|  |                 ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue()); | ||||||
|  |  | ||||||
|  |                 // Create corresponding permission | ||||||
|  |                 permission = new ConnectionPermission(type, identifier); | ||||||
|  |                  | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Create connection group permission if path has connection group prefix | ||||||
|  |             else if (path.startsWith(CONNECTION_GROUP_PERMISSION_PATCH_PATH_PREFIX)) { | ||||||
|  |  | ||||||
|  |                 // Get identifier and type from patch operation | ||||||
|  |                 String identifier = path.substring(CONNECTION_GROUP_PERMISSION_PATCH_PATH_PREFIX.length()); | ||||||
|  |                 ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue()); | ||||||
|  |  | ||||||
|  |                 // Create corresponding permission | ||||||
|  |                 permission = new ConnectionGroupPermission(type, identifier); | ||||||
|  |                  | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Create user permission if path has user prefix | ||||||
|  |             else if (path.startsWith(USER_PERMISSION_PATCH_PATH_PREFIX)) { | ||||||
|  |  | ||||||
|  |                 // Get identifier and type from patch operation | ||||||
|  |                 String identifier = path.substring(USER_PERMISSION_PATCH_PATH_PREFIX.length()); | ||||||
|  |                 ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue()); | ||||||
|  |  | ||||||
|  |                 // Create corresponding permission | ||||||
|  |                 permission = new UserPermission(type, identifier); | ||||||
|  |                  | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Create system permission if path is system path | ||||||
|  |             else if (path.startsWith(SYSTEM_PERMISSION_PATCH_PATH)) { | ||||||
|  |  | ||||||
|  |                 // Get identifier and type from patch operation | ||||||
|  |                 SystemPermission.Type type = SystemPermission.Type.valueOf(patch.getValue()); | ||||||
|  |  | ||||||
|  |                 // Create corresponding permission | ||||||
|  |                 permission = new SystemPermission(type); | ||||||
|  |                  | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Otherwise, the path is not supported | ||||||
|  |             else | ||||||
|  |                 throw new HTTPException(Status.BAD_REQUEST, "Unsupported patch path: \"" + path + "\""); | ||||||
|  |  | ||||||
|  |             // Add or remove permission based on operation | ||||||
|  |             switch (patch.getOp()) { | ||||||
|  |  | ||||||
|  |                 // Add permission | ||||||
|  |                 case add: | ||||||
|  |                     user.addPermission(permission); | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|  |                 // Remove permission | ||||||
|  |                 case remove: | ||||||
|  |                     user.removePermission(permission); | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|  |                 // Unsupported patch operation | ||||||
|  |                 default: | ||||||
|  |                     throw new HTTPException(Status.BAD_REQUEST, | ||||||
|  |                             "Unsupported patch operation: \"" + patch.getOp() + "\""); | ||||||
|  |  | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         } // end for each patch operation | ||||||
|  |          | ||||||
|  |         // Save the permission changes | ||||||
|  |         userDirectory.update(user); | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -28,20 +28,33 @@ angular.module('auth').factory('authenticationService', ['$http', '$cookieStore' | |||||||
|  |  | ||||||
|     var service = {}; |     var service = {}; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The unique identifier of the local cookie which stores the user's | ||||||
|  |      * current authentication token and user ID. | ||||||
|  |      * | ||||||
|  |      * @type String | ||||||
|  |      */ | ||||||
|     var AUTH_COOKIE_ID = "GUAC_AUTH"; |     var AUTH_COOKIE_ID = "GUAC_AUTH"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Makes a request to authenticate a user using the token REST API endpoint,  |      * Makes a request to authenticate a user using the token REST API endpoint,  | ||||||
|      * returning a promise that can be used for processing the results of the call. |      * returning a promise that succeeds only if the login operation was | ||||||
|  |      * successful. The resulting authentication data can be retrieved later | ||||||
|  |      * via getCurrentToken() or getCurrentUserID(). | ||||||
|      *  |      *  | ||||||
|      * @param {String} username The username to log in with. |      * @param {String} username | ||||||
|      * @param {String} password The password to log in with. |      *     The username to log in with. | ||||||
|      * @returns {Promise} A promise for the HTTP call. |      * | ||||||
|  |      * @param {String} password | ||||||
|  |      *     The password to log in with. | ||||||
|  |      * | ||||||
|  |      * @returns {Promise} | ||||||
|  |      *     A promise which succeeds only if the login operation was successful. | ||||||
|      */ |      */ | ||||||
|     service.login = function login(username, password) { |     service.login = function login(username, password) { | ||||||
|         return $http({ |         return $http({ | ||||||
|             method: 'POST', |             method: 'POST', | ||||||
|             url: 'api/token', |             url: 'api/tokens', | ||||||
|             headers: { |             headers: { | ||||||
|                 'Content-Type': 'application/x-www-form-urlencoded' |                 'Content-Type': 'application/x-www-form-urlencoded' | ||||||
|             }, |             }, | ||||||
| @@ -59,14 +72,17 @@ angular.module('auth').factory('authenticationService', ['$http', '$cookieStore' | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Makes a request to logout a user using the login REST API endpoint,  |      * Makes a request to logout a user using the login REST API endpoint,  | ||||||
|      * returning a promise that can be used for processing the results of the call. |      * returning a promise succeeds only if the logout operation was | ||||||
|  |      * successful. | ||||||
|      *  |      *  | ||||||
|      * @returns {Promise} A promise for the HTTP call. |      * @returns {Promise} | ||||||
|  |      *     A promise which succeeds only if the logout operation was | ||||||
|  |      *     successful. | ||||||
|      */ |      */ | ||||||
|     service.logout = function logout() { |     service.logout = function logout() { | ||||||
|         return $http({ |         return $http({ | ||||||
|             method: 'DELETE', |             method: 'DELETE', | ||||||
|             url: 'api/token/' + encodeURIComponent(service.getCurrentToken()) |             url: 'api/tokens/' + encodeURIComponent(service.getCurrentToken()) | ||||||
|         }); |         }); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,4 +23,4 @@ | |||||||
| /** | /** | ||||||
|  * The module for code used to connect to a connection or balancing group. |  * The module for code used to connect to a connection or balancing group. | ||||||
|  */ |  */ | ||||||
| angular.module('client', ['auth', 'history']); | angular.module('client', ['auth', 'history', 'rest']); | ||||||
|   | |||||||
| @@ -132,8 +132,8 @@ angular.module('home').controller('clientController', ['$scope', '$routeParams', | |||||||
|         remaining: 15 |         remaining: 15 | ||||||
|     }; |     }; | ||||||
|      |      | ||||||
|     // Get DAO for reading connections and groups |     // Get services for reading connections and groups | ||||||
|     var connectionGroupDAO = $injector.get('connectionGroupDAO'); |     var connectionGroupService = $injector.get('connectionGroupService'); | ||||||
|     var connectionService      = $injector.get('connectionService'); |     var connectionService      = $injector.get('connectionService'); | ||||||
|     var ClientProperties       = $injector.get('ClientProperties'); |     var ClientProperties       = $injector.get('ClientProperties'); | ||||||
|  |  | ||||||
| @@ -176,7 +176,7 @@ angular.module('home').controller('clientController', ['$scope', '$routeParams', | |||||||
|  |  | ||||||
|         // Connection group |         // Connection group | ||||||
|         case 'g': |         case 'g': | ||||||
|             connectionGroupDAO.getConnectionGroup($routeParams.id).success(function (group) { |             connectionGroupService.getConnectionGroup($routeParams.id).success(function (group) { | ||||||
|                 $scope.connectionName = $scope.page.title = group.name; |                 $scope.connectionName = $scope.page.title = group.name; | ||||||
|             }); |             }); | ||||||
|             break; |             break; | ||||||
|   | |||||||
| @@ -315,15 +315,18 @@ angular.module('client').directive('guacClient', [function guacClient() { | |||||||
|              * CONNECT / RECONNECT |              * CONNECT / RECONNECT | ||||||
|              */ |              */ | ||||||
|  |  | ||||||
|             // Connect to given ID whenever ID changes |             /** | ||||||
|             $scope.$watch('id', function(id, previousID) { |              * Store the thumbnail of the currently connected client within | ||||||
|  |              * the connection history under the given ID. If the client is not | ||||||
|                 // If a client is already attached, ensure it is disconnected |              * connected, or if no ID is given, this function has no effect. | ||||||
|                 if (client) |              * | ||||||
|                     client.disconnect(); |              * @param {String} id | ||||||
|  |              *     The ID of the history entry to update. | ||||||
|  |              */ | ||||||
|  |             var updateHistoryEntry = function updateHistoryEntry(id) { | ||||||
|  |  | ||||||
|                 // Update stored thumbnail of previous connection  |                 // Update stored thumbnail of previous connection  | ||||||
|                 if (previousID && display && display.getWidth() > 0 && display.getHeight() > 0) { |                 if (id && display && display.getWidth() > 0 && display.getHeight() > 0) { | ||||||
|  |  | ||||||
|                     // Get screenshot |                     // Get screenshot | ||||||
|                     var canvas = display.flatten(); |                     var canvas = display.flatten(); | ||||||
| @@ -343,10 +346,22 @@ angular.module('client').directive('guacClient', [function guacClient() { | |||||||
|                         0, 0, thumbnail.width, thumbnail.height |                         0, 0, thumbnail.width, thumbnail.height | ||||||
|                     ); |                     ); | ||||||
|  |  | ||||||
|                     guacHistory.updateThumbnail(previousID, thumbnail.toDataURL("image/png")); |                     guacHistory.updateThumbnail(id, thumbnail.toDataURL("image/png")); | ||||||
|  |  | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             // Connect to given ID whenever ID changes | ||||||
|  |             $scope.$watch('id', function(id, previousID) { | ||||||
|  |  | ||||||
|  |                 // If a client is already attached, ensure it is disconnected | ||||||
|  |                 if (client) | ||||||
|  |                     client.disconnect(); | ||||||
|  |  | ||||||
|  |                 // Update stored thumbnail of previous connection | ||||||
|  |                 updateHistoryEntry(previousID); | ||||||
|  |  | ||||||
|                 // Only proceed if a new client is attached |                 // Only proceed if a new client is attached | ||||||
|                 if (!id) |                 if (!id) | ||||||
|                     return; |                     return; | ||||||
| @@ -385,6 +400,14 @@ angular.module('client').directive('guacClient', [function guacClient() { | |||||||
|  |  | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|  |             // Clean up when client directive is destroyed | ||||||
|  |             $scope.$on('$destroy', function destroyClient() { | ||||||
|  |  | ||||||
|  |                 // Update stored thumbnail of current connection | ||||||
|  |                 updateHistoryEntry($scope.id); | ||||||
|  |  | ||||||
|  |             }); | ||||||
|  |  | ||||||
|             /* |             /* | ||||||
|              * MOUSE EMULATION |              * MOUSE EMULATION | ||||||
|              */ |              */ | ||||||
|   | |||||||
| @@ -33,10 +33,7 @@ | |||||||
|     <div id="text-input"><div id="text-input-field"><div id="sent-history"></div><textarea rows="1" id="target"></textarea></div><div id="text-input-buttons"><button class="key" data-keysym="0xFFE3" data-sticky="true">{{'client.ctrl' | translate}}</button><button class="key" data-keysym="0xFFE9" data-sticky="true">{{'client.alt' | translate}}</button><button class="key" data-keysym="0xFF1B">{{'client.esc' | translate}}</button><button class="key" data-keysym="0xFF09">{{'client.tab' | translate}}</button></div></div> |     <div id="text-input"><div id="text-input-field"><div id="sent-history"></div><textarea rows="1" id="target"></textarea></div><div id="text-input-buttons"><button class="key" data-keysym="0xFFE3" data-sticky="true">{{'client.ctrl' | translate}}</button><button class="key" data-keysym="0xFFE9" data-sticky="true">{{'client.alt' | translate}}</button><button class="key" data-keysym="0xFF1B">{{'client.esc' | translate}}</button><button class="key" data-keysym="0xFF09">{{'client.tab' | translate}}</button></div></div> | ||||||
|  |  | ||||||
|     <!-- Dimensional clone of viewport --> |     <!-- Dimensional clone of viewport --> | ||||||
|     <div id="viewportClone"/> |     <div id="viewportClone"></div> | ||||||
|  |  | ||||||
|     <!-- Notification area --> |  | ||||||
|     <div id="notificationArea"/> |  | ||||||
|  |  | ||||||
|     <!-- Menu --> |     <!-- Menu --> | ||||||
|     <div ng-class="{open: menuShown}" id="menu"> |     <div ng-class="{open: menuShown}" id="menu"> | ||||||
| @@ -108,8 +105,8 @@ | |||||||
|  |  | ||||||
|     <!-- Images which should be preloaded --> |     <!-- Images which should be preloaded --> | ||||||
|     <div id="preload"> |     <div id="preload"> | ||||||
|         <img src="images/action-icons/guac-close.png"/> |         <img src="images/action-icons/guac-close.png" alt=""/> | ||||||
|         <img src="images/progress.png"/> |         <img src="images/progress.png" alt=""/> | ||||||
|     </div> |     </div> | ||||||
|      |      | ||||||
|     <ng-include src="app/client/template/clientError.html"/> |     <ng-include src="app/client/template/clientError.html"/> | ||||||
|   | |||||||
| @@ -1,148 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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 for operating on connections via the REST API. |  | ||||||
|  */ |  | ||||||
| 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 provides the corresponding @link{Connection} if successful. |  | ||||||
|      *  |  | ||||||
|      * @param {String} id The ID of the connection. |  | ||||||
|      * @returns {Promise.<Connection>} |  | ||||||
|      *     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()); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 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. |  | ||||||
|      *  |  | ||||||
|      * @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.<Connection[]>} |  | ||||||
|      *     A promise which will resolve with an array of @link{Connection} |  | ||||||
|      *     objects upon success. |  | ||||||
|      */ |  | ||||||
|     service.getConnections = function getConnections(parentID) { |  | ||||||
|          |  | ||||||
|         var parentIDParam = ""; |  | ||||||
|         if(parentID !== undefined) |  | ||||||
|             parentIDParam = "&parentID=" + parentID; |  | ||||||
|          |  | ||||||
|         return $http.get("api/connection?token=" + authenticationService.getCurrentToken() + parentIDParam); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * 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 {Connection} connection The connection to update |  | ||||||
|      *                           |  | ||||||
|      * @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; |  | ||||||
|          |  | ||||||
|         // This is a new connection |  | ||||||
|         if(!connectionToSave.identifier) { |  | ||||||
|             return $http.post("api/connection/?token=" + authenticationService.getCurrentToken(), connectionToSave).success( |  | ||||||
|                 function setConnectionID(connectionID){ |  | ||||||
|                     // Set the identifier on the new connection |  | ||||||
|                     connection.identifier = connectionID; // FIXME: Functions with side effects = bad |  | ||||||
|                     return connectionID; // FIXME: Why? Where does this value go? |  | ||||||
|                 }); |  | ||||||
|         } else { |  | ||||||
|             return $http.post( |  | ||||||
|                 "api/connection/" + connectionToSave.identifier +  |  | ||||||
|                 "?token=" + authenticationService.getCurrentToken(),  |  | ||||||
|             connectionToSave); |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * FIXME: Why is this different from save? |  | ||||||
|      *  |  | ||||||
|      * 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 which will succeed if and only if the |  | ||||||
|      *     move operation is successful. |  | ||||||
|      */ |  | ||||||
|     service.moveConnection = function moveConnection(connection) { |  | ||||||
|          |  | ||||||
|         return $http.put( |  | ||||||
|             "api/connection/" + connection.identifier +  |  | ||||||
|             "?token=" + authenticationService.getCurrentToken() +  |  | ||||||
|             "&parentID=" + connection.parentIdentifier,  |  | ||||||
|         connection); |  | ||||||
|          |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * 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 {Connection} connection The connection to delete |  | ||||||
|      *                           |  | ||||||
|      * @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']( |  | ||||||
|             "api/connection/" + connection.identifier +  |  | ||||||
|             "?token=" + authenticationService.getCurrentToken()); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     return service; |  | ||||||
| }]); |  | ||||||
| @@ -1,130 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * The DAO for connection group operations agains the REST API. |  | ||||||
|  */ |  | ||||||
| angular.module('connectionGroup').factory('connectionGroupDAO', ['$http', 'authenticationService', |  | ||||||
|         function connectionGrouDAO($http, authenticationService) { |  | ||||||
|              |  | ||||||
|     /** |  | ||||||
|      * The ID of the root connection group. |  | ||||||
|      */ |  | ||||||
|     var ROOT_CONNECTION_GROUP_ID = "ROOT"; |  | ||||||
|              |  | ||||||
|     var service = {}; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to get the list of connection groups, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {string} parentID The parent ID for the connection group. |  | ||||||
|      *                          If not passed in, it will query a list of the  |  | ||||||
|      *                          connection groups in the root group. |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.getConnectionGroups = function getConnectionGroups(parentID) { |  | ||||||
|          |  | ||||||
|         var parentIDParam = ""; |  | ||||||
|         if(parentID !== undefined) |  | ||||||
|             parentIDParam = "&parentID=" + parentID; |  | ||||||
|          |  | ||||||
|         return $http.get("api/connectionGroup?token=" + authenticationService.getCurrentToken() + parentIDParam); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to get an individual connection group, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {string} connectionGroupID The ID for the connection group. |  | ||||||
|      *                                   If not passed in, it will query the |  | ||||||
|      *                                   root connection group. |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.getConnectionGroup = function getConnectionGroup(connectionGroupID) { |  | ||||||
|          |  | ||||||
|         // Use the root connection group ID if no ID is passed in |  | ||||||
|         connectionGroupID = connectionGroupID || ROOT_CONNECTION_GROUP_ID; |  | ||||||
|          |  | ||||||
|         return $http.get("api/connectionGroup/" + connectionGroupID + "?token=" + authenticationService.getCurrentToken()); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to save a connection group, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {object} connectionGroup The connection group to update |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.saveConnectionGroup = function saveConnectionGroup(connectionGroup) { |  | ||||||
|         // This is a new connection group |  | ||||||
|         if(!connectionGroup.identifier) { |  | ||||||
|             return $http.post("api/connectionGroup/?token=" + authenticationService.getCurrentToken(), connectionGroup).success( |  | ||||||
|                 function setConnectionGroupID(connectionGroupID){ |  | ||||||
|                     // Set the identifier on the new connection |  | ||||||
|                     connectionGroup.identifier = connectionGroupID; |  | ||||||
|                     return connectionGroupID; |  | ||||||
|                 }); |  | ||||||
|         } else { |  | ||||||
|             return $http.post( |  | ||||||
|                 "api/connectionGroup/" + connectionGroup.identifier +  |  | ||||||
|                 "?token=" + authenticationService.getCurrentToken(),  |  | ||||||
|             connectionGroup); |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to move a connection group to a different group, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {object} connectionGroup The connection group to move.  |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.moveConnectionGroup = function moveConnectionGroup(connectionGroup) { |  | ||||||
|          |  | ||||||
|         return $http.put( |  | ||||||
|             "api/connectionGroup/" + connectionGroup.identifier +  |  | ||||||
|             "?token=" + authenticationService.getCurrentToken() +  |  | ||||||
|             "&parentID=" + connectionGroup.parentIdentifier,  |  | ||||||
|         connectionGroup); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to delete a connection group, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {object} connectionGroup The connection group to delete |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.deleteConnectionGroup = function deleteConnectionGroup(connectionGroup) { |  | ||||||
|         return $http['delete']( |  | ||||||
|             "api/connectionGroup/" + connectionGroup.identifier +  |  | ||||||
|             "?token=" + authenticationService.getCurrentToken()); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     return service; |  | ||||||
| }]); |  | ||||||
| @@ -1,231 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * A service for performing useful connection group related functionaltiy. |  | ||||||
|  */ |  | ||||||
| angular.module('connectionGroup').factory('connectionGroupService', ['$injector', function connectionGroupService($injector) { |  | ||||||
|              |  | ||||||
|     var connectionGroupDAO              = $injector.get('connectionGroupDAO'); |  | ||||||
|     var connectionService               = $injector.get('connectionService'); |  | ||||||
|     var permissionCheckService          = $injector.get('permissionCheckService'); |  | ||||||
|     var $q                              = $injector.get('$q'); |  | ||||||
|     var displayObjectPreparationService = $injector.get('displayObjectPreparationService'); |  | ||||||
|              |  | ||||||
|     var service = {}; |  | ||||||
|          |  | ||||||
|     // Add all groups from this group to the parent group child list |  | ||||||
|     function addToParent(connectionGroup, parentGroup, context, includeConnections) { |  | ||||||
|          |  | ||||||
|         // Include connections by default |  | ||||||
|         if(typeof includeConnections === 'undefined') |  | ||||||
|             includeConnections = true; |  | ||||||
|          |  | ||||||
|         parentGroup.children.push(connectionGroup); |  | ||||||
|          |  | ||||||
|         // Prepare this group for display |  | ||||||
|         displayObjectPreparationService.prepareConnectionGroup(connectionGroup); |  | ||||||
|          |  | ||||||
|         if(includeConnections) { |  | ||||||
|             // Get all connections in the group and add them under this connection group |  | ||||||
|             context.openRequest(); |  | ||||||
|             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]); |  | ||||||
|                 } |  | ||||||
|                 context.closeRequest(); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Get all connection groups in the group and repeat |  | ||||||
|         context.openRequest(); |  | ||||||
|         connectionGroupDAO.getConnectionGroups(connectionGroup.identifier).success(function fetchConnectionGroups(connectionGroups) { |  | ||||||
|             for(var i = 0; i < connectionGroups.length; i++) { |  | ||||||
|                 addToParent(connectionGroups[i], connectionGroup, context, includeConnections); |  | ||||||
|             } |  | ||||||
|             context.closeRequest(); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Queries all connections and connection groups under the connection group  |  | ||||||
|      * with the provided parent ID, and returns them in a heirarchical structure |  | ||||||
|      * with convinient display properties set on the objects. |  | ||||||
|      *  |  | ||||||
|      * @param {array} items The root list of connections and groups. Should be an |  | ||||||
|      *                      initally empty array that will get filled in as the |  | ||||||
|      *                      connections and groups are loaded. |  | ||||||
|      *  |  | ||||||
|      * @param {string} parentID The parent ID for the connection group. |  | ||||||
|      *                          If not passed in, it will begin with  |  | ||||||
|      *                          the root connection group. |  | ||||||
|      *  |  | ||||||
|      * @param {boolean} includeConnections Whether or not to include connections |  | ||||||
|      *                                     in the structure. Defaults to true. |  | ||||||
|      *  |  | ||||||
|      * @param {boolean} includeRoot Whether or not to include the root connection group |  | ||||||
|      *                              in the structure. Defaults to false. |  | ||||||
|      *                           |  | ||||||
|      * @return {promise} A promise that will be fulfilled when all connections |  | ||||||
|      *                   and groups have been loaded. |  | ||||||
|      */ |  | ||||||
|     service.getAllGroupsAndConnections = function getAllGroupsAndConnections(items, parentID, includeConnections, includeRoot) { |  | ||||||
|          |  | ||||||
|         // Include connections by default |  | ||||||
|         if(typeof includeConnections === 'undefined') |  | ||||||
|             includeConnections = true; |  | ||||||
|          |  | ||||||
|         var context = { |  | ||||||
|             // The number of requets to the server currently open |  | ||||||
|             openRequests        : 0, |  | ||||||
|  |  | ||||||
|             // Create the promise |  | ||||||
|             finishedFetching    : $q.defer(), |  | ||||||
|              |  | ||||||
|             // Notify the caller that the promise has been completed |  | ||||||
|             complete            : function complete() { |  | ||||||
|                 this.finishedFetching.resolve(items); |  | ||||||
|             }, |  | ||||||
|              |  | ||||||
|             /** |  | ||||||
|              * Indicate that a request has been started. |  | ||||||
|              */  |  | ||||||
|             openRequest         : function openRequest() { |  | ||||||
|                 this.openRequests++; |  | ||||||
|             }, |  | ||||||
|              |  | ||||||
|             /** |  | ||||||
|              * Indicate that a request has been completed. If this was the last |  | ||||||
|              * open request, fulfill the promise. |  | ||||||
|              */  |  | ||||||
|             closeRequest        : function closeRequest() { |  | ||||||
|                 if(--this.openRequests === 0) |  | ||||||
|                     this.complete(); |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|          |  | ||||||
|         // Include the root only if it was asked for |  | ||||||
|         if(includeRoot) { |  | ||||||
|             context.openRequest(); |  | ||||||
|             connectionGroupDAO.getConnectionGroup(parentID).success(function setRootGroup (rootGroup) { |  | ||||||
|                 items.push(rootGroup); |  | ||||||
|                 rootGroup.children = []; |  | ||||||
|                 getChildrenOfRootGroup(rootGroup.children); |  | ||||||
|                 context.closeRequest(); |  | ||||||
|             }); |  | ||||||
|         } else { |  | ||||||
|             getChildrenOfRootGroup(items); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         // Get the children of the root group |  | ||||||
|         function getChildrenOfRootGroup(children) { |  | ||||||
|             context.openRequest(); |  | ||||||
|             connectionGroupDAO.getConnectionGroups(parentID).success(function fetchRootConnectionGroups(connectionGroups) { |  | ||||||
|                 for(var i = 0; i < connectionGroups.length; i++) { |  | ||||||
|                     addToParent(connectionGroups[i], {children: children}, context, includeConnections); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if(includeConnections) { |  | ||||||
|                     // Get all connections in the root group and add them under this connection group |  | ||||||
|                     context.openRequest(); |  | ||||||
|                     connectionService.getConnections().success(function fetchRootConnections(connections) { |  | ||||||
|                         for(var i = 0; i < connections.length; i++) { |  | ||||||
|                              |  | ||||||
|                             // Prepare this connection for display |  | ||||||
|                             displayObjectPreparationService.prepareConnection(connections[i]); |  | ||||||
|                              |  | ||||||
|                             children.push(connections[i]); |  | ||||||
|                         } |  | ||||||
|                         context.closeRequest(); |  | ||||||
|                     }); |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                 context.closeRequest(); |  | ||||||
|             });      |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         // Return the promise |  | ||||||
|         return context.finishedFetching.promise; |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Filters the list of connections and groups using the provided permissions. |  | ||||||
|      *  |  | ||||||
|      * @param {array} items The heirarchical list of groups and connections. |  | ||||||
|      *  |  | ||||||
|      * @param {object} permissionList The list of permissions to use  |  | ||||||
|      *                                when filtering. |  | ||||||
|      *  |  | ||||||
|      * @param {object} permissionCriteria A map of object type to permission type(s) |  | ||||||
|      *                                    required for that object type.  |  | ||||||
|      *                           |  | ||||||
|      * @return {array} The filtered list. |  | ||||||
|      */ |  | ||||||
|     service.filterConnectionsAndGroupByPermission = function filterConnectionsAndGroupByPermission(items, permissionList, permissionCriteria) { |  | ||||||
|         var requiredConnectionPermission      = permissionCriteria.CONNECTION; |  | ||||||
|         var requiredConnectionGroupPermission = permissionCriteria.CONNECTION_GROUP; |  | ||||||
|          |  | ||||||
|         for(var i = 0; i < items.length; i++) { |  | ||||||
|             var item = items[i]; |  | ||||||
|              |  | ||||||
|             if(item.isConnection && requiredConnectionPermission) { |  | ||||||
|                  |  | ||||||
|                 /* |  | ||||||
|                  * If item is a connection and a permission is required for this |  | ||||||
|                  * item, check now to see if the permission exists. If not, |  | ||||||
|                  * remove the item. |  | ||||||
|                  */ |  | ||||||
|                 if(!permissionCheckService.checkPermission(permissionList,  |  | ||||||
|                         "CONNECTION", item.identifier, requiredConnectionPermission)) { |  | ||||||
|                     items.splice(i, 1); |  | ||||||
|                     continue; |  | ||||||
|                 }  |  | ||||||
|             }  |  | ||||||
|             else { |  | ||||||
|                  |  | ||||||
|                 /* |  | ||||||
|                  * If item is a group and a permission is required for this |  | ||||||
|                  * item, check now to see if the permission exists. If not, |  | ||||||
|                  * remove the item. |  | ||||||
|                  */ |  | ||||||
|                 if(requiredConnectionGroupPermission) { |  | ||||||
|                     if(!permissionCheckService.checkPermission(permissionList,  |  | ||||||
|                             "CONNECTION_GROUP", item.identifier, requiredConnectionGroupPermission)) { |  | ||||||
|                         items.splice(i, 1); |  | ||||||
|                         continue; |  | ||||||
|                     }     |  | ||||||
|                 } |  | ||||||
|                  |  | ||||||
|                 // Filter the children of this connection group as well |  | ||||||
|                 if(item.children && item.children.length) |  | ||||||
|                     service.filterConnectionsAndGroupByPermission(items.children); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         return items; |  | ||||||
|          |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     return service; |  | ||||||
| }]); |  | ||||||
| @@ -0,0 +1,72 @@ | |||||||
|  | /* | ||||||
|  |  * 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. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A directive which displays the contents of a connection group. | ||||||
|  |  */ | ||||||
|  | angular.module('groupList').directive('guacGroupList', [function guacGroupList() { | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |         restrict: 'E', | ||||||
|  |         replace: true, | ||||||
|  |         scope: { | ||||||
|  |  | ||||||
|  |             /** | ||||||
|  |              * The connection group to display. | ||||||
|  |              * | ||||||
|  |              * @type ConnectionGroup|Object  | ||||||
|  |              */ | ||||||
|  |             connectionGroup : '=' | ||||||
|  |  | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         templateUrl: 'app/groupList/templates/guacGroupList.html', | ||||||
|  |         controller: ['$scope', '$injector', '$interval', function guacGroupListController($scope, $injector, $interval) { | ||||||
|  |  | ||||||
|  |             // Get required types | ||||||
|  |             var GroupListItem = $injector.get('GroupListItem'); | ||||||
|  |  | ||||||
|  |             // Set contents whenever the connection group is assigned or changed | ||||||
|  |             $scope.$watch("connectionGroup", function setContents(connectionGroup) { | ||||||
|  |  | ||||||
|  |                 if (connectionGroup) | ||||||
|  |                     $scope.rootItem = GroupListItem.fromConnectionGroup(connectionGroup); | ||||||
|  |                 else | ||||||
|  |                     $scope.rootItem = null; | ||||||
|  |  | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             /** | ||||||
|  |              * Toggle the open/closed status of a group list item. | ||||||
|  |              *  | ||||||
|  |              * @param {GroupListItem} groupListItem | ||||||
|  |              *     The list item to expand, which should represent a | ||||||
|  |              *     connection group. | ||||||
|  |              */ | ||||||
|  |             $scope.toggleExpanded = function toggleExpanded(groupListItem) { | ||||||
|  |                 groupListItem.expanded = !groupListItem.expanded; | ||||||
|  |             }; | ||||||
|  |              | ||||||
|  |         }] | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  | }]); | ||||||
| @@ -21,6 +21,7 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * The module for code relating to connection groups. |  * Module for displaying the contents of a connection group, allowing the user | ||||||
|  |  * to select individual connections or groups. | ||||||
|  */ |  */ | ||||||
| angular.module('connectionGroup', ['auth', 'util', 'connection']); | angular.module('groupList', ['rest']); | ||||||
| @@ -19,8 +19,3 @@ | |||||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  * THE SOFTWARE. |  * THE SOFTWARE. | ||||||
|  */ |  */ | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * A module for code relating to users. |  | ||||||
|  */ |  | ||||||
| angular.module('user', ['auth']); |  | ||||||
| @@ -0,0 +1,71 @@ | |||||||
|  | <div class="group-list"> | ||||||
|  |     <!-- | ||||||
|  |        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. | ||||||
|  |     --> | ||||||
|  |  | ||||||
|  |     <script type="text/ng-template" id="nestedGroup.html"> | ||||||
|  |  | ||||||
|  |         <!-- Connection --> | ||||||
|  |         <div class="connection" ng-show="item.isConnection"> | ||||||
|  |             <a ng-href="#/client/c/{{item.identifier}}"> | ||||||
|  |                 <div class="caption"> | ||||||
|  |  | ||||||
|  |                     <!-- Connection icon --> | ||||||
|  |                     <div class="protocol"> | ||||||
|  |                         <div class="icon type" ng-class="item.protocol"></div> | ||||||
|  |                     </div> | ||||||
|  |  | ||||||
|  |                     <!-- Connection name --> | ||||||
|  |                     <span class="name">{{item.name}}</span> | ||||||
|  |  | ||||||
|  |                 </div> | ||||||
|  |             </a> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <!-- Connection group --> | ||||||
|  |         <div class="group" ng-show="item.isConnectionGroup"> | ||||||
|  |  | ||||||
|  |             <div class="caption"> | ||||||
|  |  | ||||||
|  |                 <!-- Connection group icon --> | ||||||
|  |                 <div class="icon group type" ng-click="toggleExpanded(item)" | ||||||
|  |                      ng-class="{expanded: item.isExpanded, empty: !item.children.length, balancer: item.isBalancing}"></div> | ||||||
|  |  | ||||||
|  |                 <!-- Connection group name --> | ||||||
|  |                 <span class="name"> | ||||||
|  |                     <a ng-show="item.isBalancing" ng-href="#/client/g/{{item.identifier}}">{{item.name}}</a> | ||||||
|  |                     <span ng-show="!item.isBalancing">{{item.name}}</span> | ||||||
|  |                 </span> | ||||||
|  |  | ||||||
|  |             </div> | ||||||
|  |  | ||||||
|  |             <!-- Children of this group --> | ||||||
|  |             <div class="children" ng-show="item.isExpanded"> | ||||||
|  |                 <div class="list-item" ng-repeat="item in item.children | orderBy : 'name'" ng-include="'nestedGroup.html'"> | ||||||
|  |             </div> | ||||||
|  |  | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |     </script> | ||||||
|  |  | ||||||
|  |     <div class="list-item" ng-repeat="item in rootItem.children | orderBy : 'name'" ng-include="'nestedGroup.html'"></div> | ||||||
|  |  | ||||||
|  | </div> | ||||||
							
								
								
									
										181
									
								
								guacamole/src/main/webapp/app/groupList/types/GroupListItem.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								guacamole/src/main/webapp/app/groupList/types/GroupListItem.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | |||||||
|  | /* | ||||||
|  |  * 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. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Provides the GroupListItem class definition. | ||||||
|  |  */ | ||||||
|  | angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', function defineGroupListItem(ConnectionGroup) { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new GroupListItem, initializing the properties of that | ||||||
|  |      * GroupListItem with the corresponding properties of the given template. | ||||||
|  |      * | ||||||
|  |      * @constructor | ||||||
|  |      * @param {GroupListItem|Object} [template={}] | ||||||
|  |      *     The object whose properties should be copied within the new | ||||||
|  |      *     GroupListItem. | ||||||
|  |      */ | ||||||
|  |     var GroupListItem = function GroupListItem(template) { | ||||||
|  |  | ||||||
|  |         // Use empty object by default | ||||||
|  |         template = template || {}; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The unique identifier associated with the connection or connection | ||||||
|  |          * group this item represents. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.identifier = template.identifier; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The human-readable display name of this item. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.name = template.name; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The unique identifier of the protocol, if this item represents a | ||||||
|  |          * connection. If this item does not represent a connection, this | ||||||
|  |          * property is not applicable. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.protocol = template.protocol; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * All children items of this item. If this item contains no children, | ||||||
|  |          * this will be an empty array. | ||||||
|  |          * | ||||||
|  |          * @type GroupListItem[] | ||||||
|  |          */ | ||||||
|  |         this.children = template.children || []; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Whether this item represents a connection. If this item represents | ||||||
|  |          * a connection group, this MUST be false. | ||||||
|  |          * | ||||||
|  |          * @type Boolean | ||||||
|  |          */ | ||||||
|  |         this.isConnection = template.isConnection; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Whether this item represents a connection group. If this item | ||||||
|  |          * represents a connection, this MUST be false. | ||||||
|  |          * | ||||||
|  |          * @type Boolean | ||||||
|  |          */ | ||||||
|  |         this.isConnectionGroup = template.isConnectionGroup; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Whether this item represents a balancing connection group. | ||||||
|  |          * | ||||||
|  |          * @type Boolean | ||||||
|  |          */ | ||||||
|  |         this.isBalancing = template.isBalancing; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Whether the children items should be displayed. | ||||||
|  |          * | ||||||
|  |          * @type Boolean | ||||||
|  |          */ | ||||||
|  |         this.isExpanded = template.isExpanded; | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new GroupListItem using the contents of the given connection. | ||||||
|  |      * | ||||||
|  |      * @param {ConnectionGroup} connection | ||||||
|  |      *     The connection whose contents should be represented by the new | ||||||
|  |      *     GroupListItem. | ||||||
|  |      * | ||||||
|  |      * @returns {GroupListItem} | ||||||
|  |      *     A new GroupListItem which represents the given connection. | ||||||
|  |      */ | ||||||
|  |     GroupListItem.fromConnection = function fromConnection(connection) { | ||||||
|  |  | ||||||
|  |         // Return item representing the given connection | ||||||
|  |         return new GroupListItem({ | ||||||
|  |  | ||||||
|  |             // Identifying information | ||||||
|  |             name       : connection.name, | ||||||
|  |             identifier : connection.identifier, | ||||||
|  |             protocol   : connection.protocol, | ||||||
|  |  | ||||||
|  |             // Type information | ||||||
|  |             isConnection      : true, | ||||||
|  |             isConnectionGroup : false | ||||||
|  |  | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new GroupListItem using the contents and descendants of the | ||||||
|  |      * given connection group. | ||||||
|  |      * | ||||||
|  |      * @param {ConnectionGroup} connectionGroup | ||||||
|  |      *     The connection group whose contents and descendants should be | ||||||
|  |      *     represented by the new GroupListItem and its descendants. | ||||||
|  |      * | ||||||
|  |      * @returns {GroupListItem} | ||||||
|  |      *     A new GroupListItem which represents the given connection group, | ||||||
|  |      *     including all descendants. | ||||||
|  |      */ | ||||||
|  |     GroupListItem.fromConnectionGroup = function fromConnectionGroup(connectionGroup) { | ||||||
|  |  | ||||||
|  |         var children = []; | ||||||
|  |  | ||||||
|  |         // Add any child connections | ||||||
|  |         connectionGroup.childConnections.forEach(function addChildConnection(child) { | ||||||
|  |             children.push(GroupListItem.fromConnection(child)); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         // Add any child groups  | ||||||
|  |         connectionGroup.childConnectionGroups.forEach(function addChildGroup(child) { | ||||||
|  |             children.push(GroupListItem.fromConnectionGroup(child)); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         // Return item representing the given connection group | ||||||
|  |         return new GroupListItem({ | ||||||
|  |  | ||||||
|  |             // Identifying information | ||||||
|  |             name       : connectionGroup.name, | ||||||
|  |             identifier : connectionGroup.identifier, | ||||||
|  |  | ||||||
|  |             // Type information | ||||||
|  |             isConnection      : false, | ||||||
|  |             isConnectionGroup : true, | ||||||
|  |             isBalancing       : connectionGroup.type === ConnectionGroup.Type.BALANCING, | ||||||
|  |  | ||||||
|  |             // Already-converted children | ||||||
|  |             children : children | ||||||
|  |  | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return GroupListItem; | ||||||
|  |  | ||||||
|  | }]); | ||||||
| @@ -37,7 +37,8 @@ angular.module('history').factory('HistoryEntry', [function defineHistoryEntry() | |||||||
|     var HistoryEntry = function HistoryEntry(id, thumbnail) { |     var HistoryEntry = function HistoryEntry(id, thumbnail) { | ||||||
|  |  | ||||||
|         /** |         /** | ||||||
|          * The ID of the connection associated with this history entry. |          * The ID of the connection associated with this history entry, | ||||||
|  |          * including type prefix. | ||||||
|          */ |          */ | ||||||
|         this.id = id; |         this.id = id; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -26,70 +26,22 @@ | |||||||
| angular.module('home').controller('homeController', ['$scope', '$injector',  | angular.module('home').controller('homeController', ['$scope', '$injector',  | ||||||
|         function homeController($scope, $injector) { |         function homeController($scope, $injector) { | ||||||
|  |  | ||||||
|     // The parameter name for getting the history from local storage |     // Get required types | ||||||
|     var GUAC_HISTORY_STORAGE_KEY = "GUAC_HISTORY"; |     var ConnectionGroup = $injector.get("ConnectionGroup"); | ||||||
|              |              | ||||||
|     // Get the dependencies commonJS style |     // Get required services | ||||||
|     var connectionGroupService  = $injector.get("connectionGroupService"); |     var connectionGroupService  = $injector.get("connectionGroupService"); | ||||||
|     var guacHistory             = $injector.get("guacHistory"); |  | ||||||
|      |  | ||||||
|     // All the connections and connection groups in root |  | ||||||
|     $scope.connectionsAndGroups = []; |  | ||||||
|      |  | ||||||
|     // All valid recent connections |  | ||||||
|     $scope.recentConnections = []; |  | ||||||
|      |      | ||||||
|     // Set status to loading until we have all the connections and groups loaded |     // Set status to loading until we have all the connections and groups loaded | ||||||
|     $scope.loading = true; |     $scope.loading = true; | ||||||
|  |  | ||||||
|     /* Fetch all connections and groups, then find which recent connections |     // Retrieve root group and all descendants | ||||||
|      * still refer to valid connections and groups. |     connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER) | ||||||
|      */ |     .success(function rootGroupRetrieved(rootConnectionGroup) { | ||||||
|     connectionGroupService.getAllGroupsAndConnections($scope.connectionsAndGroups) |  | ||||||
|     .then(function findRecentConnections() { |  | ||||||
|          |  | ||||||
|         // TODONT: Munch the guacHistory recentConnections list into a legacy-style object |  | ||||||
|         var recentConnections = {}; |  | ||||||
|         for (var i=0; i < guacHistory.recentConnections.length; i++) { |  | ||||||
|             var entry = guacHistory.recentConnections[i]; |  | ||||||
|             recentConnections[encodeURIComponent(entry.id)] = { |  | ||||||
|                 id        : entry.id, |  | ||||||
|                 thumbnail : entry.thumbnail |  | ||||||
|             }; |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         // Figure out which recent connection entries are valid |  | ||||||
|         $scope.connectionsAndGroups.forEach(function findValidEntries (connectionOrGroup) { |  | ||||||
|              |  | ||||||
|             var type = connectionOrGroup.isConnection ? "c" : "g"; |  | ||||||
|              |  | ||||||
|             // Find the unique ID to index into the recent connections |  | ||||||
|             var uniqueId = encodeURIComponent( |  | ||||||
|                 type + "/" + connectionOrGroup.identifier |  | ||||||
|             ); |  | ||||||
|      |  | ||||||
|             /*  |  | ||||||
|              * If it's a valid recent connection, add it to the list, |  | ||||||
|              * along with enough information to make a connection url. |  | ||||||
|              */ |  | ||||||
|             var recentConnection = recentConnections[uniqueId]; |  | ||||||
|             if(recentConnection) { |  | ||||||
|                 recentConnection.type = type; |  | ||||||
|                 recentConnection.id   = connectionOrGroup.identifier; |  | ||||||
|                 $scope.recentConnections.push(recentConnection); |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|  |         $scope.rootConnectionGroup = rootConnectionGroup; | ||||||
|         $scope.loading = false; |         $scope.loading = false; | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     /** |     }); | ||||||
|      * Toggle the open/closed status of the connectionGroup. |  | ||||||
|      *  |  | ||||||
|      * @param {object} connectionGroup The connection group to toggle. |  | ||||||
|      */ |  | ||||||
|     $scope.toggleExpanded = function toggleExpanded(connectionGroup) { |  | ||||||
|         connectionGroup.expanded = !connectionGroup.expanded; |  | ||||||
|     }; |  | ||||||
|      |      | ||||||
| }]); | }]); | ||||||
|   | |||||||
| @@ -0,0 +1,115 @@ | |||||||
|  | /* | ||||||
|  |  * 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. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A directive which displays the contents of a connection group. | ||||||
|  |  */ | ||||||
|  | angular.module('home').directive('guacRecentConnections', [function guacRecentConnections() { | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |         restrict: 'E', | ||||||
|  |         replace: true, | ||||||
|  |         scope: { | ||||||
|  |  | ||||||
|  |             /** | ||||||
|  |              * The root connection group, and all visible descendants. | ||||||
|  |              * Recent connections will only be shown if they exist within this | ||||||
|  |              * hierarchy, regardless of their existence within the history. | ||||||
|  |              * | ||||||
|  |              * @type ConnectionGroup | ||||||
|  |              */ | ||||||
|  |             rootGroup : '=' | ||||||
|  |  | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         templateUrl: 'app/home/templates/guacRecentConnections.html', | ||||||
|  |         controller: ['$scope', '$injector', 'guacHistory', 'RecentConnection', | ||||||
|  |             function guacRecentConnectionsController($scope, $injector, guacHistory, RecentConnection) { | ||||||
|  |  | ||||||
|  |             var visibleObjects = {}; | ||||||
|  |  | ||||||
|  |             /** | ||||||
|  |              * Adds the given connection to the internal set of visible | ||||||
|  |              * objects. | ||||||
|  |              *  | ||||||
|  |              * @param {Connection} connection | ||||||
|  |              *     The connection to add to the internal set of visible objects. | ||||||
|  |              */ | ||||||
|  |             var addVisibleConnection = function addVisibleConnection(connection) { | ||||||
|  |  | ||||||
|  |                 // Add given connection to set of visible objects | ||||||
|  |                 visibleObjects['c/' + connection.identifier] = connection; | ||||||
|  |  | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             /** | ||||||
|  |              * Adds the given connection group to the internal set of visible | ||||||
|  |              * objects, along with any descendants. | ||||||
|  |              *  | ||||||
|  |              * @param {ConnectionGroup} connectionGroup | ||||||
|  |              *     The connection group to add to the internal set of visible | ||||||
|  |              *     objects, along with any descendants. | ||||||
|  |              */ | ||||||
|  |             var addVisibleConnectionGroup = function addVisibleConnectionGroup(connectionGroup) { | ||||||
|  |  | ||||||
|  |                 // Add given connection group to set of visible objects | ||||||
|  |                 visibleObjects['g/' + connectionGroup.identifier] = connectionGroup; | ||||||
|  |  | ||||||
|  |                 // Add all child connections | ||||||
|  |                 if (connectionGroup.childConnections) | ||||||
|  |                     connectionGroup.childConnections.forEach(addVisibleConnection); | ||||||
|  |  | ||||||
|  |                 // Add all child connection groups | ||||||
|  |                 if (connectionGroup.childConnectionGroups) | ||||||
|  |                     connectionGroup.childConnectionGroups.forEach(addVisibleConnectionGroup); | ||||||
|  |  | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             // Update visible objects when root group is set | ||||||
|  |             $scope.$watch("rootGroup", function setRootGroup(rootGroup) { | ||||||
|  |  | ||||||
|  |                 $scope.recentConnections = []; | ||||||
|  |  | ||||||
|  |                 // Produce collection of visible objects | ||||||
|  |                 visibleObjects = {}; | ||||||
|  |                 if (rootGroup) | ||||||
|  |                     addVisibleConnectionGroup(rootGroup); | ||||||
|  |  | ||||||
|  |                 // Add any recent connections that are visible | ||||||
|  |                 guacHistory.recentConnections.forEach(function addRecentConnection(historyEntry) { | ||||||
|  |  | ||||||
|  |                     // Add recent connections for history entries with associated visible objects | ||||||
|  |                     if (historyEntry.id in visibleObjects) { | ||||||
|  |  | ||||||
|  |                         var object = visibleObjects[historyEntry.id]; | ||||||
|  |                         $scope.recentConnections.push(new RecentConnection(object.name, historyEntry)); | ||||||
|  |  | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             }); // end rootGroup scope watch | ||||||
|  |  | ||||||
|  |         }] | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  | }]); | ||||||
| @@ -20,4 +20,4 @@ | |||||||
|  * THE SOFTWARE. |  * THE SOFTWARE. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| angular.module('home', ['connection', 'connectionGroup', 'history', 'user', 'permission']); | angular.module('home', ['history', 'groupList', 'rest']); | ||||||
|   | |||||||
| @@ -0,0 +1,44 @@ | |||||||
|  | <div> | ||||||
|  |     <!-- | ||||||
|  |        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. | ||||||
|  |     --> | ||||||
|  |  | ||||||
|  |     <!-- Text displayed if no recent connections exist --> | ||||||
|  |     <p class="no-recent" ng-hide="recentConnections.length">{{'home.noRecentConnections' | translate}}</p> | ||||||
|  |  | ||||||
|  |     <!-- All recent connections --> | ||||||
|  |     <div ng-repeat="recentConnection in recentConnections" class="connection"> | ||||||
|  |         <a href="#/client/{{recentConnection.entry.id}}/{{recentConnection.name}}"> | ||||||
|  |  | ||||||
|  |             <!-- Connection thumbnail --> | ||||||
|  |             <div class="thumbnail"> | ||||||
|  |                 <img alt="{{recentConnection.name}}" ng-src="{{recentConnection.entry.thumbnail}}"/> | ||||||
|  |             </div> | ||||||
|  |  | ||||||
|  |             <!-- Connection name --> | ||||||
|  |             <div class="caption"> | ||||||
|  |                 <span class="name">{{recentConnection.name}}</span> | ||||||
|  |             </div> | ||||||
|  |  | ||||||
|  |         </a> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  | </div> | ||||||
| @@ -20,31 +20,6 @@ | |||||||
|    THE SOFTWARE. |    THE SOFTWARE. | ||||||
| --> | --> | ||||||
|  |  | ||||||
| <script type="text/ng-template" id="nestedGroup.html"> |  | ||||||
|     <div class="connection" ng-show="item.isConnection"> |  | ||||||
|         <a ng-href="#/client/c/{{item.identifier}}"> |  | ||||||
|             <div class="caption"> |  | ||||||
|                 <div class="protocol"> |  | ||||||
|                     <div class="icon type" ng-class="item.protocol"></div> |  | ||||||
|                 </div> |  | ||||||
|                 <span class="name">{{item.name}}</span> |  | ||||||
|             </div> |  | ||||||
|         </a> |  | ||||||
|     </div> |  | ||||||
|     <div class="group" ng-show="!item.isConnection"> |  | ||||||
|         <div class="caption"> |  | ||||||
|             <div class="icon group type" ng-click="toggleExpanded(item)" ng-class="{expanded: item.expanded, empty: !item.children.length, balancer: item.balancer && !item.children.length}"></div> |  | ||||||
|             <span class="name"> |  | ||||||
|                 <a ng-show="item.balancer" ng-href="#/client/g/{{item.identifier}}">{{item.name}}</a> |  | ||||||
|                 <span ng-show="!item.balancer">{{item.name}}</span> |  | ||||||
|             </span> |  | ||||||
|         </div> |  | ||||||
|         <div class="children" ng-show="item.expanded"> |  | ||||||
|             <div class="list-item" ng-repeat="item in item.children | orderBy : 'name'" ng-include="'nestedGroup.html'"> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <div class="connection-list-ui"> | <div class="connection-list-ui"> | ||||||
|  |  | ||||||
|     <div class="logout-panel"> |     <div class="logout-panel"> | ||||||
| @@ -54,25 +29,14 @@ | |||||||
|  |  | ||||||
|     <!-- The recent connections for this user --> |     <!-- The recent connections for this user --> | ||||||
|     <h2>{{'home.recentConnections' | translate}}</h2> |     <h2>{{'home.recentConnections' | translate}}</h2> | ||||||
|     <div class="recent-connections" ng-hide="recentConnections.length"> |     <div class="recent-connections" ng-class="{loading: loading}"> | ||||||
|         <p class="no-recent">{{'home.noRecentConnections' | translate}}</p> |         <guac-recent-connections root-group="rootConnectionGroup"/> | ||||||
|     </div> |  | ||||||
|     <div class="recent-connections" ng-show="recentConnections.length"> |  | ||||||
|         <div ng-repeat="recentConnection in recentConnections" class="connection"> |  | ||||||
|             <a href="#/client/{{recentConnection.type}}/{{recentConnection.id}}/{{recentConnection.name}}"> |  | ||||||
|                 <div class="thumbnail"> |  | ||||||
|                     <img alt="{{recentConnection.name}}" ng-src="{{recentConnection.thumbnail}}"/> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="caption"> |  | ||||||
|                     <span class="name">{{recentConnection.name}}</span> |  | ||||||
|                 </div> |  | ||||||
|             </a> |  | ||||||
|         </div> |  | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|     <!-- All connections for this user --> |     <!-- All connections for this user --> | ||||||
|     <h2>{{'home.allConnections' | translate}}</h2> |     <h2>{{'home.allConnections' | translate}}</h2> | ||||||
|     <div class="all-connections" ng-class="{loading: loading}"> |     <div class="all-connections" ng-class="{loading: loading}"> | ||||||
|         <div class="list-item" ng-repeat="item in connectionsAndGroups | orderBy : 'name'" ng-include="'nestedGroup.html'"></div> |         <guac-group-list connection-group="rootConnectionGroup"/> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
| </div> | </div> | ||||||
| @@ -20,18 +20,36 @@ | |||||||
|  * THE SOFTWARE. |  * THE SOFTWARE. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package org.glyptodon.guacamole.net.basic.rest; |  | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * Useful constants for the REST API. |  * Provides the RecentConnection class used by the guacRecentConnections | ||||||
|  *  |  * directive. | ||||||
|  * @author James Muehlner |  | ||||||
|  */ |  */ | ||||||
| public class APIConstants  { | angular.module('home').factory('RecentConnection', [function defineRecentConnection() { | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * The identifier of the ROOT connection group. |      * A recently-user connection, visible to the current user, with an | ||||||
|  |      * associated history entry. | ||||||
|  |      *  | ||||||
|  |      * @constructor | ||||||
|      */ |      */ | ||||||
|     public static final String ROOT_CONNECTION_GROUP_IDENTIFIER = "ROOT"; |     var RecentConnection = function RecentConnection(name, entry) { | ||||||
| 
 | 
 | ||||||
| } |         /** | ||||||
|  |          * The human-readable name of this connection. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.name = name; | ||||||
|  | 
 | ||||||
|  |         /** | ||||||
|  |          * The history entry associated with this recent connection. | ||||||
|  |          *  | ||||||
|  |          * @type HistoryEntry | ||||||
|  |          */ | ||||||
|  |         this.entry = entry; | ||||||
|  | 
 | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return RecentConnection; | ||||||
|  | 
 | ||||||
|  | }]); | ||||||
| @@ -26,9 +26,11 @@ | |||||||
| angular.module('index').controller('indexController', ['$scope', '$injector', | angular.module('index').controller('indexController', ['$scope', '$injector', | ||||||
|         function indexController($scope, $injector) { |         function indexController($scope, $injector) { | ||||||
|  |  | ||||||
|     // Get the dependencies commonJS style |     // Get class dependencies | ||||||
|     var permissionDAO           = $injector.get("permissionDAO"), |     var PermissionSet = $injector.get("PermissionSet"); | ||||||
|         permissionCheckService  = $injector.get("permissionCheckService"), |  | ||||||
|  |     // Get services | ||||||
|  |     var permissionService       = $injector.get("permissionService"), | ||||||
|         authenticationService   = $injector.get("authenticationService"), |         authenticationService   = $injector.get("authenticationService"), | ||||||
|         $q                      = $injector.get("$q"), |         $q                      = $injector.get("$q"), | ||||||
|         $document               = $injector.get("$document"), |         $document               = $injector.get("$document"), | ||||||
| @@ -166,15 +168,17 @@ angular.module('index').controller('indexController', ['$scope', '$injector', | |||||||
|     // Allow the permissions to be reloaded elsewhere if needed |     // Allow the permissions to be reloaded elsewhere if needed | ||||||
|     $scope.loadBasicPermissions = function loadBasicPermissions() { |     $scope.loadBasicPermissions = function loadBasicPermissions() { | ||||||
|          |          | ||||||
|         permissionDAO.getPermissions($scope.currentUserID).success(function fetchCurrentUserPermissions(permissions) { |         permissionService.getPermissions($scope.currentUserID).success(function fetchCurrentUserPermissions(permissions) { | ||||||
|             $scope.currentUserPermissions = permissions; |             $scope.currentUserPermissions = permissions; | ||||||
|  |  | ||||||
|             // Will be true if the user is an admin |             // Whether the user has system-wide admin permission | ||||||
|             $scope.currentUserIsAdmin = permissionCheckService.checkPermission($scope.currentUserPermissions, "SYSTEM", undefined, "ADMINISTER"); |             $scope.currentUserIsAdmin = PermissionSet.hasSystemPermission($scope.currentUserPermissions, PermissionSet.SystemPermissionType.ADMINISTER); | ||||||
|  |  | ||||||
|             // Will be true if the user is an admin or has update access to any object                |             // Whether the user can update at least one object | ||||||
|             $scope.currentUserHasUpdate = $scope.currentUserIsAdmin ||  |             $scope.currentUserHasUpdate = $scope.currentUserIsAdmin | ||||||
|                     permissionCheckService.checkPermission($scope.currentUserPermissions, undefined, undefined, "UPDATE"); |                                         || PermissionSet.hasConnectionPermission($scope.currentUserPermissions, "UPDATE") | ||||||
|  |                                         || PermissionSet.hasConnectionGroupPermission($scope.currentUserPermissions, "UPDATE") | ||||||
|  |                                         || PermissionSet.hasUserPermission($scope.currentUserPermissions, "UPDATE"); | ||||||
|  |  | ||||||
|             permissionsLoaded.resolve(); |             permissionsLoaded.resolve(); | ||||||
|         }); |         }); | ||||||
|   | |||||||
| @@ -24,4 +24,4 @@ | |||||||
|  * The module for the root of the application. |  * The module for the root of the application. | ||||||
|  */ |  */ | ||||||
| angular.module('index', ['ngRoute', 'pascalprecht.translate', | angular.module('index', ['ngRoute', 'pascalprecht.translate', | ||||||
|     'auth', 'home', 'manage', 'login', 'client', 'notification']); |     'auth', 'home', 'manage', 'login', 'client', 'notification', 'rest']); | ||||||
|   | |||||||
| @@ -260,7 +260,7 @@ div.section { | |||||||
|     border-left: 1px dotted rgba(0, 0, 0, 0.25); |     border-left: 1px dotted rgba(0, 0, 0, 0.25); | ||||||
| } | } | ||||||
|  |  | ||||||
| .group.balancer > .caption .icon.type { | .group.balancer:not(.empty) > .caption .icon.type { | ||||||
|     display: inline-block; |     display: inline-block; | ||||||
|     background-image: url('images/protocol-icons/guac-monitor.png'); |     background-image: url('images/protocol-icons/guac-monitor.png'); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ angular.module('manage').controller('connectionGroupEditModalController', ['$sco | |||||||
|         function connectionEditModalController($scope, $injector) { |         function connectionEditModalController($scope, $injector) { | ||||||
|              |              | ||||||
|     var connectionGroupEditModal        = $injector.get('connectionGroupEditModal'); |     var connectionGroupEditModal        = $injector.get('connectionGroupEditModal'); | ||||||
|     var connectionGroupDAO              = $injector.get('connectionGroupDAO'); |     var connectionGroupService          = $injector.get('connectionGroupService'); | ||||||
|     var displayObjectPreparationService = $injector.get('displayObjectPreparationService'); |     var displayObjectPreparationService = $injector.get('displayObjectPreparationService'); | ||||||
|      |      | ||||||
|     // Make a copy of the old connection group so that we can copy over the changes when done |     // Make a copy of the old connection group so that we can copy over the changes when done | ||||||
| @@ -64,7 +64,7 @@ angular.module('manage').controller('connectionGroupEditModalController', ['$sco | |||||||
|      * Save the connection and close the modal. |      * Save the connection and close the modal. | ||||||
|      */ |      */ | ||||||
|     $scope.save = function save() { |     $scope.save = function save() { | ||||||
|         connectionGroupDAO.saveConnectionGroup($scope.connectionGroup).success(function successfullyUpdatedConnectionGroup() { |         connectionGroupService.saveConnectionGroup($scope.connectionGroup).success(function successfullyUpdatedConnectionGroup() { | ||||||
|              |              | ||||||
|             // Prepare this connection group for display |             // Prepare this connection group for display | ||||||
|             displayObjectPreparationService.prepareConnectionGroup($scope.connectionGroup); |             displayObjectPreparationService.prepareConnectionGroup($scope.connectionGroup); | ||||||
| @@ -79,7 +79,7 @@ angular.module('manage').controller('connectionGroupEditModalController', ['$sco | |||||||
|             if(newConnectionGroup && newParentID === $scope.rootGroup.identifier) { |             if(newConnectionGroup && newParentID === $scope.rootGroup.identifier) { | ||||||
|                 $scope.moveItem($scope.connectionGroup, oldParentID, newParentID); |                 $scope.moveItem($scope.connectionGroup, oldParentID, newParentID); | ||||||
|             } else { |             } else { | ||||||
|                 connectionGroupDAO.moveConnectionGroup($scope.connectionGroup).then(function moveConnectionGroup() { |                 connectionGroupService.moveConnectionGroup($scope.connectionGroup).then(function moveConnectionGroup() { | ||||||
|                     $scope.moveItem($scope.connectionGroup, oldParentID, newParentID); |                     $scope.moveItem($scope.connectionGroup, oldParentID, newParentID); | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
| @@ -99,7 +99,7 @@ angular.module('manage').controller('connectionGroupEditModalController', ['$sco | |||||||
|             // Close the modal |             // Close the modal | ||||||
|             connectionGroupEditModal.deactivate(); |             connectionGroupEditModal.deactivate(); | ||||||
|          |          | ||||||
|         connectionGroupDAO.deleteConnectionGroup($scope.connectionGroup).success(function successfullyDeletedConnectionGroup() { |         connectionGroupService.deleteConnectionGroup($scope.connectionGroup).success(function successfullyDeletedConnectionGroup() { | ||||||
|             var oldParentID = oldConnectionGroup.parentIdentifier; |             var oldParentID = oldConnectionGroup.parentIdentifier; | ||||||
|              |              | ||||||
|             // We have to remove this connection group from the heirarchy |             // We have to remove this connection group from the heirarchy | ||||||
|   | |||||||
| @@ -26,59 +26,38 @@ | |||||||
| angular.module('manage').controller('manageController', ['$scope', '$injector',  | angular.module('manage').controller('manageController', ['$scope', '$injector',  | ||||||
|         function manageController($scope, $injector) { |         function manageController($scope, $injector) { | ||||||
|  |  | ||||||
|     // Get the dependencies commonJS style |     // Required types | ||||||
|  |     var PermissionSet   = $injector.get('PermissionSet'); | ||||||
|  |     var ConnectionGroup = $injector.get('ConnectionGroup'); | ||||||
|  |  | ||||||
|  |     // Required services | ||||||
|     var connectionGroupService      = $injector.get('connectionGroupService'); |     var connectionGroupService      = $injector.get('connectionGroupService'); | ||||||
|     var connectionEditModal         = $injector.get('connectionEditModal'); |     var connectionEditModal         = $injector.get('connectionEditModal'); | ||||||
|     var connectionGroupEditModal    = $injector.get('connectionGroupEditModal'); |     var connectionGroupEditModal    = $injector.get('connectionGroupEditModal'); | ||||||
|     var userEditModal               = $injector.get('userEditModal'); |     var userEditModal               = $injector.get('userEditModal'); | ||||||
|     var protocolDAO                 = $injector.get('protocolDAO'); |     var protocolService             = $injector.get('protocolService'); | ||||||
|     var userDAO                     = $injector.get('userDAO'); |  | ||||||
|     var userService                 = $injector.get('userService'); |     var userService                 = $injector.get('userService'); | ||||||
|      |      | ||||||
|     // Set status to loading until we have all the connections, groups, and users have loaded |     // Set status to loading until we have all the connections, groups, and users have loaded | ||||||
|     $scope.loadingUsers         = true; |     $scope.loadingUsers         = true; | ||||||
|     $scope.loadingConnections   = true; |     $scope.loadingConnections   = true; | ||||||
|      |      | ||||||
|     // All the connections and connection groups in root |  | ||||||
|     $scope.connectionsAndGroups = []; |  | ||||||
|      |  | ||||||
|     // All users that the current user has permission to edit |  | ||||||
|     $scope.users = []; |  | ||||||
|      |  | ||||||
|     $scope.basicPermissionsLoaded.then(function basicPermissionsHaveBeenLoaded() { |     $scope.basicPermissionsLoaded.then(function basicPermissionsHaveBeenLoaded() { | ||||||
|         connectionGroupService.getAllGroupsAndConnections([], undefined, true, true).then(function filterConnectionsAndGroups(rootGroupList) { |  | ||||||
|             $scope.rootGroup = rootGroupList[0]; |  | ||||||
|             $scope.connectionsAndGroups = $scope.rootGroup.children; |  | ||||||
|              |  | ||||||
|             // Filter the items to only include ones that we have UPDATE for |  | ||||||
|             if(!$scope.currentUserIsAdmin) { |  | ||||||
|                 connectionGroupService.filterConnectionsAndGroupByPermission( |  | ||||||
|                     $scope.connectionsAndGroups, |  | ||||||
|                     $scope.currentUserPermissions, |  | ||||||
|                     { |  | ||||||
|                         'CONNECTION':       'UPDATE', |  | ||||||
|                         'CONNECTION_GROUP': 'UPDATE' |  | ||||||
|                     } |  | ||||||
|                 ); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|  |         // Retrieve all users for whom we have UPDATE permission | ||||||
|  |         connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER, PermissionSet.ObjectPermissionType.UPDATE) | ||||||
|  |         .success(function connectionGroupReceived(rootGroup) { | ||||||
|  |             $scope.rootGroup = rootGroup; | ||||||
|             $scope.loadingConnections = false;  |             $scope.loadingConnections = false;  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         userDAO.getUsers().success(function filterEditableUsers(users) { |         // Retrieve all users for whom we have UPDATE permission | ||||||
|  |         userService.getUsers(PermissionSet.ObjectPermissionType.UPDATE) | ||||||
|  |         .success(function usersReceived(users) { | ||||||
|             $scope.users = users; |             $scope.users = users; | ||||||
|              |  | ||||||
|             // Filter the users to only include ones that we have UPDATE for |  | ||||||
|             if(!$scope.currentUserIsAdmin) { |  | ||||||
|                 userService.filterUsersByPermission( |  | ||||||
|                     $scope.users, |  | ||||||
|                     $scope.currentUserPermissions, |  | ||||||
|                     'UPDATE' |  | ||||||
|                 ); |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             $scope.loadingUsers = false;  |             $scope.loadingUsers = false;  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|     }); |     }); | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
| @@ -132,7 +111,7 @@ angular.module('manage').controller('manageController', ['$scope', '$injector', | |||||||
|     $scope.protocols = {}; |     $scope.protocols = {}; | ||||||
|      |      | ||||||
|     // Get the protocol information from the server and copy it into the scope |     // Get the protocol information from the server and copy it into the scope | ||||||
|     protocolDAO.getProtocols().success(function fetchProtocols(protocols) { |     protocolService.getProtocols().success(function fetchProtocols(protocols) { | ||||||
|         angular.extend($scope.protocols, protocols); |         angular.extend($scope.protocols, protocols); | ||||||
|     }); |     }); | ||||||
|      |      | ||||||
| @@ -236,7 +215,7 @@ angular.module('manage').controller('manageController', ['$scope', '$injector', | |||||||
|                 username: $scope.newUsername |                 username: $scope.newUsername | ||||||
|             }; |             }; | ||||||
|              |              | ||||||
|             userDAO.createUser(newUser).success(function addUserToList() { |             userService.createUser(newUser).success(function addUserToList() { | ||||||
|                 $scope.users.push(newUser); |                 $scope.users.push(newUser); | ||||||
|             }); |             }); | ||||||
|              |              | ||||||
|   | |||||||
| @@ -27,8 +27,8 @@ angular.module('manage').controller('userEditModalController', ['$scope', '$inje | |||||||
|         function userEditModalController($scope, $injector) { |         function userEditModalController($scope, $injector) { | ||||||
|              |              | ||||||
|     var userEditModal     = $injector.get('userEditModal'); |     var userEditModal     = $injector.get('userEditModal'); | ||||||
|     var userDAO                         = $injector.get('userDAO'); |     var userService       = $injector.get('userService'); | ||||||
|     var permissionDAO                   = $injector.get('permissionDAO'); |     var permissionService = $injector.get('permissionService'); | ||||||
|      |      | ||||||
|     // Make a copy of the old user so that we can copy over the changes when done |     // Make a copy of the old user so that we can copy over the changes when done | ||||||
|     var oldUser = $scope.user; |     var oldUser = $scope.user; | ||||||
| @@ -73,7 +73,7 @@ angular.module('manage').controller('userEditModalController', ['$scope', '$inje | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         userDAO.saveUser($scope.user).success(function successfullyUpdatedUser() { |         userService.saveUser($scope.user).success(function successfullyUpdatedUser() { | ||||||
|              |              | ||||||
|             //Figure out what permissions have changed |             //Figure out what permissions have changed | ||||||
|             var connectionPermissionsToCreate = [], |             var connectionPermissionsToCreate = [], | ||||||
| @@ -182,7 +182,7 @@ angular.module('manage').controller('userEditModalController', ['$scope', '$inje | |||||||
|              |              | ||||||
|             if(permissionsToAdd.length || permissionsToRemove.length) { |             if(permissionsToAdd.length || permissionsToRemove.length) { | ||||||
|                 // Make the call to update the permissions |                 // Make the call to update the permissions | ||||||
|                 permissionDAO.patchPermissions( |                 permissionService.patchPermissions( | ||||||
|                         $scope.user.username, permissionsToAdd, permissionsToRemove) |                         $scope.user.username, permissionsToAdd, permissionsToRemove) | ||||||
|                         .success(completeSaveProcess).error(handleFailure); |                         .success(completeSaveProcess).error(handleFailure); | ||||||
|             } else { |             } else { | ||||||
| @@ -205,7 +205,7 @@ angular.module('manage').controller('userEditModalController', ['$scope', '$inje | |||||||
|         originalSystemPermissions; |         originalSystemPermissions; | ||||||
|      |      | ||||||
|     // Get the permissions for the user we are editing |     // Get the permissions for the user we are editing | ||||||
|     permissionDAO.getPermissions($scope.user.username).success(function gotPermissions(permissions) { |     permissionService.getPermissions($scope.user.username).success(function gotPermissions(permissions) { | ||||||
|         $scope.permissions = permissions; |         $scope.permissions = permissions; | ||||||
|          |          | ||||||
|         // Figure out if the user has any system level permissions |         // Figure out if the user has any system level permissions | ||||||
| @@ -239,7 +239,7 @@ angular.module('manage').controller('userEditModalController', ['$scope', '$inje | |||||||
|      * Delete the user and close the modal. |      * Delete the user and close the modal. | ||||||
|      */ |      */ | ||||||
|     $scope['delete'] = function deleteUser() { |     $scope['delete'] = function deleteUser() { | ||||||
|         userDAO.deleteUser($scope.user).success(function successfullyDeletedUser() { |         userService.deleteUser($scope.user).success(function successfullyDeletedUser() { | ||||||
|              |              | ||||||
|             // Remove the user from the list |             // Remove the user from the list | ||||||
|             $scope.removeUser($scope.user); |             $scope.removeUser($scope.user); | ||||||
|   | |||||||
| @@ -23,5 +23,5 @@ | |||||||
| /** | /** | ||||||
|  * The module for the administration functionality. |  * The module for the administration functionality. | ||||||
|  */ |  */ | ||||||
| angular.module('manage', ['btford.modal', 'protocol', 'connection', 'connectionGroup', 'util']); | angular.module('manage', ['btford.modal', 'groupList', 'rest', 'util']); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,28 +20,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||||||
| THE SOFTWARE. | THE SOFTWARE. | ||||||
| --> | --> | ||||||
|  |  | ||||||
| <script type="text/ng-template" id="nestedGroup.html"> |  | ||||||
|     <div class="connection" ng-click="editConnection(item)" ng-show="item.isConnection"> |  | ||||||
|         <div class="caption"> |  | ||||||
|             <div class="protocol"> |  | ||||||
|                 <div class="icon type" ng-class="item.protocol"></div> |  | ||||||
|             </div> |  | ||||||
|             <span class="name">{{item.name}}</span> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
|     <div class="group" ng-show="!item.isConnection"> |  | ||||||
|         <div class="caption"> |  | ||||||
|             <div class="icon group type" ng-click="toggleExpanded(item)" ng-class="{expanded: item.expanded, empty: !item.children.length, balancer: item.balancer && !item.children.length}"></div> |  | ||||||
|             <span ng-click="editConnectionGroup(item)" class="name"> |  | ||||||
|                 <span>{{item.name}}</span> |  | ||||||
|             </span> |  | ||||||
|         </div> |  | ||||||
|         <div class="children" ng-show="item.expanded"> |  | ||||||
|             <div class="list-item" ng-repeat="item in item.children | orderBy : 'name'" ng-include="'nestedGroup.html'"> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <div class="logout-panel"> | <div class="logout-panel"> | ||||||
|     <a class="back button" href="#/">{{'manage.back' | translate}}</a> |     <a class="back button" href="#/">{{'manage.back' | translate}}</a> | ||||||
|     <a class="logout button" ng-click="logout()">{{'home.logout' | translate}}</a> |     <a class="logout button" ng-click="logout()">{{'home.logout' | translate}}</a> | ||||||
| @@ -85,7 +63,7 @@ THE SOFTWARE. | |||||||
|  |  | ||||||
|         <!-- List of connections and groups this user has access to --> |         <!-- List of connections and groups this user has access to --> | ||||||
|         <div class="connection-list" ng-class="{loading: loadingConnections}"> |         <div class="connection-list" ng-class="{loading: loadingConnections}"> | ||||||
|             <div class="list-item" ng-repeat="item in connectionsAndGroups | orderBy : 'name'" ng-include="'nestedGroup.html'"></div> |             <guac-group-list connection-group="rootGroup"/> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,26 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * A module for code relating to permissions. |  | ||||||
|  */ |  | ||||||
| angular.module('permission', ['auth']); |  | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * A service for checking if a specific permission exists  |  | ||||||
|  * in a given list of permissions. |  | ||||||
|  */ |  | ||||||
| angular.module('permission').factory('permissionCheckService', [ |  | ||||||
|         function permissionCheckService() { |  | ||||||
|              |  | ||||||
|     var service = {}; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * A service for checking if the given permission list contains the given |  | ||||||
|      * permission, defined by the objectType, objectID, and permissionType. |  | ||||||
|      * If the objectType or objectID are not passed, they will not be checked. |  | ||||||
|      *  |  | ||||||
|      * For example, checkPermission(list, "CONNECTION", undefined, "READ") would |  | ||||||
|      * check if the permission list contains permission to read any connection. |  | ||||||
|      *  |  | ||||||
|      * @param {array} permissions The array of permissions to check. |  | ||||||
|      * @param {string} objectType The object type for the permission. |  | ||||||
|      *                            If not passed, this will not be checked. |  | ||||||
|      * @param {string} objectID The ID of the object the permission is for.  |  | ||||||
|      *                          If not passed, this will not be checked. |  | ||||||
|      * @param {string} permissionType The actual permission type to check for. |  | ||||||
|      * @returns {boolean} True if the given permissions contain the requested permission, false otherwise. |  | ||||||
|      */ |  | ||||||
|     service.checkPermission = function checkPermission(permissions, objectType, objectID, permissionType) { |  | ||||||
|          |  | ||||||
|         // Loop through all the permissions and check if any of them match the given parameters |  | ||||||
|         for(var i = 0; i < permissions.length; i++) { |  | ||||||
|             var permission = permissions[i]; |  | ||||||
|              |  | ||||||
|             if(objectType === "SYSTEM") { |  | ||||||
|                 // System permissions have no object ID, we only need to check the type. |  | ||||||
|                 if(permission.permissionType === permissionType) |  | ||||||
|                     return true; |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 // Object permissions need to match the object ID and type if given. |  | ||||||
|                 if(permission.permissionType === permissionType &&  |  | ||||||
|                         (!objectType || permission.objectType === objectType) &&  |  | ||||||
|                         (!objectID || permission.objectID === objectID)) |  | ||||||
|                     return true; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         // Didn't find any that matched |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     return service; |  | ||||||
| }]); |  | ||||||
| @@ -1,115 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * The DAO for permission operations agains the REST API. |  | ||||||
|  */ |  | ||||||
| angular.module('permission').factory('permissionDAO', ['$http', 'authenticationService', |  | ||||||
|         function permissionDAO($http, authenticationService) { |  | ||||||
|              |  | ||||||
|     var service = {}; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to get the list of permissions for a given user, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {string} userID The ID of the user to retrieve the permissions for. |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.getPermissions = function getPermissions(userID) { |  | ||||||
|         return $http.get("api/permission/" + userID + "/?token=" + authenticationService.getCurrentToken()); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to add a permission for a given user, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {string} userID The ID of the user to add the permission for. |  | ||||||
|      * @param {object} permission The permission to add. |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.addPermission = function addPermission(userID, permission) { |  | ||||||
|         return $http.post("api/permission/" + userID + "/?token=" + authenticationService.getCurrentToken(), permission); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to remove a permission for a given user, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {string} userID The ID of the user to remove the permission for. |  | ||||||
|      * @param {object} permission The permission to remove. |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.removePermission = function removePermission(userID, permission) { |  | ||||||
|         return $http.post("api/permission/remove/" + userID + "/?token=" + authenticationService.getCurrentToken(), permission); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to modify the permissions for a given user, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {string} userID The ID of the user to remove the permission for. |  | ||||||
|      * @param {array} permissionsToAdd The permissions to add. |  | ||||||
|      * @param {array} permissionsToRemove The permissions to remove. |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.patchPermissions = function patchPermissions(userID, permissionsToAdd, permissionsToRemove) { |  | ||||||
|         var permissionPatch = []; |  | ||||||
|          |  | ||||||
|         // Add all the add operations to the patch |  | ||||||
|         for(var i = 0; i < permissionsToAdd.length; i++ ) { |  | ||||||
|             permissionPatch.push({ |  | ||||||
|                 op      : "add", |  | ||||||
|                 path    : userID,  |  | ||||||
|                 value   : permissionsToAdd[i] |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         // Add all the remove operations to the patch |  | ||||||
|         for(var i = 0; i < permissionsToRemove.length; i++ ) { |  | ||||||
|             permissionPatch.push({ |  | ||||||
|                 op      : "remove", |  | ||||||
|                 path    : userID,  |  | ||||||
|                 value   : permissionsToRemove[i] |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         // Make the HTTP call |  | ||||||
|         return $http({ |  | ||||||
|             method  : 'PATCH',  |  | ||||||
|             url     : "api/permission/?token=" + authenticationService.getCurrentToken(), |  | ||||||
|             data    : permissionPatch |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     return service; |  | ||||||
| }]); |  | ||||||
| @@ -21,6 +21,7 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * The module for the protocol functionality. |  * The module for code relating to communication with the REST API of the | ||||||
|  |  * Guacamole web application. | ||||||
|  */ |  */ | ||||||
| angular.module('protocol', []); | angular.module('rest', ['auth']); | ||||||
| @@ -0,0 +1,181 @@ | |||||||
|  | /* | ||||||
|  |  * 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 for operating on connection groups via the REST API. | ||||||
|  |  */ | ||||||
|  | angular.module('rest').factory('connectionGroupService', ['$http', 'authenticationService', 'ConnectionGroup', | ||||||
|  |         function connectionGroupService($http, authenticationService, ConnectionGroup) { | ||||||
|  |              | ||||||
|  |     var service = {}; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to get an individual connection group | ||||||
|  |      * and all descendants, returning a promise that provides the corresponding | ||||||
|  |      * @link{ConnectionGroup} if successful. Descendant groups and connections | ||||||
|  |      * will be stored as children of that connection group. If a permission | ||||||
|  |      * type is specified, the result will be filtering by that permission. | ||||||
|  |      *  | ||||||
|  |      * @param {String} [connectionGroupID=ConnectionGroup.ROOT_IDENTIFIER] | ||||||
|  |      *     The ID of the connection group to retrieve. If not provided, the | ||||||
|  |      *     root connection group will be retrieved by default. | ||||||
|  |      *      | ||||||
|  |      * @param {String} [permissionType] | ||||||
|  |      *     The permission type string of the permission that the current user | ||||||
|  |      *     must have for a given connection or connection group to appear | ||||||
|  |      *     within the result. Valid values are listed within | ||||||
|  |      *     PermissionSet.ObjectType. | ||||||
|  |      * | ||||||
|  |      * @returns {Promise.ConnectionGroup} | ||||||
|  |      *     A promise which will resolve with a @link{ConnectionGroup} upon | ||||||
|  |      *     success. | ||||||
|  |      */ | ||||||
|  |     service.getConnectionGroupTree = function getConnectionGroupTree(connectionGroupID, permissionType) { | ||||||
|  |          | ||||||
|  |         // Use the root connection group ID if no ID is passed in | ||||||
|  |         connectionGroupID = connectionGroupID || ConnectionGroup.ROOT_IDENTIFIER; | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Add permission filter if specified | ||||||
|  |         if (permissionType) | ||||||
|  |             httpParameters.permission = permissionType; | ||||||
|  |  | ||||||
|  |         // Retrieve connection group  | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'GET', | ||||||
|  |             url     : 'api/connectionGroups/' + encodeURIComponent(connectionGroupID) + '/tree', | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |         | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to get an individual connection group, | ||||||
|  |      * returning a promise that provides the corresponding | ||||||
|  |      * @link{ConnectionGroup} if successful. | ||||||
|  |      * | ||||||
|  |      * @param {String} [connectionGroupID=ConnectionGroup.ROOT_IDENTIFIER] | ||||||
|  |      *     The ID of the connection group to retrieve. If not provided, the | ||||||
|  |      *     root connection group will be retrieved by default. | ||||||
|  |      *      | ||||||
|  |      * @returns {Promise.<ConnectionGroup>} A promise for the HTTP call. | ||||||
|  |      *     A promise which will resolve with a @link{ConnectionGroup} upon | ||||||
|  |      *     success. | ||||||
|  |      */ | ||||||
|  |     service.getConnectionGroup = function getConnectionGroup(connectionGroupID) { | ||||||
|  |          | ||||||
|  |         // Use the root connection group ID if no ID is passed in | ||||||
|  |         connectionGroupID = connectionGroupID || ConnectionGroup.ROOT_IDENTIFIER; | ||||||
|  |          | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Retrieve connection group | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'GET', | ||||||
|  |             url     : 'api/connectionGroups/' + encodeURIComponent(connectionGroupID), | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to save a connection group, returning a | ||||||
|  |      * promise that can be used for processing the results of the call. If the | ||||||
|  |      * connection group is new, and thus does not yet have an associated | ||||||
|  |      * identifier, the identifier will be automatically set in the provided | ||||||
|  |      * connection group upon success. | ||||||
|  |      *  | ||||||
|  |      * @param {ConnectionGroup} connectionGroup The connection group to update. | ||||||
|  |      *                           | ||||||
|  |      * @returns {Promise} | ||||||
|  |      *     A promise for the HTTP call which will succeed if and only if the | ||||||
|  |      *     save operation is successful. | ||||||
|  |      */ | ||||||
|  |     service.saveConnectionGroup = function saveConnectionGroup(connectionGroup) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // If connection group is new, add it and set the identifier automatically | ||||||
|  |         if (!connectionGroup.identifier) { | ||||||
|  |             return $http({ | ||||||
|  |                 method  : 'POST', | ||||||
|  |                 url     : 'api/connectionGroups', | ||||||
|  |                 params  : httpParameters, | ||||||
|  |                 data    : connectionGroup | ||||||
|  |             }) | ||||||
|  |  | ||||||
|  |             // Set the identifier on the new connection group | ||||||
|  |             .success(function connectionGroupCreated(identifier){ | ||||||
|  |                 connectionGroup.identifier = identifier; | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Otherwise, update the existing connection group | ||||||
|  |         else { | ||||||
|  |             return $http({ | ||||||
|  |                 method  : 'PUT', | ||||||
|  |                 url     : 'api/connectionGroups/' + encodeURIComponent(connectionGroup.identifier), | ||||||
|  |                 params  : httpParameters, | ||||||
|  |                 data    : connectionGroup | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to delete a connection group, returning | ||||||
|  |      * a promise that can be used for processing the results of the call. | ||||||
|  |      *  | ||||||
|  |      * @param {ConnectionGroup} connectionGroup The connection group to delete. | ||||||
|  |      *                           | ||||||
|  |      * @returns {Promise} | ||||||
|  |      *     A promise for the HTTP call which will succeed if and only if the | ||||||
|  |      *     delete operation is successful. | ||||||
|  |      */ | ||||||
|  |     service.deleteConnectionGroup = function deleteConnectionGroup(connectionGroup) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Delete connection group | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'DELETE', | ||||||
|  |             url     : 'api/connectionGroups/' + encodeURIComponent(connectionGroup.identifier), | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     return service; | ||||||
|  | }]); | ||||||
							
								
								
									
										192
									
								
								guacamole/src/main/webapp/app/rest/services/connectionService.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								guacamole/src/main/webapp/app/rest/services/connectionService.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | |||||||
|  | /* | ||||||
|  |  * 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 for operating on connections via the REST API. | ||||||
|  |  */ | ||||||
|  | angular.module('rest').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 provides the corresponding @link{Connection} if successful. | ||||||
|  |      *  | ||||||
|  |      * @param {String} id The ID of the connection. | ||||||
|  |      *  | ||||||
|  |      * @returns {Promise.<Connection>} | ||||||
|  |      *     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) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Retrieve connection | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'GET', | ||||||
|  |             url     : 'api/connections/' + encodeURIComponent(id), | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to get the usage history of a single | ||||||
|  |      * connection, returning a promise that provides the corresponding | ||||||
|  |      * array of @link{ConnectionHistoryEntry} objects if successful. | ||||||
|  |      *  | ||||||
|  |      * @param {String} id | ||||||
|  |      *     The identifier of the connection. | ||||||
|  |      *  | ||||||
|  |      * @returns {Promise.<ConnectionHistoryEntry[]>} | ||||||
|  |      *     A promise which will resolve with an array of | ||||||
|  |      *     @link{ConnectionHistoryEntry} objects upon success. | ||||||
|  |      */ | ||||||
|  |     service.getConnectionHistory = function getConnectionHistory(id) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Retrieve connection history | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'GET', | ||||||
|  |             url     : 'api/connections/' + encodeURIComponent(id) + '/history', | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |   | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to get the parameters of a single | ||||||
|  |      * connection, returning a promise that provides the corresponding | ||||||
|  |      * map of parameter name/value pairs if successful. | ||||||
|  |      *  | ||||||
|  |      * @param {String} id | ||||||
|  |      *     The identifier of the connection. | ||||||
|  |      *  | ||||||
|  |      * @returns {Promise.<Object.<String, String>>} | ||||||
|  |      *     A promise which will resolve with an map of parameter name/value | ||||||
|  |      *     pairs upon success. | ||||||
|  |      */ | ||||||
|  |     service.getConnectionParameters = function getConnectionParameters(id) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Retrieve connection parameters | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'GET', | ||||||
|  |             url     : 'api/connections/' + encodeURIComponent(id) + '/parameters', | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |   | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 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. If the | ||||||
|  |      * connection is new, and thus does not yet have an associated identifier, | ||||||
|  |      * the identifier will be automatically set in the provided connection | ||||||
|  |      * upon success. | ||||||
|  |      *  | ||||||
|  |      * @param {Connection} connection The connection to update. | ||||||
|  |      *                           | ||||||
|  |      * @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) { | ||||||
|  |          | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // If connection is new, add it and set the identifier automatically | ||||||
|  |         if (!connection.identifier) { | ||||||
|  |             return $http({ | ||||||
|  |                 method  : 'POST', | ||||||
|  |                 url     : 'api/connections', | ||||||
|  |                 params  : httpParameters, | ||||||
|  |                 data    : connection | ||||||
|  |             }) | ||||||
|  |  | ||||||
|  |             // Set the identifier on the new connection | ||||||
|  |             .success(function connectionCreated(identifier){ | ||||||
|  |                 connection.identifier = identifier; | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Otherwise, update the existing connection | ||||||
|  |         else { | ||||||
|  |             return $http({ | ||||||
|  |                 method  : 'PUT', | ||||||
|  |                 url     : 'api/connections/' + encodeURIComponent(connection.identifier), | ||||||
|  |                 params  : httpParameters, | ||||||
|  |                 data    : connection | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * 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 {Connection} connection The connection to delete. | ||||||
|  |      *                           | ||||||
|  |      * @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) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Delete connection | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'DELETE', | ||||||
|  |             url     : 'api/connections/' + encodeURIComponent(connection.identifier), | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     return service; | ||||||
|  | }]); | ||||||
							
								
								
									
										216
									
								
								guacamole/src/main/webapp/app/rest/services/permissionService.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								guacamole/src/main/webapp/app/rest/services/permissionService.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | |||||||
|  | /* | ||||||
|  |  * 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 for operating on user permissions via the REST API. | ||||||
|  |  */ | ||||||
|  | angular.module('rest').factory('permissionService', ['$http', 'authenticationService', 'PermissionPatch', | ||||||
|  |         function permissionService($http, authenticationService, PermissionPatch) { | ||||||
|  |              | ||||||
|  |     var service = {}; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to get the list of permissions for a | ||||||
|  |      * given user, returning a promise that provides an array of | ||||||
|  |      * @link{Permission} objects if successful. | ||||||
|  |      *  | ||||||
|  |      * @param {String} userID | ||||||
|  |      *     The ID of the user to retrieve the permissions for. | ||||||
|  |      *                           | ||||||
|  |      * @returns {Promise.<PermissionSet>} | ||||||
|  |      *     A promise which will resolve with a @link{PermissionSet} upon | ||||||
|  |      *     success. | ||||||
|  |      */ | ||||||
|  |     service.getPermissions = function getPermissions(userID) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Retrieve user permissions | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'GET', | ||||||
|  |             url     : 'api/users/' + encodeURIComponent(userID) + '/permissions', | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to add permissions for a given user, | ||||||
|  |      * returning a promise that can be used for processing the results of the | ||||||
|  |      * call. | ||||||
|  |      *  | ||||||
|  |      * @param {String} userID | ||||||
|  |      *     The ID of the user to modify the permissions of. | ||||||
|  |      *                           | ||||||
|  |      * @param {PermissionSet} permissions | ||||||
|  |      *     The set of permissions to add. | ||||||
|  |      *                           | ||||||
|  |      * @returns {Promise} | ||||||
|  |      *     A promise for the HTTP call which will succeed if and only if the | ||||||
|  |      *     add operation is successful. | ||||||
|  |      */ | ||||||
|  |     service.addPermissions = function addPermissions(userID, permissions) { | ||||||
|  |         return service.patchPermissions(userID, permissions, null); | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to remove permissions for a given user, | ||||||
|  |      * returning a promise that can be used for processing the results of the | ||||||
|  |      * call. | ||||||
|  |      *  | ||||||
|  |      * @param {String} userID | ||||||
|  |      *     The ID of the user to modify the permissions of. | ||||||
|  |      *                           | ||||||
|  |      * @param {PermissionSet} permissions | ||||||
|  |      *     The set of permissions to remove. | ||||||
|  |      *                           | ||||||
|  |      * @returns {Promise} | ||||||
|  |      *     A promise for the HTTP call which will succeed if and only if the | ||||||
|  |      *     remove operation is successful. | ||||||
|  |      */ | ||||||
|  |     service.removePermissions = function removePermissions(userID, permissions) { | ||||||
|  |         return service.patchPermissions(userID, null, permissions); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Adds patches for modifying the permissions associated with specific | ||||||
|  |      * objects to the given array of patches. | ||||||
|  |      * | ||||||
|  |      * @param {PermissionPatch[]} patch | ||||||
|  |      *     The array of patches to add new patches to. | ||||||
|  |      * | ||||||
|  |      * @param {String} operation | ||||||
|  |      *     The operation to specify within each of the patches. Valid values | ||||||
|  |      *     for this are defined within PermissionPatch.Operation. | ||||||
|  |      *      | ||||||
|  |      * @param {String} path | ||||||
|  |      *     The path of the permissions being patched. The path is a JSON path | ||||||
|  |      *     describing the position of the permissions within a PermissionSet. | ||||||
|  |      * | ||||||
|  |      * @param {Object.<String, String[]>} permissions | ||||||
|  |      *     A map of object identifiers to arrays of permission type strings, | ||||||
|  |      *     where each type string is a value from | ||||||
|  |      *     PermissionSet.ObjectPermissionType. | ||||||
|  |      */ | ||||||
|  |     var addObjectPatchOperations = function addObjectPatchOperations(patch, operation, path, permissions) { | ||||||
|  |  | ||||||
|  |         // Add object permission operations to patch | ||||||
|  |         for (var identifier in permissions) { | ||||||
|  |             permissions[identifier].forEach(function addObjectPatch(type) { | ||||||
|  |                 patch.push({ | ||||||
|  |                     op    : operation, | ||||||
|  |                     path  : path + "/" + identifier, | ||||||
|  |                     value : type | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Adds patches for modifying any permission that can be stored within a | ||||||
|  |      * @link{PermissionSet}. | ||||||
|  |      *  | ||||||
|  |      * @param {PermissionPatch[]} patch | ||||||
|  |      *     The array of patches to add new patches to. | ||||||
|  |      * | ||||||
|  |      * @param {String} operation | ||||||
|  |      *     The operation to specify within each of the patches. Valid values | ||||||
|  |      *     for this are defined within PermissionPatch.Operation. | ||||||
|  |      * | ||||||
|  |      * @param {PermissionSet} permissions | ||||||
|  |      *     The set of permissions for which patches should be added. | ||||||
|  |      */ | ||||||
|  |     var addPatchOperations = function addPatchOperations(patch, operation, permissions) { | ||||||
|  |  | ||||||
|  |         // Add connection permission operations to patch | ||||||
|  |         addObjectPatchOperations(patch, operation, "/connectionPermissions", | ||||||
|  |             permissions.connectionPermissions); | ||||||
|  |  | ||||||
|  |         // Add connection group permission operations to patch | ||||||
|  |         addObjectPatchOperations(patch, operation, "/connectionGroupPermissions", | ||||||
|  |             permissions.connectionGroupPermissions); | ||||||
|  |  | ||||||
|  |         // Add user permission operations to patch | ||||||
|  |         addObjectPatchOperations(patch, operation, "/userPermissions", | ||||||
|  |             permissions.userPermissions); | ||||||
|  |  | ||||||
|  |         // Add system operations to patch | ||||||
|  |         permissions.systemPermissions.forEach(function addSystemPatch(type) { | ||||||
|  |             patch.push({ | ||||||
|  |                 op    : operation, | ||||||
|  |                 path  : "/systemPermissions", | ||||||
|  |                 value : type | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |              | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to modify the permissions for a given | ||||||
|  |      * user, returning a promise that can be used for processing the results of | ||||||
|  |      * the call. | ||||||
|  |      *  | ||||||
|  |      * @param {String} userID | ||||||
|  |      *     The ID of the user to modify the permissions of. | ||||||
|  |      *                           | ||||||
|  |      * @param {PermissionSet} [permissionsToAdd] | ||||||
|  |      *     The set of permissions to add, if any. | ||||||
|  |      * | ||||||
|  |      * @param {PermissionSet} [permissionsToRemove] | ||||||
|  |      *     The set of permissions to remove, if any. | ||||||
|  |      *                           | ||||||
|  |      * @returns {Promise} | ||||||
|  |      *     A promise for the HTTP call which will succeed if and only if the | ||||||
|  |      *     patch operation is successful. | ||||||
|  |      */ | ||||||
|  |     service.patchPermissions = function patchPermissions(userID, permissionsToAdd, permissionsToRemove) { | ||||||
|  |  | ||||||
|  |         var permissionPatch = []; | ||||||
|  |          | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Add all the add operations to the patch | ||||||
|  |         addPatchOperations(permissionPatch, PermissionPatch.Operation.ADD, permissionsToAdd); | ||||||
|  |  | ||||||
|  |         // Add all the remove operations to the patch | ||||||
|  |         addPatchOperations(permissionPatch, PermissionPatch.Operation.REMOVE, permissionsToRemove); | ||||||
|  |  | ||||||
|  |         // Patch user permissions | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'PATCH',  | ||||||
|  |             url     : 'api/users/' + encodeURIComponent(userID) + '/permissions', | ||||||
|  |             params  : httpParameters, | ||||||
|  |             data    : permissionPatch | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     return service; | ||||||
|  |  | ||||||
|  | }]); | ||||||
| @@ -21,21 +21,38 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * The DAO for protocol operations agains the REST API. |  * Service for operating on protocol metadata via the REST API. | ||||||
|  */ |  */ | ||||||
| angular.module('protocol').factory('protocolDAO', ['$http', function protocolDAO($http) { | angular.module('rest').factory('protocolService', ['$http', 'authenticationService', | ||||||
|  |         function protocolService($http, authenticationService) { | ||||||
|              |              | ||||||
|     var service = {}; |     var service = {}; | ||||||
|      |      | ||||||
|     /** |     /** | ||||||
|      * Makes a request to the REST API to get the list of protocols, |      * Makes a request to the REST API to get the list of protocols, returning | ||||||
|      * returning a promise that can be used for processing the results of the call. |      * a promise that provides an array of @link{Protocol} objects if | ||||||
|  |      * successful. | ||||||
|      *                           |      *                           | ||||||
|      * @returns {promise} A promise for the HTTP call. |      * @returns {Promise.<Protocol[]>} | ||||||
|  |      *     A promise which will resolve with an array of @link{Protocol} | ||||||
|  |      *     objects upon success. | ||||||
|      */ |      */ | ||||||
|     service.getProtocols = function getProtocols() { |     service.getProtocols = function getProtocols() { | ||||||
|         return $http.get("api/protocol"); | 
 | ||||||
|  |         // Build HTTP parameters set
 | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         // Retrieve available protocols
 | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'GET', | ||||||
|  |             url     : 'api/protocols', | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|     }; |     }; | ||||||
|      |      | ||||||
|     return service; |     return service; | ||||||
|  | 
 | ||||||
| }]); | }]); | ||||||
							
								
								
									
										177
									
								
								guacamole/src/main/webapp/app/rest/services/userService.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								guacamole/src/main/webapp/app/rest/services/userService.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | |||||||
|  | /* | ||||||
|  |  * 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 for operating on users via the REST API. | ||||||
|  |  */ | ||||||
|  | angular.module('rest').factory('userService', ['$http', 'authenticationService', | ||||||
|  |         function userService($http, authenticationService) { | ||||||
|  |              | ||||||
|  |     var service = {}; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to get the list of users, | ||||||
|  |      * returning a promise that provides an array of @link{User} objects if | ||||||
|  |      * successful. | ||||||
|  |      *  | ||||||
|  |      * @param {String} [permissionType] | ||||||
|  |      *     The permission type string of the permission that the current user | ||||||
|  |      *     must have for a given user to appear within the list. Valid values | ||||||
|  |      *     are listed within PermissionSet.ObjectType. | ||||||
|  |      *                           | ||||||
|  |      * @returns {Promise.<User[]>} | ||||||
|  |      *     A promise which will resolve with an array of @link{User} objects | ||||||
|  |      *     upon success. | ||||||
|  |      */ | ||||||
|  |     service.getUsers = function getUsers(permissionType) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Add permission filter if specified | ||||||
|  |         if (permissionType) | ||||||
|  |             httpParameters.permission = permissionType; | ||||||
|  |  | ||||||
|  |         // Retrieve users | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'GET', | ||||||
|  |             url     : 'api/users', | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to get the user having the given | ||||||
|  |      * username, returning a promise that provides the corresponding | ||||||
|  |      * @link{User} if successful. | ||||||
|  |      *  | ||||||
|  |      * @param {String} username | ||||||
|  |      *     The username of the user to retrieve. | ||||||
|  |      *  | ||||||
|  |      * @returns {Promise.<User>} | ||||||
|  |      *     A promise which will resolve with a @link{User} upon success. | ||||||
|  |      */ | ||||||
|  |     service.getUser = function getUser(username) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Retrieve user | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'GET', | ||||||
|  |             url     : 'api/users/' + encodeURIComponent(username), | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to delete a user, returning a promise | ||||||
|  |      * that can be used for processing the results of the call. | ||||||
|  |      *  | ||||||
|  |      * @param {User} user | ||||||
|  |      *     The user to delete. | ||||||
|  |      *                           | ||||||
|  |      * @returns {Promise} | ||||||
|  |      *     A promise for the HTTP call which will succeed if and only if the | ||||||
|  |      *     delete operation is successful. | ||||||
|  |      */ | ||||||
|  |     service.deleteUser = function deleteUser(user) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Retrieve user | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'DELETE', | ||||||
|  |             url     : 'api/users/' + encodeURIComponent(user.username), | ||||||
|  |             params  : httpParameters | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to create a user, returning a promise | ||||||
|  |      * that can be used for processing the results of the call. | ||||||
|  |      *  | ||||||
|  |      * @param {User} user | ||||||
|  |      *     The user to create. | ||||||
|  |      *                           | ||||||
|  |      * @returns {Promise} | ||||||
|  |      *     A promise for the HTTP call which will succeed if and only if the | ||||||
|  |      *     create operation is successful. | ||||||
|  |      */ | ||||||
|  |     service.createUser = function createUser(user) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Retrieve user | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'POST', | ||||||
|  |             url     : 'api/users', | ||||||
|  |             params  : httpParameters, | ||||||
|  |             data    : user | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Makes a request to the REST API to save a user, returning a promise that | ||||||
|  |      * can be used for processing the results of the call. | ||||||
|  |      *  | ||||||
|  |      * @param {User} user | ||||||
|  |      *     The user to update. | ||||||
|  |      *                           | ||||||
|  |      * @returns {Promise} | ||||||
|  |      *     A promise for the HTTP call which will succeed if and only if the | ||||||
|  |      *     save operation is successful. | ||||||
|  |      */ | ||||||
|  |     service.saveUser = function saveUser(user) { | ||||||
|  |  | ||||||
|  |         // Build HTTP parameters set | ||||||
|  |         var httpParameters = { | ||||||
|  |             token : authenticationService.getCurrentToken() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Retrieve user | ||||||
|  |         return $http({ | ||||||
|  |             method  : 'PUT', | ||||||
|  |             url     : 'api/users/' + encodeURIComponent(user.username), | ||||||
|  |             params  : httpParameters, | ||||||
|  |             data    : user | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     return service; | ||||||
|  |  | ||||||
|  | }]); | ||||||
| @@ -23,7 +23,7 @@ | |||||||
| /** | /** | ||||||
|  * Service which defines the Connection class. |  * Service which defines the Connection class. | ||||||
|  */ |  */ | ||||||
| angular.module('connection').factory('Connection', [function defineConnection() { | angular.module('rest').factory('Connection', [function defineConnection() { | ||||||
|              |              | ||||||
|     /** |     /** | ||||||
|      * The object returned by REST API calls when representing the data |      * The object returned by REST API calls when representing the data | ||||||
| @@ -70,24 +70,15 @@ angular.module('connection').factory('Connection', [function defineConnection() | |||||||
|          */ |          */ | ||||||
|         this.protocol = template.protocol; |         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 |          * Connection configuration parameters, as dictated by the protocol in | ||||||
|          * use, arranged as name/value pairs. This information may not be |          * use, arranged as name/value pairs. This information may not be | ||||||
|          * available if the current user lacks permission to update |          * available until directly queried. If this information is | ||||||
|          * connection parameters, even if they otherwise have permission to |          * unavailable, this property will be null or undefined. | ||||||
|          * read and use the connection. |  | ||||||
|          * |          * | ||||||
|          * @type Object.<String, String> |          * @type Object.<String, String> | ||||||
|          */ |          */ | ||||||
|         this.parameters = template.parameters || {}; |         this.parameters = template.parameters; | ||||||
| 
 | 
 | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
							
								
								
									
										127
									
								
								guacamole/src/main/webapp/app/rest/types/ConnectionGroup.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								guacamole/src/main/webapp/app/rest/types/ConnectionGroup.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | |||||||
|  | /* | ||||||
|  |  * 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 ConnectionGroup class. | ||||||
|  |  */ | ||||||
|  | angular.module('rest').factory('ConnectionGroup', [function defineConnectionGroup() { | ||||||
|  |              | ||||||
|  |     /** | ||||||
|  |      * The object returned by REST API calls when representing the data | ||||||
|  |      * associated with a connection group. | ||||||
|  |      *  | ||||||
|  |      * @constructor | ||||||
|  |      * @param {ConnectionGroup|Object} [template={}] | ||||||
|  |      *     The object whose properties should be copied within the new | ||||||
|  |      *     ConnectionGroup. | ||||||
|  |      */ | ||||||
|  |     var ConnectionGroup = function ConnectionGroup(template) { | ||||||
|  |  | ||||||
|  |         // Use empty object by default | ||||||
|  |         template = template || {}; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The unique identifier associated with this connection group. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.identifier = template.identifier; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The unique identifier of the connection group that contains this | ||||||
|  |          * connection group. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          * @default ConnectionGroup.ROOT_IDENTIFIER | ||||||
|  |          */ | ||||||
|  |         this.parentIdentifier = template.parentIdentifier || ConnectionGroup.ROOT_IDENTIFIER; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The human-readable name of this connection group, which is not | ||||||
|  |          * necessarily unique. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.name = template.name; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type of this connection group, which may be either | ||||||
|  |          * ConnectionGroup.Type.ORGANIZATIONAL or | ||||||
|  |          * ConnectionGroup.Type.BALANCING. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          * @default ConnectionGroup.Type.ORGANIZATIONAL | ||||||
|  |          */ | ||||||
|  |         this.type = template.type || ConnectionGroup.Type.ORGANIZATIONAL; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * An array of all child connections, if known. This property may be | ||||||
|  |          * null or undefined if children have not been queried, and thus the | ||||||
|  |          * child connections are unknown. | ||||||
|  |          * | ||||||
|  |          * @type Connection[] | ||||||
|  |          */ | ||||||
|  |         this.childConnections = template.childConnections; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * An array of all child connection groups, if known. This property may | ||||||
|  |          * be null or undefined if children have not been queried, and thus the | ||||||
|  |          * child connection groups are unknown. | ||||||
|  |          * | ||||||
|  |          * @type ConnectionGroup[] | ||||||
|  |          */ | ||||||
|  |         this.childConnectionGroups = template.childConnectionGroups; | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The reserved identifier which always represents the root connection | ||||||
|  |      * group. | ||||||
|  |      *  | ||||||
|  |      * @type String | ||||||
|  |      */ | ||||||
|  |     ConnectionGroup.ROOT_IDENTIFIER = "ROOT"; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * All valid connection group types. | ||||||
|  |      */ | ||||||
|  |     ConnectionGroup.Type = { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type string associated with balancing connection groups. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         BALANCING : "BALANCING", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type string associated with organizational connection groups. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         ORGANIZATIONAL : "ORGANIZATIONAL" | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return ConnectionGroup; | ||||||
|  |  | ||||||
|  | }]); | ||||||
| @@ -23,7 +23,7 @@ | |||||||
| /** | /** | ||||||
|  * Service which defines the ConnectionHistoryEntry class. |  * Service which defines the ConnectionHistoryEntry class. | ||||||
|  */ |  */ | ||||||
| angular.module('connection').factory('ConnectionHistoryEntry', [function defineConnectionHistoryEntry() { | angular.module('rest').factory('ConnectionHistoryEntry', [function defineConnectionHistoryEntry() { | ||||||
|              |              | ||||||
|     /** |     /** | ||||||
|      * The object returned by REST API calls when representing the data |      * The object returned by REST API calls when representing the data | ||||||
							
								
								
									
										94
									
								
								guacamole/src/main/webapp/app/rest/types/PermissionPatch.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								guacamole/src/main/webapp/app/rest/types/PermissionPatch.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | |||||||
|  | /* | ||||||
|  |  * 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 PermissionPatch class. | ||||||
|  |  */ | ||||||
|  | angular.module('rest').factory('PermissionPatch', [function definePermissionPatch() { | ||||||
|  |              | ||||||
|  |     /** | ||||||
|  |      * The object returned by REST API calls when representing changes to the | ||||||
|  |      * permissions granted to a specific user. | ||||||
|  |      *  | ||||||
|  |      * @constructor | ||||||
|  |      * @param {PermissionPatch|Object} [template={}] | ||||||
|  |      *     The object whose properties should be copied within the new | ||||||
|  |      *     PermissionPatch. | ||||||
|  |      */ | ||||||
|  |     var PermissionPatch = function PermissionPatch(template) { | ||||||
|  |  | ||||||
|  |         // Use empty object by default | ||||||
|  |         template = template || {}; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The operation to apply to the permissions indicated by the path. | ||||||
|  |          * Valid operation values are defined within PermissionPatch.Operation. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.op = template.op; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The path of the permissions to modify. Depending on the type of the | ||||||
|  |          * permission, this will be either "/connectionPermissions/ID", | ||||||
|  |          * "/connectionGroupPermissions/ID", "/userPermissions/ID", or | ||||||
|  |          * "/systemPermissions", where "ID" is the identifier of the object | ||||||
|  |          * to which the permissions apply, if any. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.path = template.path; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The permissions being added or removed. If the permission applies to | ||||||
|  |          * an object, such as a connection or connection group, this will be a | ||||||
|  |          * value from PermissionSet.ObjectPermissionType. If the permission | ||||||
|  |          * applies to the system as a whole (the path is "/systemPermissions"), | ||||||
|  |          * this will be a value from PermissionSet.SystemPermissionType. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.value = template.value; | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * All valid patch operations for permissions. Currently, only add and | ||||||
|  |      * remove are supported. | ||||||
|  |      */ | ||||||
|  |     PermissionPatch.Operation = { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Adds (grants) the specified permission. | ||||||
|  |          */ | ||||||
|  |         ADD : "add", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Removes (revokes) the specified permission. | ||||||
|  |          */ | ||||||
|  |         REMOVE : "remove" | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return PermissionPatch; | ||||||
|  |  | ||||||
|  | }]); | ||||||
							
								
								
									
										280
									
								
								guacamole/src/main/webapp/app/rest/types/PermissionSet.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								guacamole/src/main/webapp/app/rest/types/PermissionSet.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,280 @@ | |||||||
|  | /* | ||||||
|  |  * 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 PermissionSet class. | ||||||
|  |  */ | ||||||
|  | angular.module('rest').factory('PermissionSet', [function definePermissionSet() { | ||||||
|  |              | ||||||
|  |     /** | ||||||
|  |      * The object returned by REST API calls when representing the permissions | ||||||
|  |      * granted to a specific user. | ||||||
|  |      *  | ||||||
|  |      * @constructor | ||||||
|  |      * @param {PermissionSet|Object} [template={}] | ||||||
|  |      *     The object whose properties should be copied within the new | ||||||
|  |      *     PermissionSet. | ||||||
|  |      */ | ||||||
|  |     var PermissionSet = function PermissionSet(template) { | ||||||
|  |  | ||||||
|  |         // Use empty object by default | ||||||
|  |         template = template || {}; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Map of connection identifiers to the corresponding array of granted | ||||||
|  |          * permissions. Each permission is represented by a string listed | ||||||
|  |          * within PermissionSet.ObjectPermissionType. | ||||||
|  |          * | ||||||
|  |          * @type Object.<String, String[]> | ||||||
|  |          */ | ||||||
|  |         this.connectionPermissions = template.connectionPermissions || {}; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Map of connection group identifiers to the corresponding array of | ||||||
|  |          * granted permissions. Each permission is represented by a string | ||||||
|  |          * listed within PermissionSet.ObjectPermissionType. | ||||||
|  |          * | ||||||
|  |          * @type Object.<String, String[]> | ||||||
|  |          */ | ||||||
|  |         this.connectionGroupPermissions = template.connectionGroupPermissions || {}; | ||||||
|  |          | ||||||
|  |         /** | ||||||
|  |          * Map of user identifiers to the corresponding array of granted | ||||||
|  |          * permissions. Each permission is represented by a string listed | ||||||
|  |          * within PermissionSet.ObjectPermissionType. | ||||||
|  |          * | ||||||
|  |          * @type Object.<String, String[]> | ||||||
|  |          */ | ||||||
|  |         this.userPermissions = template.userPermissions || {}; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Array of granted system permissions. Each permission is represented | ||||||
|  |          * by a string listed within PermissionSet.SystemPermissionType. | ||||||
|  |          * | ||||||
|  |          * @type String[] | ||||||
|  |          */ | ||||||
|  |         this.systemPermissions = template.systemPermissions || []; | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Valid object permission type strings. | ||||||
|  |      */ | ||||||
|  |     PermissionSet.ObjectPermissionType = { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Permission to read from the specified object. | ||||||
|  |          */ | ||||||
|  |         READ : "READ", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Permission to update the specified object. | ||||||
|  |          */ | ||||||
|  |         UPDATE : "UPDATE", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Permission to delete the specified object. | ||||||
|  |          */ | ||||||
|  |         DELETE : "DELETE", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Permission to administer the specified object | ||||||
|  |          */ | ||||||
|  |         ADMINISTER : "ADMINISTER" | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Valid system permission type strings. | ||||||
|  |      */ | ||||||
|  |     PermissionSet.SystemPermissionType = { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Permission to administer the entire system. | ||||||
|  |          */ | ||||||
|  |         ADMINISTER : "ADMINISTER", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Permission to create new users. | ||||||
|  |          */ | ||||||
|  |         CREATE_USER : "CREATE_USER", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Permission to create new connections. | ||||||
|  |          */ | ||||||
|  |         CREATE_CONNECTION : "CREATE_CONNECTION", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Permission to create new connection groups. | ||||||
|  |          */ | ||||||
|  |         CREATE_CONNECTION_GROUP : "CREATE_CONNECTION_GROUP" | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether the given permission is granted for at least one | ||||||
|  |      * arbitrary object, regardless of ID. | ||||||
|  |      * | ||||||
|  |      * @param {Object.<String, String[]>} permMap | ||||||
|  |      *     The permission map to check, where each entry maps an object | ||||||
|  |      *     identifer to the array of granted permissions. | ||||||
|  |      * | ||||||
|  |      * @param {String} type | ||||||
|  |      *     The permission to search for, as defined by | ||||||
|  |      *     PermissionSet.ObjectPermissionType. | ||||||
|  |      *      | ||||||
|  |      * @returns {Boolean} | ||||||
|  |      *     true if the permission is present (granted), false otherwise. | ||||||
|  |      */ | ||||||
|  |     var containsPermission = function containsPermission(permMap, type) { | ||||||
|  |  | ||||||
|  |         // Search all identifiers for given permission | ||||||
|  |         for (var identifier in permMap) { | ||||||
|  |  | ||||||
|  |             // If permission is granted, then no further searching is necessary | ||||||
|  |             if (permMap[identifier].indexOf(type) !== -1) | ||||||
|  |                 return true; | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // No such permission exists | ||||||
|  |         return false; | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether the given permission is granted for the arbitrary | ||||||
|  |      * object having the given ID. If no ID is given, this function determines | ||||||
|  |      * whether the permission is granted at all for any such arbitrary object. | ||||||
|  |      * | ||||||
|  |      * @param {Object.<String, String[]>} permMap | ||||||
|  |      *     The permission map to check, where each entry maps an object | ||||||
|  |      *     identifer to the array of granted permissions. | ||||||
|  |      * | ||||||
|  |      * @param {String} type | ||||||
|  |      *     The permission to search for, as defined by | ||||||
|  |      *     PermissionSet.ObjectPermissionType. | ||||||
|  |      *      | ||||||
|  |      * @param {String} [identifier] | ||||||
|  |      *     The identifier of the object to which the permission applies. | ||||||
|  |      * | ||||||
|  |      * @returns {Boolean} | ||||||
|  |      *     true if the permission is present (granted), false otherwise. | ||||||
|  |      */ | ||||||
|  |     var hasPermission = function hasPermission(permMap, type, identifier) { | ||||||
|  |  | ||||||
|  |         // If no identifier given, search ignoring the identifier | ||||||
|  |         if (!identifier) | ||||||
|  |             return containsPermission(permMap, type); | ||||||
|  |  | ||||||
|  |         // If identifier not present at all, there are no such permissions | ||||||
|  |         if (!(identifier in permMap)) | ||||||
|  |             return false; | ||||||
|  |  | ||||||
|  |         return permMap[identifier].indexOf(type) !== -1; | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether the given permission is granted for the connection | ||||||
|  |      * having the given ID. | ||||||
|  |      * | ||||||
|  |      * @param {PermissionSet|Object} permSet | ||||||
|  |      *     The permission set to check. | ||||||
|  |      * | ||||||
|  |      * @param {String} type | ||||||
|  |      *     The permission to search for, as defined by | ||||||
|  |      *     PermissionSet.ObjectPermissionType. | ||||||
|  |      *      | ||||||
|  |      * @param {String} identifier | ||||||
|  |      *     The identifier of the connection to which the permission applies. | ||||||
|  |      * | ||||||
|  |      * @returns {Boolean} | ||||||
|  |      *     true if the permission is present (granted), false otherwise. | ||||||
|  |      */ | ||||||
|  |     PermissionSet.hasConnectionPermission = function hasConnectionPermission(permSet, type, identifier) { | ||||||
|  |         return hasPermission(permSet.connectionPermissions, type, identifier); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether the given permission is granted for the connection group | ||||||
|  |      * having the given ID. | ||||||
|  |      * | ||||||
|  |      * @param {PermissionSet|Object} permSet | ||||||
|  |      *     The permission set to check. | ||||||
|  |      * | ||||||
|  |      * @param {String} type | ||||||
|  |      *     The permission to search for, as defined by | ||||||
|  |      *     PermissionSet.ObjectPermissionType. | ||||||
|  |      *      | ||||||
|  |      * @param {String} identifier | ||||||
|  |      *     The identifier of the connection group to which the permission | ||||||
|  |      *     applies. | ||||||
|  |      * | ||||||
|  |      * @returns {Boolean} | ||||||
|  |      *     true if the permission is present (granted), false otherwise. | ||||||
|  |      */ | ||||||
|  |     PermissionSet.hasConnectionGroupPermission = function hasConnectionGroupPermission(permSet, type, identifier) { | ||||||
|  |         return hasPermission(permSet.connectionGroupPermissions, type, identifier); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether the given permission is granted for the user having the  | ||||||
|  |      * given ID. | ||||||
|  |      * | ||||||
|  |      * @param {PermissionSet|Object} permSet | ||||||
|  |      *     The permission set to check. | ||||||
|  |      * | ||||||
|  |      * @param {String} type | ||||||
|  |      *     The permission to search for, as defined by | ||||||
|  |      *     PermissionSet.ObjectPermissionType. | ||||||
|  |      *      | ||||||
|  |      * @param {String} identifier | ||||||
|  |      *     The identifier of the user to which the permission applies. | ||||||
|  |      * | ||||||
|  |      * @returns {Boolean} | ||||||
|  |      *     true if the permission is present (granted), false otherwise. | ||||||
|  |      */ | ||||||
|  |     PermissionSet.hasUserPermission = function hasUserPermission(permSet, type, identifier) { | ||||||
|  |         return hasPermission(permSet.userPermissions, type, identifier); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether the given permission is granted at the system level. | ||||||
|  |      * | ||||||
|  |      * @param {PermissionSet|Object} permSet | ||||||
|  |      *     The permission set to check. | ||||||
|  |      * | ||||||
|  |      * @param {String} type | ||||||
|  |      *     The permission to search for, as defined by | ||||||
|  |      *     PermissionSet.SystemPermissionType. | ||||||
|  |      * | ||||||
|  |      * @returns {Boolean} | ||||||
|  |      *     true if the permission is present (granted), false otherwise. | ||||||
|  |      */ | ||||||
|  |     PermissionSet.hasSystemPermission = function hasSystemPermission(permSet, type) { | ||||||
|  |         return permSet.systemPermissions.indexOf(type) !== -1; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return PermissionSet; | ||||||
|  |  | ||||||
|  | }]); | ||||||
| @@ -21,37 +21,49 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A service for performing useful user related functionaltiy. |  * Service which defines the Protocol class. | ||||||
|  */ |  */ | ||||||
| angular.module('user').factory('userService', ['$injector', function userService($injector) { | angular.module('rest').factory('Protocol', [function defineProtocol() { | ||||||
|              |  | ||||||
|     var permissionCheckService          = $injector.get('permissionCheckService'); |  | ||||||
|              |  | ||||||
|     var service = {}; |  | ||||||
|              |              | ||||||
|     /** |     /** | ||||||
|      * Filters the list of users using the provided permissions. |      * The object returned by REST API calls when representing the data | ||||||
|  |      * associated with a supported remote desktop protocol. | ||||||
|      *  |      *  | ||||||
|      * @param {array} users The user list. |      * @constructor | ||||||
|      *  |      * @param {Protocol|Object} [template={}] | ||||||
|      * @param {object} permissionList The list of permissions to use  |      *     The object whose properties should be copied within the new | ||||||
|      *                                when filtering. |      *     Protocol. | ||||||
|      *  |  | ||||||
|      * @param {object} permissionCriteria The required permission for each user. |  | ||||||
|      *                           |  | ||||||
|      * @return {array} The filtered list. |  | ||||||
|      */ |      */ | ||||||
|     service.filterUsersByPermission = function filterUsersByPermission(users, permissionList, permissionCriteria) { |     var Protocol = function Protocol(template) { | ||||||
|         for(var i = 0; i < users.length; i++) { | 
 | ||||||
|             if(!permissionCheckService.checkPermission(permissionList,  |         // Use empty object by default
 | ||||||
|                     "USER", user.username, permissionCriteria)) { |         template = template || {}; | ||||||
|                 items.splice(i, 1); | 
 | ||||||
|                 continue; |         /** | ||||||
|             }  |          * The name which uniquely identifies this protocol. | ||||||
|         } |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.name = template.name; | ||||||
|  | 
 | ||||||
|  |         /** | ||||||
|  |          * A human-readable name for this protocol. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.title = template.title; | ||||||
|  | 
 | ||||||
|  |         /** | ||||||
|  |          * An array of all known parameters for this protocol, their types, | ||||||
|  |          * and other information. | ||||||
|  |          * | ||||||
|  |          * @type ProtocolParameter[] | ||||||
|  |          * @default [] | ||||||
|  |          */ | ||||||
|  |         this.parameters = template.parameters || []; | ||||||
| 
 | 
 | ||||||
|         return users; |  | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     return service; |     return Protocol; | ||||||
|  | 
 | ||||||
| }]); | }]); | ||||||
							
								
								
									
										152
									
								
								guacamole/src/main/webapp/app/rest/types/ProtocolParameter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								guacamole/src/main/webapp/app/rest/types/ProtocolParameter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | |||||||
|  | /* | ||||||
|  |  * 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 ProtocolParameter class. | ||||||
|  |  */ | ||||||
|  | angular.module('rest').factory('ProtocolParameter', [function defineProtocolParameter() { | ||||||
|  |              | ||||||
|  |     /** | ||||||
|  |      * The object returned by REST API calls when representing the data | ||||||
|  |      * associated with a configuration parameter of a remote desktop protocol. | ||||||
|  |      *  | ||||||
|  |      * @constructor | ||||||
|  |      * @param {ProtocolParameter|Object} [template={}] | ||||||
|  |      *     The object whose properties should be copied within the new | ||||||
|  |      *     ProtocolParameter. | ||||||
|  |      */ | ||||||
|  |     var ProtocolParameter = function ProtocolParameter(template) { | ||||||
|  |  | ||||||
|  |         // Use empty object by default | ||||||
|  |         template = template || {}; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The name which uniquely identifies this parameter. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.name = template.name; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * A human-readable name for this parameter. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.title = template.title; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type string defining which values this parameter may contain, | ||||||
|  |          * as well as what properties are applicable. Valid types are listed | ||||||
|  |          * within ProtocolParameter.Type. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          * @default ProtocolParameter.Type.TEXT | ||||||
|  |          */ | ||||||
|  |         this.type = template.type || ProtocolParameter.Type.TEXT; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The value to set the parameter to, in the case of a BOOLEAN | ||||||
|  |          * parameter, to enable that parameter's effect. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.value = template.value; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * All possible legal values for this parameter. This property is only | ||||||
|  |          * applicable to ENUM type parameters. | ||||||
|  |          * | ||||||
|  |          * @type ProtocolParameterOption[] | ||||||
|  |          */ | ||||||
|  |         this.options = template.options; | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * All valid protocol parameter types. | ||||||
|  |      */ | ||||||
|  |     ProtocolParameter.Type = { | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type string associated with parameters that may contain a single | ||||||
|  |          * line of arbitrary text. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         TEXT : "TEXT", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type string associated with parameters that may contain an | ||||||
|  |          * arbitrary string, where that string represents the username of the | ||||||
|  |          * user authenticating with the remote desktop service. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         USERNAME : "USERNAME", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type string associated with parameters that may contain an | ||||||
|  |          * arbitrary string, where that string represents the password of the | ||||||
|  |          * user authenticating with the remote desktop service. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         PASSWORD : "PASSWORD", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type string associated with parameters that may contain only | ||||||
|  |          * numeric values. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         NUMERIC : "NUMERIC", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type string associated with parameters that may contain only a | ||||||
|  |          * single possible value, where that value enables the parameter's | ||||||
|  |          * effect. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         BOOLEAN : "BOOLEAN", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type string associated with parameters that may contain a | ||||||
|  |          * strictly-defined set of possible values. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         ENUM : "ENUM", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The type string associated with parameters that may contain any | ||||||
|  |          * number of lines of arbitrary text. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         MULTILINE : "MULTILINE" | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return ProtocolParameter; | ||||||
|  |  | ||||||
|  | }]); | ||||||
| @@ -20,40 +20,42 @@ | |||||||
|  * THE SOFTWARE. |  * THE SOFTWARE. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package org.glyptodon.guacamole.net.basic.rest.user; |  | ||||||
| 
 |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.List; |  | ||||||
| import org.glyptodon.guacamole.GuacamoleException; |  | ||||||
| import org.glyptodon.guacamole.net.auth.Directory; |  | ||||||
| import org.glyptodon.guacamole.net.auth.User; |  | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * A service for performing useful manipulations on REST Users. |  * Service which defines the ProtocolParameterOption class. | ||||||
|  *  |  | ||||||
|  * @author James Muehlner |  | ||||||
|  */ |  */ | ||||||
| public class UserService { | angular.module('rest').factory('ProtocolParameterOption', [function defineProtocolParameterOption() { | ||||||
|              |              | ||||||
|     /** |     /** | ||||||
|      * Converts a user directory to a list of APIUser objects for  |      * The object returned by REST API calls when representing a single possible | ||||||
|      * exposing with the REST endpoints. |      * legal value of a configuration parameter of a remote desktop protocol. | ||||||
|      *  |      *  | ||||||
|      * @param userDirectory The user directory to convert for REST endpoint use. |      * @constructor | ||||||
|      * @return A List of APIUser objects for use with the REST endpoint. |      * @param {ProtocolParameterOption|Object} [template={}] | ||||||
|      * @throws GuacamoleException If an error occurs while converting the  |      *     The object whose properties should be copied within the new | ||||||
|      *                            user directory. |      *     ProtocolParameterOption. | ||||||
|      */ |      */ | ||||||
|     public List<APIUser> convertUserList(Directory<String, User> userDirectory)  |     var ProtocolParameterOption = function ProtocolParameterOption(template) { | ||||||
|             throws GuacamoleException { |  | ||||||
| 
 | 
 | ||||||
|         List<APIUser> restUsers = new ArrayList<APIUser>(); |         // Use empty object by default
 | ||||||
|  |         template = template || {}; | ||||||
| 
 | 
 | ||||||
|         for(String username : userDirectory.getIdentifiers()) |         /** | ||||||
|             restUsers.add(new APIUser(userDirectory.get(username))); |          * A human-readable name for this parameter value. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.title = template.title; | ||||||
| 
 | 
 | ||||||
|         return restUsers; |         /** | ||||||
|  |          * The actual value to set the parameter to, if this option is | ||||||
|  |          * selected. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.value = template.value; | ||||||
| 
 | 
 | ||||||
|     } |     }; | ||||||
| 
 | 
 | ||||||
| } |     return ProtocolParameterOption; | ||||||
|  | 
 | ||||||
|  | }]); | ||||||
| @@ -21,6 +21,43 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * The module for code relating to connections. |  * Service which defines the User class. | ||||||
|  */ |  */ | ||||||
| angular.module('connection', ['auth']); | angular.module('rest').factory('User', [function defineUser() { | ||||||
|  |              | ||||||
|  |     /** | ||||||
|  |      * The object returned by REST API calls when representing the data | ||||||
|  |      * associated with a user. | ||||||
|  |      *  | ||||||
|  |      * @constructor | ||||||
|  |      * @param {User|Object} [template={}] | ||||||
|  |      *     The object whose properties should be copied within the new | ||||||
|  |      *     User. | ||||||
|  |      */ | ||||||
|  |     var User = function User(template) { | ||||||
|  | 
 | ||||||
|  |         // Use empty object by default
 | ||||||
|  |         template = template || {}; | ||||||
|  | 
 | ||||||
|  |         /** | ||||||
|  |          * The name which uniquely identifies this user. | ||||||
|  |          * | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.username = template.username; | ||||||
|  | 
 | ||||||
|  |         /** | ||||||
|  |          * This user's password. Note that the REST API may not populate this | ||||||
|  |          * property for the sake of security. In most cases, it's not even | ||||||
|  |          * possible for the authentication layer to retrieve the user's true | ||||||
|  |          * password. | ||||||
|  |          *  | ||||||
|  |          * @type String | ||||||
|  |          */ | ||||||
|  |         this.password = template.password; | ||||||
|  | 
 | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return User; | ||||||
|  | 
 | ||||||
|  | }]); | ||||||
| @@ -1,100 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * The DAO for connection operations agains the REST API. |  | ||||||
|  */ |  | ||||||
| angular.module('user').factory('userDAO', ['$http', 'authenticationService', |  | ||||||
|         function userDAO($http, authenticationService) { |  | ||||||
|              |  | ||||||
|     var service = {}; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to get the list of users, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.getUsers = function getUsers() { |  | ||||||
|         return $http.get("api/user?token=" + authenticationService.getCurrentToken()); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to get the list of users, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {string} userID The ID of the user to retrieve. |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.getUser = function getUser(userID) { |  | ||||||
|         return $http.get("api/user/" + userID + "/?token=" + authenticationService.getCurrentToken()); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to delete a user, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {object} user The user to delete. |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.deleteUser = function deleteUser(user) { |  | ||||||
|         return $http['delete']( |  | ||||||
|             "api/user/" + user.username +  |  | ||||||
|             "?token=" + authenticationService.getCurrentToken()); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to create a user, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {object} user The user to create. |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.createUser = function createUser(user) { |  | ||||||
|         return $http.post( |  | ||||||
|             "api/user/"  |  | ||||||
|             + "?token=" + authenticationService.getCurrentToken(),  |  | ||||||
|             user |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Makes a request to the REST API to save a user, |  | ||||||
|      * returning a promise that can be used for processing the results of the call. |  | ||||||
|      *  |  | ||||||
|      * @param {object} user The user to update. |  | ||||||
|      *                           |  | ||||||
|      * @returns {promise} A promise for the HTTP call. |  | ||||||
|      */ |  | ||||||
|     service.saveUser = function saveUser(user) { |  | ||||||
|         return $http.post( |  | ||||||
|             "api/user/" + user.username +  |  | ||||||
|             "?token=" + authenticationService.getCurrentToken(),  |  | ||||||
|         user); |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     return service; |  | ||||||
| }]); |  | ||||||
| @@ -48,7 +48,7 @@ THE SOFTWARE. | |||||||
|         <div id="notificationArea"> |         <div id="notificationArea"> | ||||||
|             <div ng-repeat="wrapper in notifications"> |             <div ng-repeat="wrapper in notifications"> | ||||||
|                 <guac-notification notification="wrapper.notification"/> |                 <guac-notification notification="wrapper.notification"/> | ||||||
|             <div>                 |             </div>                 | ||||||
|         </div> |         </div> | ||||||
|          |          | ||||||
|         <script type="text/javascript" src="guacamole.min.js"></script> |         <script type="text/javascript" src="guacamole.min.js"></script> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user