You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2013/08/13 17:55:57 UTC
[3/6] git commit: [#4818] add admin extensions
[#4818] add admin extensions
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/dc8c2e95
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/dc8c2e95
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/dc8c2e95
Branch: refs/heads/db/4818
Commit: dc8c2e95ec7c1e46a92abdcb1de7d8a0725ef55d
Parents: d43c254
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri Aug 9 19:41:07 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Tue Aug 13 15:55:46 2013 +0000
----------------------------------------------------------------------
Allura/allura/ext/admin/admin_main.py | 17 ++++++++++
Allura/allura/lib/app_globals.py | 1 +
Allura/allura/lib/plugin.py | 32 +++++++++++++++++++
Allura/allura/tests/functional/test_admin.py | 39 +++++++++++++++++++++++
4 files changed, 89 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/dc8c2e95/Allura/allura/ext/admin/admin_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/admin/admin_main.py b/Allura/allura/ext/admin/admin_main.py
index f8c8983..92efacb 100644
--- a/Allura/allura/ext/admin/admin_main.py
+++ b/Allura/allura/ext/admin/admin_main.py
@@ -139,6 +139,10 @@ class AdminApp(Application):
links.append(SitemapEntry('Statistics', nbhd_admin_url+ 'stats/'))
links.append(None)
links.append(SitemapEntry('Help', nbhd_admin_url+ 'help/'))
+
+ for name, admin_extension in g.entry_points['admin'].iteritems():
+ admin_extension().update_project_sidebar_menu(links)
+
return links
def admin_menu(self):
@@ -147,6 +151,18 @@ class AdminApp(Application):
def install(self, project):
pass
+
+class AdminExtensionLookup(object):
+
+ @expose()
+ def _lookup(self, name, *remainder):
+ for ext_name, admin_extension in g.entry_points['admin'].iteritems():
+ controller = admin_extension().project_admin_controllers.get(name)
+ if controller:
+ return controller(), remainder
+ raise exc.HTTPNotFound, name
+
+
class ProjectAdminController(BaseController):
def _check_security(self):
@@ -156,6 +172,7 @@ class ProjectAdminController(BaseController):
self.permissions = PermissionsController()
self.groups = GroupsController()
self.audit = AuditController()
+ self.ext = AdminExtensionLookup()
@with_trailing_slash
@expose('jinja:allura.ext.admin:templates/project_admin.html')
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/dc8c2e95/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index bdcacf7..7f45f69 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -197,6 +197,7 @@ class Globals(object):
spam=_cache_eps('allura.spam'),
stats=_cache_eps('allura.stats'),
site_stats=_cache_eps('allura.site_stats'),
+ admin=_cache_eps('allura.admin'),
)
# Zarkov logger
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/dc8c2e95/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 4afd9fc..f972c26 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -915,3 +915,35 @@ class LocalUserPreferencesProvider(UserPreferencesProvider):
users = M.User.query.find(dict(
display_name=name_regex)).sort('username').all()
return users
+
+
+class AdminExtension(object):
+ """
+ A base class for extending the admin areas in Allura.
+
+ After extending this, expose the app by adding an entry point in your
+ setup.py::
+
+ [allura.admin]
+ myadmin = foo.bar.baz:MyCustomAdmin
+
+ :ivar dict project_admin_controllers: Mapping of str (url component) to
+ Controllers. Can be implemented as a ``@property`` function. The str
+ url components will be mounted at /p/someproject/admin/ext/STR/ and will
+ invoke the Controller.
+ """
+
+ project_admin_controllers = {}
+
+ def update_project_sidebar_menu(self, sidebar_links):
+ """
+ Implement this function to modify the project sidebar.
+ Check `c.project` if you want to limit when this displays
+ (e.g. nbhd project, subproject, etc)
+
+ :param sidebar_links: project admin side bar links
+ :type sidebar_links: list of :class:`allura.app.SitemapEntry`
+
+ :rtype: ``None``
+ """
+ pass
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/dc8c2e95/Allura/allura/tests/functional/test_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_admin.py b/Allura/allura/tests/functional/test_admin.py
index 7d630c9..adeb71b 100644
--- a/Allura/allura/tests/functional/test_admin.py
+++ b/Allura/allura/tests/functional/test_admin.py
@@ -24,6 +24,10 @@ from contextlib import contextmanager
import PIL
from nose.tools import assert_equals
from ming.orm.ormsession import ThreadLocalORMSession
+from tg import expose
+from pylons import tmpl_context as c, app_globals as g
+import mock
+from BeautifulSoup import BeautifulSoup
try:
import sfx
@@ -33,6 +37,8 @@ except ImportError:
from allura.tests import TestController
from allura.tests import decorators as td
from allura import model as M
+from allura.app import SitemapEntry
+from allura.lib.plugin import AdminExtension
@contextmanager
def audits(*messages):
@@ -726,3 +732,36 @@ class TestProjectAdmin(TestController):
assert {u'text': u'Does not have permission create', u'has': u'no', u'name': u'create'} in r.json[admin_id]
assert {u'text': u'Does not have permission create', u'has': u'no', u'name': u'create'} in r.json[mem_id]
assert {u'text': u'Does not have permission create', u'has': u'no', u'name': u'create'} in r.json[anon_id]
+
+
+ def test_admin_extension_sidebar(self):
+
+ class FooSettingsController(object):
+ @expose()
+ def index(self, *a, **kw):
+ return 'here the foo settings go'
+
+
+ class FooSettingsExtension(AdminExtension):
+ def update_project_sidebar_menu(self, sidebar_links):
+ base_url = c.project.url()+'admin/ext/'
+ sidebar_links.append(SitemapEntry('Foo Settings', base_url+'foo'))
+
+ @property
+ def project_admin_controllers(self):
+ return {
+ 'foo': FooSettingsController,
+ }
+
+ eps = {
+ 'admin': {
+ 'foo-settings': FooSettingsExtension,
+ }
+ }
+
+ with mock.patch.dict(g.entry_points, eps):
+ main_page = self.app.get('/admin/')
+ foo_page = main_page.click(description='Foo Settings')
+ url = foo_page.environ['PATH_INFO']
+ assert url.endswith('/admin/ext/foo'), url
+ assert_equals('here the foo settings go', foo_page.body)