Repository: ckan/ckan

Issue:
Groups and organizations can be visited with interchangeable URLs
A group can be visited with a /organization url as well.

See the following URLs
(bacon-is-awesome is actually a group)
http://demo.ckan.org/group/bacon-is-awesome
http://demo.ckan.org/organization/bacon-is-awesome

Seems to happen vice versa too
(ccccc is actually an organization)
http://demo.ckan.org/organization/ccccc
http://demo.ckan.org/group/ccccc

We should raise a 404 when you visit a group with a /organization url and when you visit something that's an organization with a /group URL.



Discussion:
+1 to the 404 you propose

+1 to 404


Resolving patch:
diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py
--- a/ckan/logic/action/get.py
+++ b/ckan/logic/action/get.py
@@ -850,6 +850,10 @@ def _group_or_org_show(context, data_dict, is_org=False):
 
     if group is None:
         raise NotFound
+    if is_org and not group.is_organization:
+        raise NotFound
+    if not is_org and group.is_organization:
+        raise NotFound
 
     if is_org:
         _check_access('organization_show',context, data_dict)


Test patch:
diff --git a/ckan/tests/logic/test_action.py b/ckan/tests/logic/test_action.py
--- a/ckan/tests/logic/test_action.py
+++ b/ckan/tests/logic/test_action.py
@@ -1644,3 +1644,57 @@ def test_02_bulk_delete(self):
 
         res = self.app.get('/api/action/package_search?q=*:*')
         assert json.loads(res.body)['result']['count'] == 0
+
+
+class TestGroupOrgView(WsgiAppCase):
+
+    @classmethod
+    def setup_class(cls):
+        model.Session.add_all([
+            model.User(name=u'sysadmin', apikey=u'sysadmin',
+                       password=u'sysadmin', sysadmin=True),
+        ])
+        model.Session.commit()
+
+        org_dict = '%s=1' % json.dumps({
+            'name': 'org',
+        })
+        res = cls.app.post('/api/action/organization_create',
+                            extra_environ={'Authorization': 'sysadmin'},
+                            params=org_dict)
+        cls.org_id = json.loads(res.body)['result']['id']
+
+        group_dict = '%s=1' % json.dumps({
+            'name': 'group',
+        })
+        res = cls.app.post('/api/action/group_create',
+                            extra_environ={'Authorization': 'sysadmin'},
+                            params=group_dict)
+        cls.group_id = json.loads(res.body)['result']['id']
+
+    @classmethod
+    def teardown_class(self):
+        model.repo.rebuild_db()
+
+    def test_1_view_org(self):
+        res = self.app.get('/api/action/organization_show',
+                params={'id': self.org_id})
+        res_json = json.loads(res.body)
+        assert res_json['success'] is True
+
+        res = self.app.get('/api/action/group_show',
+                params={'id': self.org_id}, expect_errors=True)
+        res_json = json.loads(res.body)
+        assert res_json['success'] is False
+
+    def test_2_view_group(self):
+        res = self.app.get('/api/action/group_show',
+                params={'id': self.group_id})
+        res_json = json.loads(res.body)
+        assert res_json['success'] is True
+
+        res = self.app.get('/api/action/organization_show',
+                params={'id': self.group_id}, expect_errors=True)
+        res_json = json.loads(res.body)
+        assert res_json['success'] is False
+