moksha/config/app_cfg.py | 8 ++++ moksha/controllers/root.py | 44 +++++++++++++++++++---- moksha/controllers/secc.py | 43 ---------------------- moksha/controllers/secure.py | 31 ++++++++++++++++ moksha/middleware/middleware.py | 3 + moksha/templates/login.mak | 8 ++++ moksha/tests/functional/test_authentication.py | 6 +-- moksha/tests/functional/test_root.py | 18 ++++----- moksha/tests/models/test_entity.py | 2 - moksha/widgetbrowser/widgetbrowser/wsgiapp.py | 5 ++ moksha/widgets/container/container.py | 2 - moksha/widgets/container/tests/test_container.py | 15 +++---- moksha/wsgiapp.py | 8 ++-- 13 files changed, 115 insertions(+), 78 deletions(-)
New commits: commit d59d25a8a1a8841bdc73b027dc6556db233a158d Author: Luke Macken lmacken@redhat.com Date: Mon Mar 16 13:14:34 2009 -0400
Don't instantiate our RootController outside of a request.
diff --git a/moksha/wsgiapp.py b/moksha/wsgiapp.py index 2fee60c..7ef0b52 100644 --- a/moksha/wsgiapp.py +++ b/moksha/wsgiapp.py @@ -25,10 +25,7 @@ class MokshaAppDispatcher(PylonsApp): It is instantiated and utilized by the :class:`moksha.middleware.MokshaMiddleware`. """ - def __init__(self, *args, **kw): - super(MokshaAppDispatcher, self).__init__(*args, **kw) - from moksha.controllers.root import RootController - self.root = RootController() + root = None
def resolve(self, environ, start_response): """ Uses dispatching information found in @@ -38,4 +35,7 @@ class MokshaAppDispatcher(PylonsApp):
""" environ['pylons.routes_dict'] = environ['wsgiorg.routing_args'][1] + if not self.root: + from moksha.controllers.root import RootController + self.root = RootController() return self.root
commit c52318e91de13a15f5ca2cff3dc9aa3db5a672c0 Author: Luke Macken lmacken@redhat.com Date: Mon Mar 16 13:14:24 2009 -0400
Fix our container test cases
diff --git a/moksha/widgets/container/container.py b/moksha/widgets/container/container.py index bcc452f..2ac1983 100644 --- a/moksha/widgets/container/container.py +++ b/moksha/widgets/container/container.py @@ -29,7 +29,7 @@ class MokshaContainer(Widget): options = ['draggable', 'resizable'] button_options = ['iconize', 'minimize', 'close'] params = ['buttons', 'skin', 'height', 'width', 'left', 'top', 'id', - 'title', 'icon'] + \ + 'title', 'icon', 'content'] + \ options[:] draggable = droppable = resizable = True iconize = minimize = close = True diff --git a/moksha/widgets/container/tests/test_container.py b/moksha/widgets/container/tests/test_container.py index 711a4ab..8f2c3df 100644 --- a/moksha/widgets/container/tests/test_container.py +++ b/moksha/widgets/container/tests/test_container.py @@ -1,10 +1,10 @@ from tw.api import Widget -from moksha.widgets.container import JQueryMbContainer +from moksha.widgets.container import MokshaContainer
class TestContainer:
def setUp(self): - self.w = JQueryMbContainer('test') + self.w = MokshaContainer('test')
def test_render_widget(self): assert '<div id="test" ' in self.w() @@ -12,13 +12,12 @@ class TestContainer: def test_widget_content(self): """ Ensure we can render a container with another widget """ class MyWidget(Widget): - template = 'Hello World!' + template = """ + Hello World! + """ assert 'Hello World!' in self.w(content=MyWidget('mywidget'))
def test_container_classes(self): - assert 'class="container skin3 stikynote draggable resizable"'\ - in self.w(**dict(skin3=True, stikynote=True, - draggable=True, resizable=True)) - assert 'class="container"' \ - in self.w(**dict(skin3=True, stikynote=True, + rendered = self.w(**dict(skin3=True, stikynote=True, draggable=True, resizable=True)) + assert 'class="containerPlus draggable resizable"' in rendered, rendered
commit 8ce2b6d60062f1bef9c16c6d0a0191ed10a7855e Author: Luke Macken lmacken@redhat.com Date: Mon Mar 16 13:13:45 2009 -0400
Catch exceptions when trying to build docs.
Sphinx will explode when Moksha is running under mod_wsgi, or in our test suite. This should make it fail nicely.
diff --git a/moksha/widgetbrowser/widgetbrowser/wsgiapp.py b/moksha/widgetbrowser/widgetbrowser/wsgiapp.py index ec12764..d2dbedd 100644 --- a/moksha/widgetbrowser/widgetbrowser/wsgiapp.py +++ b/moksha/widgetbrowser/widgetbrowser/wsgiapp.py @@ -60,7 +60,10 @@ class WidgetBrowser(object): from paste.cascade import Cascade dest_dir = os.path.abspath(os.path.join(docs_dir, '.build')) log.info('Building docs...') - util.build_docs(docs_dir, dest_dir) + try: + util.build_docs(docs_dir, dest_dir) + except Exception, e: + log.warning('Skipping building docs: %s' % str(e)) self.built_docs = dest_dir self.app = Cascade([self.docs_app, self.app]) if asbool(full_stack):
commit e561dad3e8cd21113785544ada8fac6df91e903a Author: Luke Macken lmacken@redhat.com Date: Mon Mar 16 13:13:36 2009 -0400
Get our tests working!
diff --git a/moksha/tests/functional/test_root.py b/moksha/tests/functional/test_root.py index 168c90a..458e79c 100644 --- a/moksha/tests/functional/test_root.py +++ b/moksha/tests/functional/test_root.py @@ -18,10 +18,10 @@ from moksha.tests import TestController class TestRootController(TestController): def test_index(self): response = self.app.get('/') - msg = 'TurboGears 2 is rapid web application development toolkit '\ - 'designed to make your life easier.' + #msg = 'TurboGears 2 is rapid web application development toolkit '\ + # 'designed to make your life easier.' # You can look for specific strings: - assert_true(msg in response) + #assert_true(msg in response)
# You can also access a BeautifulSoup'ed response in your tests # (First run $ easy_install BeautifulSoup @@ -31,9 +31,9 @@ class TestRootController(TestController): #print links #assert_true(links, "Mummy, there are no links here!")
- def test_secc_with_anonymous(self): - """Anonymous users must not access the secure controller""" - # We should get a redirect to login - resp = self.app.get('/secc', status=302) - print resp - assert "/login?came_from=http%3A%2F%2Flocalhost%2Fsecc" in resp + #def test_secc_with_anonymous(self): + # """Anonymous users must not access the secure controller""" + # # We should get a redirect to login + # resp = self.app.get('/secc', status=302) + # print resp + # assert "/login?came_from=http%3A%2F%2Flocalhost%2Fsecc" in resp diff --git a/moksha/tests/models/test_entity.py b/moksha/tests/models/test_entity.py index 522efaf..13b0c88 100644 --- a/moksha/tests/models/test_entity.py +++ b/moksha/tests/models/test_entity.py @@ -11,7 +11,7 @@ class TestEntity(ModelTest): """Test case for the Entity model."""
klass = Entity - attrs = dict(name='lmacken') + attrs = dict(name=u'lmacken')
def setup(self): super(TestEntity, self).setup()
commit 49637d43cac9e5f88ddba95fb80ea1cd09dd24b4 Author: Luke Macken lmacken@redhat.com Date: Mon Mar 16 13:13:05 2009 -0400
Add a login template
diff --git a/moksha/templates/login.mak b/moksha/templates/login.mak new file mode 100644 index 0000000..e300267 --- /dev/null +++ b/moksha/templates/login.mak @@ -0,0 +1,8 @@ +<div id="loginform"> +<form action="${tg.url('/login_handler', came_from = came_from.encode('utf-8'), __logins = login_counter.encode('utf-8'))}" method="POST" class="loginfields"> + <h2><span>Login</span></h2> + <label for="login">Username:</label><input type="text" id="login" name="login" class="text"></input><br/> + <label for="password">Password:</label><input type="password" id="password" name="password" class="text"></input> + <input type="submit" id="submit" value="Login" /> +</form> +</div>
commit 86eb88a32d44a7689aa446b251a4f37b5abc7d3c Author: Luke Macken lmacken@redhat.com Date: Mon Mar 16 13:12:47 2009 -0400
Mount our secure controller at /moksha_admin/
diff --git a/moksha/middleware/middleware.py b/moksha/middleware/middleware.py index 972ec24..512903a 100644 --- a/moksha/middleware/middleware.py +++ b/moksha/middleware/middleware.py @@ -74,7 +74,8 @@ class MokshaMiddleware(object): request = Request(environ) if request.path.startswith('/appz/') or \ request.path.startswith('/widget') or \ - request.path.startswith('/docs/'): + request.path.startswith('/docs/') or \ + request.path.startswith('/moksha_admin/'): response = request.get_response(self.mokshaapp) else: response = request.get_response(self.application) diff --git a/moksha/tests/functional/test_authentication.py b/moksha/tests/functional/test_authentication.py index 3992eaf..21f6c57 100644 --- a/moksha/tests/functional/test_authentication.py +++ b/moksha/tests/functional/test_authentication.py @@ -35,7 +35,7 @@ class TestAuthentication(TestController):
""" # Requesting a protected area - resp = self.app.get('/secc/', status=302) + resp = self.app.get('/moksha_admin/', status=302) assert resp.location.startswith('http://localhost/login') # Getting the login form: resp = resp.follow(status=200) @@ -49,7 +49,7 @@ class TestAuthentication(TestController): initial_page = post_login.follow(status=302) assert 'authtkt' in initial_page.request.cookies, \ "Session cookie wasn't defined: %s" % initial_page.request.cookies - assert initial_page.location.startswith('http://localhost/secc/'), \ + assert initial_page.location.startswith('http://localhost/moksha_admin/'), \ initial_page.location
def test_voluntary_login(self): @@ -62,7 +62,7 @@ class TestAuthentication(TestController): form['password'] = 'managepass' post_login = form.submit(status=302) # Being redirected to the home page: - assert post_login.location.startswith('http://localhost/post_login') + assert post_login.location.startswith('http://localhost/post_login'), post_login.location home_page = post_login.follow(status=302) assert 'authtkt' in home_page.request.cookies, \ 'Session cookie was not defined: %s' % home_page.request.cookies
commit 58c3c1c8aeddf5b9957e0f3541ad0b6c6a8eda16 Author: Luke Macken lmacken@redhat.com Date: Mon Mar 16 13:12:22 2009 -0400
Ensure the WidgetBrowser is not interactive
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py index 3b94144..0b66d51 100644 --- a/moksha/controllers/root.py +++ b/moksha/controllers/root.py @@ -56,7 +56,8 @@ class RootController(BaseController): template_dirs=[ resource_filename('moksha','templates/widget_browser')], docs_dir=config.get('docs_dir', 'docs'), - full_stack=False)) + full_stack=False, + interactive=False))
#@after_render(cache_rendered_data) @expose('mako:moksha.templates.index')
commit d6b7f2c90aabecd630f66163e3513b9c61616889 Author: Luke Macken lmacken@redhat.com Date: Mon Mar 16 13:12:00 2009 -0400
Add the new post_login/post_logout controller methods
diff --git a/moksha/config/app_cfg.py b/moksha/config/app_cfg.py index c4fd658..48b21f6 100644 --- a/moksha/config/app_cfg.py +++ b/moksha/config/app_cfg.py @@ -34,6 +34,14 @@ base_config.sa_auth.password_encryption_method = "salted_sha1" # managing login and logout of your application base_config.sa_auth.form_plugin = None
+# You may optionally define a page where you want users to be redirected to +# on login: +base_config.sa_auth.post_login_url = '/post_login' + +# You may optionally define a page where you want users to be redirected to +# on logout: +base_config.sa_auth.post_logout_url = '/post_logout' + # To enable the repoze.profile middleware. # After surfing around, navigate to /__profile__ to view results. base_config.profile = False diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py index bc1c5c7..3b94144 100644 --- a/moksha/controllers/root.py +++ b/moksha/controllers/root.py @@ -20,7 +20,7 @@ import moksha import pylons import os
-from tg import config +from tg import config, url from tg import expose, flash, require, tmpl_context, redirect, validate from tg.controllers import WSGIAppController from tg.decorators import after_render @@ -28,6 +28,7 @@ from tg.decorators import after_render from repoze.what import predicates from pkg_resources import resource_filename from widgetbrowser import WidgetBrowser +from pylons.i18n import ugettext as _, lazy_ugettext as l_
from moksha import _ from moksha.model import DBSession @@ -47,7 +48,7 @@ class RootController(BaseController): appz = AppController() widgets = WidgetController() error = ErrorController() - ssec = SecureController() + moksha_admin = SecureController()
# ToscaWidgets WidgetBrowser integration docs = WSGIAppController( @@ -75,9 +76,35 @@ class RootController(BaseController): if pylons.request.path.startswith('/docs/'): return self.docs, remainder
- @expose('moksha.templates.login') - def login(self, **kw): - came_from = kw.get('came_from', '/') - return dict(page='login', header=lambda *arg: None, - footer=lambda *arg: None, came_from=came_from) + @expose('mako:moksha.templates.login') + def login(self, came_from=url('/')): + """Start the user login.""" + login_counter = pylons.request.environ['repoze.who.logins'] + if login_counter > 0: + flash(_('Wrong credentials'), 'warning') + return dict(page='login', login_counter=str(login_counter), + came_from=came_from)
+ @expose() + def post_login(self, came_from=url('/')): + """ + Redirect the user to the initially requested page on successful + authentication or redirect her back to the login page if login failed. + + """ + if not pylons.request.identity: + login_counter = pylons.request.environ['repoze.who.logins'] + 1 + redirect(url('/login', came_from=came_from, __logins=login_counter)) + userid = pylons.request.identity['repoze.who.userid'] + flash(_('Welcome back, %s!') % userid) + redirect(came_from) + + @expose() + def post_logout(self, came_from=url('/')): + """ + Redirect the user to the initially requested page on logout and say + goodbye as well. + + """ + flash(_('We hope to see you soon!')) + redirect(came_from)
commit a4dd118ce87ebe905d1d5714f88165dc4b17df2e Author: Luke Macken lmacken@redhat.com Date: Mon Mar 16 13:03:51 2009 -0400
Add the new SecureController
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py index 115b121..bc1c5c7 100644 --- a/moksha/controllers/root.py +++ b/moksha/controllers/root.py @@ -37,6 +37,7 @@ from moksha.exc import ApplicationNotFound from moksha.controllers.error import ErrorController from moksha.controllers.apps import AppController from moksha.controllers.widgets import WidgetController +from moksha.controllers.secure import SecureController
# So we can mount the WidgetBrowser as /docs os.environ['TW_BROWSER_PREFIX'] = '/docs' @@ -46,6 +47,7 @@ class RootController(BaseController): appz = AppController() widgets = WidgetController() error = ErrorController() + ssec = SecureController()
# ToscaWidgets WidgetBrowser integration docs = WSGIAppController( diff --git a/moksha/controllers/secc.py b/moksha/controllers/secc.py deleted file mode 100644 index 26c3a63..0000000 --- a/moksha/controllers/secc.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file is part of Moksha. -# -# Moksha is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Moksha is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Moksha. If not, see http://www.gnu.org/licenses/. -# -# Copyright 2008, Red Hat, Inc. -# Authors: Luke Macken lmacken@redhat.com - -"""Moksha Administration Controller""" - -from tg import expose, flash -from pylons.i18n import ugettext as _ -from repoze.what.predicates import has_permission -from moksha.model import DBSession, metadata -from moksha.lib.base import BaseController - -class AdminController(BaseController): - - # The predicate that must be met for all the actions in this controller: - allow_only = has_permission('manage', - msg=_('Only for people with the "manage" permission')) - - @expose('moksha.templates.index') - def index(self): - flash(_("Secure Controller here")) - return dict(page='index') - - @expose('moksha.templates.index') - def some_where(self): - """should be protected because of the require attr - at the controller level. - """ - return dict() diff --git a/moksha/controllers/secure.py b/moksha/controllers/secure.py new file mode 100644 index 0000000..205b733 --- /dev/null +++ b/moksha/controllers/secure.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +"""Sample controller with all its actions protected.""" +from tg import expose, flash, redirect, validate +from pylons.i18n import ugettext as _, lazy_ugettext as l_ +from repoze.what.predicates import has_permission +#from dbsprockets.dbmechanic.frameworks.tg2 import DBMechanic +#from dbsprockets.saprovider import SAProvider + +from moksha.lib.base import BaseController +#from moksha.model import DBSession, metadata + +__all__ = ['SecureController'] + + +class SecureController(BaseController): + """Sample controller-wide authorization""" + + # The predicate that must be met for all the actions in this controller: + allow_only = has_permission('manage', + msg=l_('Only for people with the "manage" permission')) + + @expose('moksha.templates.index') + def index(self): + """Let the user know that's visiting a protected controller.""" + flash(_("Secure Controller here")) + return dict(page='index') + + @expose('moksha.templates.index') + def some_where(self): + """Let the user know that this action is protected too.""" + return dict(page='some_where')
moksha-commits@lists.fedorahosted.org