Repository: ckan/ckan

Issue:
 URL ‘/hello’ rule in public site
I suggest providing the /hello path only in debug mode.

### CKAN Version if known (or site URL)
2.8

### Please describe the expected behaviour
Ckan extension can determine whether to use /hello routing.

### Please describe the actual behaviour
Currently ckan core provides the "/hello" path by default.
In a production build, I think this is unnecessary information for users.
There is no way to remove "/hello" routing from an extension without modifying the core, and it must be redefined.

### What steps can be taken to reproduce the issue? 
It is being routed on some sites based on ckan
eg)
https://demo.ckan.org/hello
https://data.stadt-zuerich.ch/hello
https://data.gov.ie/hello
https://ckan0.cf.opendata.inter.sandbox-toronto.ca/hello



Discussion:

Resolving patch:
diff --git a/ckan/config/middleware/flask_app.py b/ckan/config/middleware/flask_app.py
--- a/ckan/config/middleware/flask_app.py
+++ b/ckan/config/middleware/flask_app.py
@@ -176,14 +176,6 @@ def ungettext_alias():
 
     babel.localeselector(get_locale)
 
-    @app.route('/hello', methods=['GET'])
-    def hello_world():
-        return 'Hello World, this is served by Flask'
-
-    @app.route('/hello', methods=['POST'])
-    def hello_world_post():
-        return 'Hello World, this was posted to Flask'
-
     # WebAssets
     _setup_webassets(app)
 
diff --git a/ckan/plugins/toolkit.py b/ckan/plugins/toolkit.py
--- a/ckan/plugins/toolkit.py
+++ b/ckan/plugins/toolkit.py
@@ -498,11 +498,7 @@ def _get_endpoint(cls):
                 return common.c.controller, common.c.action
             except AttributeError:
                 return (None, None)
-        # there are some routes('hello_world') that are not using blueprint
-        # For such case, let's assume that view function is a controller
-        # itself and action is None.
-        if len(endpoint) == 1:
-            return endpoint + (None,)
+
         return endpoint
 
     def __getattr__(self, name):
diff --git a/ckanext/example_flask_iblueprint/plugin.py b/ckanext/example_flask_iblueprint/plugin.py
--- a/ckanext/example_flask_iblueprint/plugin.py
+++ b/ckanext/example_flask_iblueprint/plugin.py
@@ -11,21 +11,8 @@ def hello_plugin():
     return u'Hello World, this is served from an extension'
 
 
