From 36634e8306c3303aa97a04099219d5e40f193f9b Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Wed, 29 Aug 2012 11:08:43 -0700 Subject: [PATCH] extensive commit (see note) The following changes are included: - ``edbob.pyramid.Session`` uses ``sessionmaker()`` instead of ``edbob.db.Session``. - ``edbob.pyramid.includeme()`` now configures ``pyramid_beaker`` directly. - ``edbob.pyramid.includeme()`` now configures auth/auth policies directly. - Pyramid progress indicator added. - ``edbob.pyramid.Session`` added to global template render context. - ``request.get_referrer()`` method added (removed ``edbob.pyramid.util`` module). - ``request.get_setting()`` and ``request.save_setting()`` methods added. - ``Grid.column_header()`` now supports ``title`` attribute. - ``Grid.editable`` support added. - Template / style tweaks. - ``text`` argument to ``disable_button()`` JS function is now optional. - Forbidden view flash message no longer duplicated when multiple redirects occur. - ``CrudView`` class improved to support various workflow needs (e.g. post-delete procesing). - Extra renderer keyword args support added to ``GridView`` class. - ``SearchableAlchemyGridView`` class improved to support various workflow needs (e.g. obtaining an unsorted query). --- edbob/pyramid/__init__.py | 29 ++-- edbob/pyramid/grids/alchemy.py | 16 ++- edbob/pyramid/grids/core.py | 20 ++- edbob/pyramid/progress.py | 96 +++++++++++++ edbob/pyramid/static/__init__.py | 62 ++++----- edbob/pyramid/static/css/forms.css | 3 +- edbob/pyramid/static/css/grids.css | 36 +++-- edbob/pyramid/static/img/edit.png | Bin 0 -> 533 bytes edbob/pyramid/static/js/edbob.js | 11 +- edbob/pyramid/subscribers.py | 59 +++++--- edbob/pyramid/templates/edbob/grid.mako | 19 ++- edbob/pyramid/templates/edbob/login.mako | 3 +- edbob/pyramid/templates/grids/grid.mako | 6 + edbob/pyramid/templates/progress.mako | 138 +++++++++++++++++++ edbob/pyramid/views/__init__.py | 3 +- edbob/pyramid/views/auth.py | 13 +- edbob/pyramid/views/crud.py | 26 +++- edbob/pyramid/views/grids/alchemy.py | 14 +- edbob/pyramid/views/grids/core.py | 6 +- edbob/pyramid/{util.py => views/progress.py} | 43 +++--- 20 files changed, 481 insertions(+), 122 deletions(-) create mode 100644 edbob/pyramid/progress.py create mode 100644 edbob/pyramid/static/img/edit.png create mode 100644 edbob/pyramid/templates/progress.mako rename edbob/pyramid/{util.py => views/progress.py} (50%) diff --git a/edbob/pyramid/__init__.py b/edbob/pyramid/__init__.py index e5c4633..64defc6 100644 --- a/edbob/pyramid/__init__.py +++ b/edbob/pyramid/__init__.py @@ -26,15 +26,13 @@ ``edbob.pyramid`` -- Pyramid Framework """ -from sqlalchemy.orm import scoped_session +from sqlalchemy.orm import sessionmaker, scoped_session from zope.sqlalchemy import ZopeTransactionExtension -import edbob.db - __all__ = ['Session'] -Session = scoped_session(edbob.db.Session) +Session = scoped_session(sessionmaker()) def includeme(config): @@ -51,16 +49,23 @@ def includeme(config): The other thing added is the ``edbob`` static view for CSS files etc. """ - # Session is extended here instead of at module scope to prevent import - # side-effects. + # Configure Beaker session. + config.include('pyramid_beaker') + + # Bring in transaction manager. + config.include('pyramid_tm') + + # Configure SQLAlchemy session. Session.configure(extension=ZopeTransactionExtension()) - # Forbidden view is configured here instead of within edbob.pyramid.views - # since it's so "important." + # Configure user authentication / authorization. + from pyramid.authentication import SessionAuthenticationPolicy + config.set_authentication_policy(SessionAuthenticationPolicy()) + from edbob.pyramid.auth import EdbobAuthorizationPolicy + config.set_authorization_policy(EdbobAuthorizationPolicy()) + + # Add forbidden view. config.add_forbidden_view('edbob.pyramid.views.forbidden') - # Same goes with the edbob static route; we need that JS. + # Add static views. config.include('edbob.pyramid.static') - - # Include transaction manager tween. - config.include('pyramid_tm') diff --git a/edbob/pyramid/grids/alchemy.py b/edbob/pyramid/grids/alchemy.py index eb3b7d7..4402ac4 100644 --- a/edbob/pyramid/grids/alchemy.py +++ b/edbob/pyramid/grids/alchemy.py @@ -26,8 +26,8 @@ ``edbob.pyramid.grids.alchemy`` -- FormAlchemy Grid Classes """ -from webhelpers.html import literal from webhelpers.html import tags +from webhelpers.html import HTML import formalchemy @@ -70,16 +70,18 @@ class AlchemyGrid(Grid): return {'uuid': row.uuid} def column_header(self, field): - cls = '' + class_ = None label = field.label() if field.key in self.sort_map: - cls = 'sortable' + class_ = 'sortable' if field.key == self.config['sort']: - cls += ' sorted ' + self.config['dir'] + class_ += ' sorted ' + self.config['dir'] label = tags.link_to(label, '#') - if cls: - cls = ' class="%s"' % cls - return literal('' % (cls, field.key)) + label + literal('') + return HTML.tag('th', class_=class_, field=field.key, + title=self.column_titles.get(field.key), c=label) + + def edit_route_kwargs(self, row): + return {'uuid': row.uuid} def delete_route_kwargs(self, row): return {'uuid': row.uuid} diff --git a/edbob/pyramid/grids/core.py b/edbob/pyramid/grids/core.py index f1de01a..312ca60 100644 --- a/edbob/pyramid/grids/core.py +++ b/edbob/pyramid/grids/core.py @@ -31,7 +31,7 @@ try: except ImportError: from ordereddict import OrderedDict -from webhelpers.html import literal +from webhelpers.html import HTML from webhelpers.html.builder import format_attrs from pyramid.renderers import render @@ -48,6 +48,7 @@ class Grid(edbob.Object): hoverable = True clickable = False checkboxes = False + editable = False deletable = False partial_only = False @@ -55,11 +56,15 @@ class Grid(edbob.Object): click_route_name = None click_route_kwargs = None + edit_route_name = None + edit_route_kwargs = None + delete_route_name = None delete_route_kwargs = None def __init__(self, request, **kwargs): kwargs.setdefault('fields', OrderedDict()) + kwargs.setdefault('column_titles', {}) kwargs.setdefault('extra_columns', []) super(Grid, self).__init__(**kwargs) self.request = request @@ -69,7 +74,9 @@ class Grid(edbob.Object): edbob.Object(name=name, label=label, callback=callback)) def column_header(self, field): - return literal('%s' % (field.name, field.label)) + return HTML.tag('th', field=field.name, + title=self.column_titles.get(field.name), + c=field.label) def div_attrs(self): classes = ['grid'] @@ -92,6 +99,15 @@ class Grid(edbob.Object): kwargs = self.delete_route_kwargs return self.request.route_url(self.delete_route_name, **kwargs) + def get_edit_url(self, row): + kwargs = {} + if self.edit_route_kwargs: + if callable(self.edit_route_kwargs): + kwargs = self.edit_route_kwargs(row) + else: + kwargs = self.edit_route_kwargs + return self.request.route_url(self.edit_route_name, **kwargs) + def get_row_attrs(self, row, i): attrs = self.row_attrs(row, i) if self.clickable: diff --git a/edbob/pyramid/progress.py b/edbob/pyramid/progress.py new file mode 100644 index 0000000..65c79e7 --- /dev/null +++ b/edbob/pyramid/progress.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +################################################################################ +# +# edbob -- Pythonic Software Framework +# Copyright © 2010-2012 Lance Edgar +# +# This file is part of edbob. +# +# edbob is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# edbob 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 Affero General Public License for +# more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with edbob. If not, see . +# +################################################################################ + +""" +``edbob.pyramid.progress`` -- Progress Indicator +""" + +from beaker.session import Session + + +def get_progress_session(session, key): + request = session.request + id = '%s.progress.%s' % (session.id, key) + session = Session(request, id) + return session + + +class SessionProgress(object): + """ + Provides a session-based progress bar mechanism. + + This class is only responsible for keeping the progress *data* current. It + is the responsibility of some client-side AJAX (etc.) to consume the data + for display to the user. + """ + + def __init__(self, session, key): + self.session = get_progress_session(session, key) + self.cancelled = False + + def __call__(self, message, maximum): + self.session['complete'] = False + self.session['message'] = message + self.session['maximum'] = maximum + self.session['cancelled'] = False + self.session['value'] = 0 + self.session.save() + return self + + def update(self, value): + self.session.load() + if self.session.get('cancelled'): + self.cancelled = True + else: + self.session['value'] = value + self.session.save() + return not self.cancelled + + def destroy(self): + if not self.cancelled: + self.session['complete'] = True + self.session.save() + + def secondary_progress(self): + return SecondarySessionProgress(self) + + +class SecondarySessionProgress(object): + + def __init__(self, parent): + self.parent = parent + self.session = parent.session + + def __call__(self, message, maximum): + self.session['message'] = message + self.session['value'] = 0 + self.session['maximum'] = maximum + self.session.save() + return self + + def update(self, value): + return self.parent.update(value) + + def destroy(self): + pass diff --git a/edbob/pyramid/static/__init__.py b/edbob/pyramid/static/__init__.py index 0fc349d..64af3d3 100644 --- a/edbob/pyramid/static/__init__.py +++ b/edbob/pyramid/static/__init__.py @@ -1,31 +1,31 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -################################################################################ -# -# edbob -- Pythonic Software Framework -# Copyright © 2010-2012 Lance Edgar -# -# This file is part of edbob. -# -# edbob is free software: you can redistribute it and/or modify it under the -# terms of the GNU Affero General Public License as published by the Free -# Software Foundation, either version 3 of the License, or (at your option) -# any later version. -# -# edbob 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 Affero General Public License for -# more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with edbob. If not, see . -# -################################################################################ - -""" -``edbob.pyramid.static`` -- Static Assets -""" - - -def includeme(config): - config.add_static_view('edbob', 'edbob.pyramid:static', cache_max_age=3600) +#!/usr/bin/env python +# -*- coding: utf-8 -*- +################################################################################ +# +# edbob -- Pythonic Software Framework +# Copyright © 2010-2012 Lance Edgar +# +# This file is part of edbob. +# +# edbob is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# edbob 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 Affero General Public License for +# more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with edbob. If not, see . +# +################################################################################ + +""" +``edbob.pyramid.static`` -- Static Assets +""" + + +def includeme(config): + config.add_static_view('edbob', 'edbob.pyramid:static', cache_max_age=3600) diff --git a/edbob/pyramid/static/css/forms.css b/edbob/pyramid/static/css/forms.css index 086f882..3047756 100644 --- a/edbob/pyramid/static/css/forms.css +++ b/edbob/pyramid/static/css/forms.css @@ -66,7 +66,8 @@ div.field-wrapper div.field { div.field-wrapper div.field input[type=text], div.field-wrapper div.field input[type=password], -div.field-wrapper div.field select { +div.field-wrapper div.field select, +div.field-wrapper div.field textarea { width: 320px; } diff --git a/edbob/pyramid/static/css/grids.css b/edbob/pyramid/static/css/grids.css index 59c84a9..1a84cbe 100644 --- a/edbob/pyramid/static/css/grids.css +++ b/edbob/pyramid/static/css/grids.css @@ -9,6 +9,15 @@ table.grid-header { } +/****************************** + * Form (Filters etc.) + ******************************/ + +table.grid-header td.form { + vertical-align: bottom; +} + + /****************************** * Context Menu ******************************/ @@ -104,15 +113,6 @@ div.grid table tr.odd { /* width: 15px; */ /* } */ -div.grid table tbody td.delete { - background-image: url(../img/delete.png); - background-repeat: no-repeat; - background-position: center; - cursor: pointer; - min-width: 18px; - width: 18px; -} - div.grid table tbody tr.hovering { background-color: #bbbbbb; } @@ -129,6 +129,24 @@ div.grid table.checkable tbody tr { div.grid.clickable table tbody tr td.noclick { cursor: default; + text-align: center; + width: 18px; +} + +div.grid table tbody tr td.noclick.edit, +div.grid table tbody tr td.noclick.delete { + background-repeat: no-repeat; + background-position: center; + cursor: pointer; + min-width: 18px; +} + +div.grid table tbody tr td.noclick.edit { + background-image: url(../img/edit.png); +} + +div.grid table tbody tr td.noclick.delete { + background-image: url(../img/delete.png); } /* div.grid table.selectable tbody tr.selected, */ diff --git a/edbob/pyramid/static/img/edit.png b/edbob/pyramid/static/img/edit.png new file mode 100644 index 0000000000000000000000000000000000000000..c46fa7e894c7d44712331bec678296da1c013f0d GIT binary patch literal 533 zcmV+w0_y#VP)Px#32;bRa{vGe@Bjb`@Bu=sG?)MY00(qQO+^RX2ow_(0+{1gtpET4r%6OXR4C6) zlFe!qQ4obs-MY7X=wznHV1mm$fRErVJ6(%U;6}tZ5+A^o8<%k*xD!o8!6^8<5QIc# zdZxSYtsfU1iDy|Hiu%qe+H5vCXCh)|07OJYW+ozS+X9$|00I%k7@0YQ!2gs|$~kvk zhyN4-xckM$MM{a8`@V0QMpdUxtJSJqEEG=g0Km**jPB0N^Z8s=tEw`yuIqBnq8dPM z2mqLay8{pr5h0@OcFWAAl&Y%6aqM3od)EbbSC#d89YW~)-raM~?rvrW*KbsAZ{EKA z_3F&sB0%mQV;qJd#yF0nyPG)?4WrZ_?;ZYVuibybRTGH-z+Gdk%p|2GB9VjUlD^;F zo_*T8bKJ~!0Za#IUDv8QA&N)<@BVyHPEY9Qd714`VO;{{oJGVPGW0;2eSS#qPr9RL z*f|KWE9(RfAdiD6ExtVRZ>Q(Co|d#Xjzb7^X`M21_hA?~rX}9l*AKsMKCbr<=es)q z%>1$~GgH-Z80xxS{W-7Wl5f9QIN&Iyh)4*0RctAxT`q~JX?B$Nb <%def name="context_menu_items()"> + +<%def name="form()"> + % if search: + ${search.render()} + % else: +   + % endif + + <%def name="tools()">
- % if search: - - % else: - - % endif + + % endif % if grid.deletable: % endif @@ -28,6 +31,9 @@ % for col in grid.extra_columns: % endfor + % if grid.editable: + + % endif % if grid.deletable: % endif diff --git a/edbob/pyramid/templates/progress.mako b/edbob/pyramid/templates/progress.mako new file mode 100644 index 0000000..d33beb9 --- /dev/null +++ b/edbob/pyramid/templates/progress.mako @@ -0,0 +1,138 @@ + + + + + Working... + ${h.javascript_link(request.static_url('edbob.pyramid:static/js/jquery.js'))} + ${h.javascript_link(request.static_url('edbob.pyramid:static/js/edbob.js'))} + ${h.stylesheet_link(request.static_url('edbob.pyramid:static/css/edbob.css'))} + + + + +
+ +
+ +

