diff --git a/tailbone/app.py b/tailbone/app.py index 55f85c7b..d9c791e4 100644 --- a/tailbone/app.py +++ b/tailbone/app.py @@ -1,9 +1,8 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2012 Lance Edgar +# Copyright © 2010-2015 Lance Edgar # # This file is part of Rattail. # @@ -21,22 +20,29 @@ # along with Rattail. If not, see . # ################################################################################ - """ Application Entry Point """ -from pyramid.config import Configurator +from __future__ import unicode_literals -import os.path -import edbob +import os from sqlalchemy import engine_from_config -from .db import Session + +import edbob +from edbob.pyramid.forms.formalchemy import TemplateEngine + +from rattail.db.types import GPCType + +import formalchemy +from pyramid.config import Configurator +from pyramid.authentication import SessionAuthenticationPolicy from zope.sqlalchemy import ZopeTransactionExtension -from pyramid.authentication import SessionAuthenticationPolicy -from .auth import TailboneAuthorizationPolicy +from tailbone.db import Session +from tailbone.auth import TailboneAuthorizationPolicy +from tailbone.forms import GPCFieldRenderer def main(global_config, **settings): @@ -73,6 +79,10 @@ def main(global_config, **settings): # Bring in the rest of Tailbone. config.include('tailbone') + # Configure FormAlchemy. + formalchemy.config.engine = TemplateEngine() + formalchemy.FieldSet.default_renderers[GPCType] = GPCFieldRenderer + # Consider PostgreSQL server restart errors to be "retryable." config.add_tween('edbob.pyramid.tweens.sqlerror_tween_factory', under='pyramid_tm.tm_tween_factory') diff --git a/tailbone/templates/crud.mako b/tailbone/templates/crud.mako index 9d3a6297..b1afa0e5 100644 --- a/tailbone/templates/crud.mako +++ b/tailbone/templates/crud.mako @@ -3,7 +3,7 @@ <%def name="title()">${"New "+form.pretty_name if form.creating else form.pretty_name+' : '+capture(self.model_title)} -<%def name="model_title()">${h.literal(str(form.fieldset.model))} +<%def name="model_title()">${h.literal(unicode(form.fieldset.model))} <%def name="head_tags()"> ${parent.head_tags()} diff --git a/tailbone/views/labels.py b/tailbone/views/labels.py index 82b49dec..bd292fcb 100644 --- a/tailbone/views/labels.py +++ b/tailbone/views/labels.py @@ -1,9 +1,8 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2012 Lance Edgar +# Copyright © 2010-2015 Lance Edgar # # This file is part of Rattail. # @@ -21,11 +20,12 @@ # along with Rattail. If not, see . # ################################################################################ - """ Label Views """ +from __future__ import unicode_literals + from pyramid.httpexceptions import HTTPFound import formalchemy @@ -35,7 +35,6 @@ from webhelpers.html import HTML from ..db import Session from . import SearchableAlchemyGridView, CrudView from ..grids.search import BooleanSearchFilter -from edbob.pyramid.forms import StrippingFieldRenderer from rattail.db.model import LabelProfile @@ -102,8 +101,6 @@ class ProfileCrud(CrudView): return super(FormatFieldRenderer, self).render(**kwargs) fs = self.make_fieldset(model) - fs.printer_spec.set(renderer=StrippingFieldRenderer) - fs.formatter_spec.set(renderer=StrippingFieldRenderer) fs.format.set(renderer=FormatFieldRenderer) fs.configure( include=[ diff --git a/tailbone/views/users.py b/tailbone/views/users.py index 562ec8e3..983fe3ad 100644 --- a/tailbone/views/users.py +++ b/tailbone/views/users.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2014 Lance Edgar +# Copyright © 2010-2015 Lance Edgar # # This file is part of Rattail. # @@ -20,27 +20,24 @@ # along with Rattail. If not, see . # ################################################################################ - """ User Views """ from __future__ import unicode_literals +from rattail.db.model import User, Person, Role +from rattail.db.auth import guest_role, set_user_password + +import formalchemy from formalchemy import Field, ValidationError from formalchemy.fields import SelectFieldRenderer - -from edbob.pyramid.views import users +from webhelpers.html import tags +from webhelpers.html import HTML from . import SearchableAlchemyGridView, CrudView from ..forms import PersonFieldLinkRenderer from ..db import Session -from rattail.db.model import User, Person, Role -from rattail.db.auth import guest_role - -from webhelpers.html import tags -from webhelpers.html import HTML - from tailbone.grids.search import BooleanSearchFilter @@ -141,6 +138,33 @@ def RolesFieldRenderer(request): return RolesFieldRenderer +class PasswordFieldRenderer(formalchemy.PasswordFieldRenderer): + + def render(self, **kwargs): + return tags.password(self.name, value='', maxlength=self.length, **kwargs) + + +def passwords_match(value, field): + if field.parent.confirm_password.value != value: + raise formalchemy.ValidationError("Passwords do not match") + return value + + +class PasswordField(formalchemy.Field): + + def __init__(self, *args, **kwargs): + kwargs.setdefault('value', lambda x: x.password) + kwargs.setdefault('renderer', PasswordFieldRenderer) + kwargs.setdefault('validate', passwords_match) + super(PasswordField, self).__init__(*args, **kwargs) + + def sync(self): + if not self.is_readonly(): + password = self.renderer.deserialize() + if password: + set_user_password(self.model, password) + + class UserCrud(CrudView): mapped_class = User @@ -152,9 +176,9 @@ class UserCrud(CrudView): # Must set Person options to empty set to avoid unwanted magic. fs.person.set(options=[]) - fs.append(users.PasswordField('password')) + fs.append(PasswordField('password')) fs.append(Field('confirm_password', - renderer=users.PasswordFieldRenderer)) + renderer=PasswordFieldRenderer)) fs.append(RolesField( 'roles', renderer=RolesFieldRenderer(self.request)))