From e73a767bb731e72b01d46c9bce4ee970ef59c901 Mon Sep 17 00:00:00 2001 From: Marcin Erdmann Date: Wed, 21 Nov 2012 21:50:59 +0000 Subject: [PATCH] Add GAE services to route validation closures' scope. Conflicts: core/src/main/groovyx/gaelyk/routes/Route.groovy --- .../main/groovyx/gaelyk/routes/Route.groovy | 11 ++++-- .../gaelyk/routes/RoutesFilterTest.groovy | 35 +++++++++++++++++-- .../groovyx/gaelyk/routes/RoutesTest.groovy | 16 ++++++++- .../test/groovyx/gaelyk/routes/routes.sample | 4 ++- .../pages/tutorial/flexibleUrlRouting.gtpl | 12 ++++++- 5 files changed, 70 insertions(+), 8 deletions(-) diff --git a/core/src/main/groovyx/gaelyk/routes/Route.groovy b/core/src/main/groovyx/gaelyk/routes/Route.groovy index 45bfa342..70982ea5 100644 --- a/core/src/main/groovyx/gaelyk/routes/Route.groovy +++ b/core/src/main/groovyx/gaelyk/routes/Route.groovy @@ -18,6 +18,7 @@ package groovyx.gaelyk.routes import java.util.regex.Matcher import java.util.regex.Pattern import javax.servlet.http.HttpServletRequest +import groovyx.gaelyk.GaelykBindingEnhancer /** * Representation of a route URL mapping. @@ -148,10 +149,14 @@ class Route { def clonedValidator = this.validator.clone() // adds the request to the variables available for validation - def variablesAndRequest = variableMap.clone() - variablesAndRequest.request = request + def binding = new Binding() + GaelykBindingEnhancer.bind(binding) + def validatorDelegate = binding.variables - clonedValidator.delegate = variablesAndRequest + validatorDelegate += variableMap.clone() + validatorDelegate.request = request + + clonedValidator.delegate = validatorDelegate clonedValidator.resolveStrategy = Closure.DELEGATE_ONLY boolean validated = false diff --git a/core/src/test/groovyx/gaelyk/routes/RoutesFilterTest.groovy b/core/src/test/groovyx/gaelyk/routes/RoutesFilterTest.groovy index 49c91443..5230d3de 100644 --- a/core/src/test/groovyx/gaelyk/routes/RoutesFilterTest.groovy +++ b/core/src/test/groovyx/gaelyk/routes/RoutesFilterTest.groovy @@ -22,7 +22,7 @@ import javax.servlet.ServletRequest import javax.servlet.ServletResponse /** - * + * * @author Guillaume Laforge */ class RoutesFilterTest extends GroovyTestCase { @@ -193,7 +193,7 @@ class RoutesFilterTest extends GroovyTestCase { ] as RequestDispatcher def attributes = [:] - + def request = [ getRequestURI: { -> "/somewhere" }, getQueryString: { -> "" }, @@ -216,4 +216,35 @@ class RoutesFilterTest extends GroovyTestCase { assert attributes[RoutesFilter.ORIGINAL_URI] == "/somewhere" } + void testValidatedRoute() { + def forwarded = false + def dispatched = "" + + def dispatcher = [ + forward: { ServletRequest req, ServletResponse resp -> forwarded = true } + ] as RequestDispatcher + + def attributes = [:] + + def request = [ + getRequestURI: {-> "/validate" }, + getQueryString: {-> "" }, + getMethod: {-> "GET" }, + getRequestDispatcher: { String s -> dispatched = s; return dispatcher }, + setAttribute: { String name, val -> attributes[name] = val }, + getAttribute: { String name -> attributes[name] }, + getServletPath: {-> '' }, + getPathInfo: {-> '/validate' } + ] as HttpServletRequest + + def response = [:] as HttpServletResponse + + def chain = [:] as FilterChain + + filter.doFilter(request, response, chain) + + assert forwarded + assert dispatched == "/validate.gtpl" + assert attributes[RoutesFilter.ORIGINAL_URI] == "/validate" + } } diff --git a/core/src/test/groovyx/gaelyk/routes/RoutesTest.groovy b/core/src/test/groovyx/gaelyk/routes/RoutesTest.groovy index 46c90e4a..359d7371 100644 --- a/core/src/test/groovyx/gaelyk/routes/RoutesTest.groovy +++ b/core/src/test/groovyx/gaelyk/routes/RoutesTest.groovy @@ -16,6 +16,8 @@ package groovyx.gaelyk.routes import static groovyx.gaelyk.TestUtil.request as r +import com.google.appengine.tools.development.testing.LocalServiceTestHelper +import com.google.appengine.tools.development.testing.LocalUserServiceTestConfig /** * Tests for the routing support. @@ -24,7 +26,19 @@ import static groovyx.gaelyk.TestUtil.request as r */ class RoutesTest extends GroovyTestCase { - /** Tests the variable extraction logic */ + LocalServiceTestHelper helper = new LocalServiceTestHelper(new LocalUserServiceTestConfig()) + + protected void setUp() { + super.setUp() + helper.setUp() + } + + protected void tearDown() { + super.tearDown() + helper.tearDown() + } + +/** Tests the variable extraction logic */ void testRoutesParameterExtraction() { def inputOutputExpected = [ "/": [], diff --git a/core/src/test/groovyx/gaelyk/routes/routes.sample b/core/src/test/groovyx/gaelyk/routes/routes.sample index e8134586..7170f318 100644 --- a/core/src/test/groovyx/gaelyk/routes/routes.sample +++ b/core/src/test/groovyx/gaelyk/routes/routes.sample @@ -4,4 +4,6 @@ all "/ignore", ignore: true get "/redirect", redirect: "/elsewhere.gtpl" -get "/@cust/home", forward: "/customer.groovy?cust=@cust", namespace: { cust } \ No newline at end of file +get "/@cust/home", forward: "/customer.groovy?cust=@cust", namespace: { cust } + +get "/validate", forward: "/validate.gtpl", validate: { users in com.google.appengine.api.users.UserService } \ No newline at end of file diff --git a/website/war/WEB-INF/pages/tutorial/flexibleUrlRouting.gtpl b/website/war/WEB-INF/pages/tutorial/flexibleUrlRouting.gtpl index c0e6e7cb..33500941 100644 --- a/website/war/WEB-INF/pages/tutorial/flexibleUrlRouting.gtpl +++ b/website/war/WEB-INF/pages/tutorial/flexibleUrlRouting.gtpl @@ -316,7 +316,7 @@ but you can use boolean logic that you want, like year.isNumber(),

-In addition to the path variables, you also have access to the request from within the validation closure. +In addition to the path variables, you also have access to the request as well as all GAE services from within the validation closure. For example, if you wanted to check that a particular attribute is present in the request, like checking a user is registered to access a message board, you could do:

@@ -327,6 +327,16 @@ like checking a user is registered to access a message board, you could do: validate: { request.registered == true } +

+Another example would be to verify if the current user is an admin before allowing the route to kick in. The GAE services are available under the same variable names as in groovlets. +

+ +
+    get "/only-admin",
+        forward: "/secured.groovy",
+        validate: { users.isUserAdmin() }
+
+

Capability-aware routing