Working ...

+ +
- ${search.render()} -   + ${self.form()} +
    ${self.context_menu_items()} diff --git a/edbob/pyramid/templates/edbob/login.mako b/edbob/pyramid/templates/edbob/login.mako index 16724b6..de6c595 100644 --- a/edbob/pyramid/templates/edbob/login.mako +++ b/edbob/pyramid/templates/edbob/login.mako @@ -3,6 +3,7 @@ <%def name="title()">Login <%def name="head_tags()"> + ${parent.head_tags()} ${h.stylesheet_link(request.static_url('edbob.pyramid:static/css/login.css'))} ${self.logo_styles()} @@ -26,7 +27,7 @@
    ${h.form('')} ## - + % if error:
    ${error}
    diff --git a/edbob/pyramid/templates/grids/grid.mako b/edbob/pyramid/templates/grids/grid.mako index d0767b6..dabb1d4 100644 --- a/edbob/pyramid/templates/grids/grid.mako +++ b/edbob/pyramid/templates/grids/grid.mako @@ -11,6 +11,9 @@ % for col in grid.extra_columns:
${col.label} % endfor + % if grid.editable: +   ${col.callback(row)}  
+ + + + + +
+ + + + + +
+
+ +
+ +
+ + + + diff --git a/edbob/pyramid/views/__init__.py b/edbob/pyramid/views/__init__.py index d2b4847..0d8f5b2 100644 --- a/edbob/pyramid/views/__init__.py +++ b/edbob/pyramid/views/__init__.py @@ -49,7 +49,7 @@ def forbidden(request): if not authenticated_userid(request): msg += literal("  (Perhaps you should %s?)" % link_to("log in", request.route_url('login'))) - request.session.flash(msg) + request.session.flash(msg, allow_duplicate=False) url = request.referer if not url or url == request.current_route_url(): @@ -60,4 +60,5 @@ def forbidden(request): def includeme(config): config.include('edbob.pyramid.views.auth') config.include('edbob.pyramid.views.people') + config.include('edbob.pyramid.views.progress') config.include('edbob.pyramid.views.users') diff --git a/edbob/pyramid/views/auth.py b/edbob/pyramid/views/auth.py index 9754faa..09344aa 100644 --- a/edbob/pyramid/views/auth.py +++ b/edbob/pyramid/views/auth.py @@ -35,7 +35,6 @@ from pyramid_simpleform.renderers import FormRenderer import edbob from edbob.db.auth import authenticate_user from edbob.pyramid import Session -from edbob.pyramid.util import get_referer class UserLogin(formencode.Schema): @@ -50,11 +49,11 @@ def login(request): The login view, responsible for displaying and handling the login form. """ - referer = get_referer(request) + referrer = request.get_referrer() # Redirect if already logged in. if request.user: - return HTTPFound(location=referer) + return HTTPFound(location=referrer) form = Form(request, schema=UserLogin) if form.validate(): @@ -66,7 +65,7 @@ def login(request): user.display_name, edbob.local_time().strftime('%I:%M %p'))) headers = remember(request, user.uuid) - return HTTPFound(location=referer, headers=headers) + return HTTPFound(location=referrer, headers=headers) request.session.flash("Invalid username or password") url = edbob.config.get('edbob.pyramid', 'login.logo_url', @@ -74,7 +73,7 @@ def login(request): kwargs = eval(edbob.config.get('edbob.pyramid', 'login.logo_kwargs', default="dict(width=500)")) - return {'form': FormRenderer(form), 'referer': referer, + return {'form': FormRenderer(form), 'referrer': referrer, 'logo_url': url, 'logo_kwargs': kwargs} @@ -89,8 +88,8 @@ def logout(request): request.session.delete() request.session.invalidate() headers = forget(request) - referer = get_referer(request) - return HTTPFound(location=referer, headers=headers) + referrer = request.get_referrer() + return HTTPFound(location=referrer, headers=headers) def includeme(config): diff --git a/edbob/pyramid/views/crud.py b/edbob/pyramid/views/crud.py index 8078cab..d85beda 100644 --- a/edbob/pyramid/views/crud.py +++ b/edbob/pyramid/views/crud.py @@ -33,7 +33,7 @@ import formalchemy from edbob.pyramid import Session from edbob.pyramid.forms.formalchemy import AlchemyForm from edbob.pyramid.views.core import View -from edbob.util import requires_impl +from edbob.util import requires_impl, prettify __all__ = ['CrudView'] @@ -41,7 +41,9 @@ __all__ = ['CrudView'] class CrudView(View): + readonly = False allow_successive_creates = False + update_cancel_route = None @property @requires_impl(is_property=True) @@ -72,6 +74,7 @@ class CrudView(View): def make_fieldset(self, model, **kwargs): kwargs.setdefault('session', Session()) fieldset = formalchemy.FieldSet(model, **kwargs) + fieldset.prettify = prettify return fieldset def fieldset(self, model): @@ -84,7 +87,11 @@ class CrudView(View): fieldset = self.fieldset(model) kwargs.setdefault('pretty_name', self.pretty_name) kwargs.setdefault('action_url', self.request.current_route_url()) - kwargs.setdefault('cancel_url', self.cancel_url) + if self.updating and self.update_cancel_route: + kwargs.setdefault('cancel_url', self.request.route_url( + self.update_cancel_route, uuid=model.uuid)) + else: + kwargs.setdefault('cancel_url', self.cancel_url) kwargs.setdefault('creating', self.creating) kwargs.setdefault('updating', self.updating) form = AlchemyForm(self.request, fieldset, **kwargs) @@ -104,6 +111,9 @@ class CrudView(View): def crud(self, model, readonly=False): + if readonly: + self.readonly = True + form = self.form(model) if readonly: form.readonly = True @@ -125,7 +135,7 @@ class CrudView(View): and self.request.params.get('create_and_continue')): return HTTPFound(location=self.request.current_route_url()) - return HTTPFound(location=self.home_url) + return HTTPFound(location=self.post_save_url(form)) self.validation_failed(form) @@ -139,6 +149,9 @@ class CrudView(View): def post_save(self, form): pass + def post_save_url(self, form): + return self.home_url + def validation_failed(self, form): pass @@ -160,7 +173,8 @@ class CrudView(View): def read(self): uuid = self.request.matchdict['uuid'] model = Session.query(self.mapped_class).get(uuid) if uuid else None - assert model + if not model: + return HTTPFound(location=self.home_url) return self.crud(model, readonly=True) def update(self): @@ -172,6 +186,9 @@ class CrudView(View): def pre_delete(self, model): pass + def post_delete(self, model): + pass + def delete(self): uuid = self.request.matchdict['uuid'] model = Session.query(self.mapped_class).get(uuid) if uuid else None @@ -181,5 +198,6 @@ class CrudView(View): return result Session.delete(model) Session.flush() # Don't set flash message if delete fails. + self.post_delete(model) self.flash_delete(model) return HTTPFound(location=self.home_url) diff --git a/edbob/pyramid/views/grids/alchemy.py b/edbob/pyramid/views/grids/alchemy.py index 3e763f1..053a145 100644 --- a/edbob/pyramid/views/grids/alchemy.py +++ b/edbob/pyramid/views/grids/alchemy.py @@ -164,14 +164,15 @@ class SearchableAlchemyGridView(PagedAlchemyGridView): def search_form(self): return self.make_search_form() - def make_query(self): + def make_query(self, session=Session): join_map = self.join_map() - query = Session.query(self.mapped_class) + query = session.query(self.mapped_class) query = grids.search.filter_query( query, self._filter_config, self.filter_map(), join_map) - self._sort_config['joins'] = self._filter_config['joins'] - query = grids.util.sort_query( - query, self._sort_config, self.sort_map(), join_map) + if hasattr(self, '_sort_config'): + self._sort_config['joins'] = self._filter_config['joins'] + query = grids.util.sort_query( + query, self._sort_config, self.sort_map(), join_map) return query def __call__(self): @@ -181,4 +182,5 @@ class SearchableAlchemyGridView(PagedAlchemyGridView): self._data = self.make_pager() grid = self.grid() grid.pager = self._data - return grids.util.render_grid(grid, search) + kwargs = self.render_kwargs() + return grids.util.render_grid(grid, search, **kwargs) diff --git a/edbob/pyramid/views/grids/core.py b/edbob/pyramid/views/grids/core.py index 87de942..61f6c75 100644 --- a/edbob/pyramid/views/grids/core.py +++ b/edbob/pyramid/views/grids/core.py @@ -61,6 +61,10 @@ class GridView(View): def grid(self): return self.make_grid() + def render_kwargs(self): + return {} + def __call__(self): grid = self.grid() - return grids.util.render_grid(grid) + kwargs = self.render_kwargs() + return grids.util.render_grid(grid, **kwargs) diff --git a/edbob/pyramid/util.py b/edbob/pyramid/views/progress.py similarity index 50% rename from edbob/pyramid/util.py rename to edbob/pyramid/views/progress.py index a148fc2..4d86c3a 100644 --- a/edbob/pyramid/util.py +++ b/edbob/pyramid/views/progress.py @@ -23,23 +23,34 @@ ################################################################################ """ -``edbob.pyramid.util`` -- Utilities +``edbob.pyramid.views.progress`` -- Progress Views """ +from edbob.pyramid.progress import get_progress_session -def get_referer(request, default=None): - """ - Returns a "referer" URL. - """ - if request.params.get('referer'): - return request.params['referer'] - if request.session.get('referer'): - return request.session.pop('referer') - referer = request.referer - if not referer or referer == request.current_route_url(): - if default: - referer = default - else: - referer = request.route_url('home') - return referer +def progress(request): + key = request.matchdict['key'] + session = get_progress_session(request.session, key) + if session.get('complete') and session.get('success_msg'): + request.session.flash(session['success_msg']) + return session + + +def cancel(request): + key = request.matchdict['key'] + session = get_progress_session(request.session, key) + session.clear() + session['cancelled'] = True + session.save() + msg = request.params.get('cancel_msg', "The operation was cancelled.") + request.session.flash(msg) + return {} + + +def includeme(config): + config.add_route('progress', '/progress/{key}') + config.add_view(progress, route_name='progress', renderer='json') + + config.add_route('progress.cancel', '/progress/{key}/cancel') + config.add_view(cancel, route_name='progress.cancel', renderer='json')