-def override_pylons_about():
-    u'''A simple replacement for the pylons About page.'''
-    return render_template(u'about.html')
-
-
-def override_pylons_about_with_core_template():
-    u'''
-    Override the pylons about controller to render the core about page
-    template.
-    '''
-    return render_template(u'home/about.html')
-
-
-def override_flask_hello():
-    u'''A simple replacement for the flash Hello view function.'''
+def override_flask_home():
+    u'''A simple replacement for the flash Home view function.'''
     html = u'''<!DOCTYPE html>
 <html>
     <head>
@@ -94,10 +81,7 @@ def get_blueprint(self):
         # Add plugin url rules to Blueprint object
         rules = [
             (u'/hello_plugin', u'hello_plugin', hello_plugin),
-            (u'/about', u'about', override_pylons_about),
-            (u'/about_core', u'about_core',
-                override_pylons_about_with_core_template),
-            (u'/hello', u'hello', override_flask_hello),
+            (u'/', u'home', override_flask_home),
             (u'/helper_not_here', u'helper_not_here', helper_not_here),
             (u'/helper', u'helper_here', helper_here),
         ]


Test patch:
diff --git a/ckan/tests/config/test_middleware.py b/ckan/tests/config/test_middleware.py
--- a/ckan/tests/config/test_middleware.py
+++ b/ckan/tests/config/test_middleware.py
@@ -144,18 +144,15 @@ def test_ask_around_flask_core_route_get(self):
         app = app.app
 
         environ = {
-            'PATH_INFO': '/hello',
+            'PATH_INFO': '/',
             'REQUEST_METHOD': 'GET',
         }
         wsgiref.util.setup_testing_defaults(environ)
 
         answers = app.ask_around(environ)
 
-        # Even though this route is defined in Flask, there is catch all route
-        # in Pylons for all requests to point arbitrary urls to templates with
-        # the same name, so we get two positive answers
         eq_(answers, [(True, 'flask_app', 'core'),
-                      (True, 'pylons_app', 'core')])
+                      (False, 'pylons_app')])
 
     def test_ask_around_flask_core_route_post(self):
 
@@ -165,7 +162,7 @@ def test_ask_around_flask_core_route_post(self):
         app = app.app
 
         environ = {
-            'PATH_INFO': '/hello',
+            'PATH_INFO': '/group/new',
             'REQUEST_METHOD': 'POST',
         }
         wsgiref.util.setup_testing_defaults(environ)
@@ -330,7 +327,7 @@ def test_flask_core_route_is_served_by_flask(self):
 
         app = self._get_test_app()
 
-        res = app.get('/hello')
+        res = app.get('/')
 
         eq_(res.environ['ckan.app'], 'flask_app')
 
@@ -562,7 +559,7 @@ def before_map(self, _map):
                      controller=self.controller, action='view')
 
         # This one conflicts with a core Flask route
-        _map.connect('/hello',
+        _map.connect('/about',
                      controller=self.controller, action='view')
 
         _map.connect('/pylons_route_flask_url_for',
diff --git a/ckan/tests/test_common.py b/ckan/tests/test_common.py
--- a/ckan/tests/test_common.py
+++ b/ckan/tests/test_common.py
@@ -222,7 +222,7 @@ def test_params_also_works_on_flask_request(self):
 
         app = helpers._get_test_app()
 
-        with app.flask_app.test_request_context(u'/hello?a=1'):
+        with app.flask_app.test_request_context(u'/?a=1'):
 
             assert u'a' in ckan_request.args
             assert u'a' in ckan_request.params
@@ -231,7 +231,7 @@ def test_other_missing_attributes_raise_attributeerror_exceptions(self):
 
         app = helpers._get_test_app()
 
-        with app.flask_app.test_request_context(u'/hello?a=1'):
+        with app.flask_app.test_request_context(u'/?a=1'):
 
             assert_raises(AttributeError, getattr, ckan_request, u'not_here')
 
diff --git a/ckanext/example_flask_iblueprint/tests/test_routes.py b/ckanext/example_flask_iblueprint/tests/test_routes.py
--- a/ckanext/example_flask_iblueprint/tests/test_routes.py
+++ b/ckanext/example_flask_iblueprint/tests/test_routes.py
@@ -24,28 +24,12 @@ def test_plugin_route(self):
 
         eq_(u'Hello World, this is served from an extension', res.body)
 
-    def test_plugin_route_core_pylons_override(self):
-        u'''Test extension overrides pylons core route.'''
-        res = self.app.get(u'/about')
-
-        ok_(u'This is an about page served from an extention, overriding the pylons url.' in res.body)
-
     def test_plugin_route_core_flask_override(self):
         u'''Test extension overrides flask core route.'''
-        res = self.app.get(u'/hello')
+        res = self.app.get(u'/')
 
         ok_(u'Hello World, this is served from an extension, overriding the flask url.' in res.body)
 
-# TODO This won't work until the url_for work is merged
-#    def test_plugin_route_core_flask_override_with_template(self):
-#        u'''
-#        Test extension overrides a python core route, rendering a core
-#        template (home/about.html).
-#        '''
-#        res = self.app.get(u'/about_core')
-#
-#        ok_(u'<title>About - CKAN</title>' in res.ubody)
-
     def test_plugin_route_with_helper(self):
         u'''
         Test extension rendering with a helper method that exists shouldn't