Return to Snippet

Revision: 12799
at March 29, 2009 09:28 by wackysalut


Initial Code
### My App name = Vigilia

## in vigilia/forms/__init__.py
class FieldSet(forms.FieldSet):
    def _render(self, **kwargs):
        return render('/fieldset.mako',
                      extra_vars=kwargs)
    def _render_readonly(self, **kwargs):
        return render('/fieldset_readonly.mako',
                      extra_vars=kwargs)

    def insert_after(self, after_what, field):
        """Insert a field to be rendered after a given field"""
        idx = self._render_fields._list.index(after_what)
        if idx is not None:
            self.insert_at_index(idx + 1, field)
        else:
            raise ValueError('No such field in render_fields: %s' % after_what)

    def insert_at_index(self, idx, field):
        """Insert a field to be rendered before a given field"""
        if field.key in self._render_fields._list:
            self._render_fields._list.remove(field.key)
        self._render_fields._list.insert(idx, field.key)
        self._render_fields[field.key] = field


class RadioSetRenderer(fields.RadioSet):
    widget = staticmethod(h.radio)
    def render(self, options, **kwargs):
        self.radios = []
        self.options = opts = options
        for i, (choice_name, choice_value) in enumerate(opts):
            choice_id = '%s_%i' % (self.name, i)
            radio = self.widget(self.name, choice_name, id=choice_id,
                            checked=self._is_checked(choice_value), **kwargs)
            label = h.make_tag('label', c=radio + ' %s' % choice_value)
            self.radios.append(label)
        return h.make_tag('div', c=h.make_tag("br").join(self.radios))

class CheckboxRenderer(RadioSetRenderer):
    widget = staticmethod(h.checkbox)


class EmailSmsRenderer(fields.TextFieldRenderer):
    pass

class PermissionField(fields.Field):
    is_collection = False
    is_composite_foreign_key = False

class PermissionsRenderer(fields.SelectFieldRenderer):
    def render(self, **kwargs):
        return h.select(self.name, [p.permission for p in self.field.model.permissions],
                        model.permissions_list,
                        size=len(model.permissions_list),
                        id=self.name, multiple=True)
    def deserialize(self):
        # This simple calculation makes sure we don't delete rows that
        # haven't changed. We only add rows that were actually added,
        # and remove the rows that were actually deleted from the last
        # saved records.
        u = self.field.model

        p1 = set([perm.permission for perm in u.permissions])
        p2 = set(self._params.getall(self.name))
        p_rem = list(p1.difference(p2))
        p_add = list(p2.difference(p1))

        # Remove unwanted permissions..
        u.permissions = [perm for perm in u.permissions
                         if perm.permission not in p_rem]
        # Add new permissions
        for x in p_add:
            u.permissions.append(model.Permission(x))

        return None


def password_validator(value, field):
    if field.parent.passwd1.value != value:
        raise validators.ValidationError('Les deux mots de passes ne concordent pas')






## in vigilia/model/___init___.py


# Permissions definitions
permissions_list = [
    ('admin', u'Administration globale'),
    ('moderation', u'Modération des commentaires'),
    ('posts_admin', u'Administration des posts'),
    ('posts_post', u'Poster un événement'),
    ('events_admin', u'Gestion des Activités'),
    ('logs_view', u'Visionnement des logs'),
    ]

# Users
users_t = Table('users', metadata,
                Column('id', Integer, primary_key=True),
                Column('username', String(25)),
                Column('password', String(50)),
                Column('firstname', Unicode(80)),
                Column('lastname', Unicode(80)),
                Column('gender', String(5), default='M'),
                Column('email', Unicode(255)),
                Column('email_sms', Unicode(150)),
                Column('photo', Unicode(255)),  # Lien relatif à une variable
                                               # de configuration, vers l'image
                Column('telephone', Unicode(100)),
                Column('dob', Date), # Date of birth - Sans garder l'année
                Column('pref_email_new_post', Boolean),
                Column('pref_email_updt_post', Boolean),
                Column('pref_email_sms_post', Boolean), # Only when asked for
                Column('pref_email_new_event', Boolean),
                Column('pref_email_updt_event', Boolean),
                )


class User(object):
    @property
    def fullname(self):
        """Create the full-name representation of the user."""
        if not self.firstname:
            return unicode(self.username)
        return self.firstname + \
               (' %s' % self.lastname if self.lastname else '')

    def __str__(self):
        return self.fullname

    def __repr__(self):
        return "<User: %s>" % self.username

    def __cmp__(self, other):
        if self.firstname is None or other.firstname is None:
            return 0
        n1 = self.firstname + self.lastname
        n2 = other.firstname + other.lastname
        return cmp(n1, n2)

    def has_perm(self, *args):
        """Checks if user has certain permissions"""
        return has_perm(permissions=[p.permission for p in self.permissions],
                        *args)



mapper(User, users_t, {
    'post_answers': relation(PostAnswer, lazy=True, backref='answer_user'),
    'recipient_to': relation(Recipient, backref='user'),
    'last_viewed': relation(LastViewed, backref='user'),
    'permissions': relation(Permission),
    'openids': relation(OpenID, backref='user'),
    })




## in vigilia/controller/users.py

from vigilia.lib.base import *

log = logging.getLogger(__name__)

def gen_fieldset(mdl):
    fs = forms.FieldSet(mdl)
    fs.add(forms.Field('passwd1'))
    fs.add(forms.Field('passwd2'))
    fs.add(forms.PermissionField(name='permissions'))
    fs.add(forms.Field('alert', value='').label(u'E-mail notification')\
                .checkbox([('X', u'Envoyer un courriel avec ces informations '\
                                  'au nouvel usager')])\
                .with_renderer(forms.CheckboxRenderer))
    inc = [fs.username.label(u"Nom d'usager"),
           fs.passwd1.password().label(u'Mot de passe'),
           fs.passwd2.password().label(u'Répétez le mot de passe').validate(forms.password_validator),
           fs.gender.label(u'Genre').radio([('M', 'M'), ('F', 'F')]).with_renderer(forms.RadioSetRenderer),
           fs.firstname.label(u'Prénom'),
           fs.lastname.label(u'Nom de famille'),
           fs.email.label(u'Courriel'),
           fs.permissions.label(u'Permissions').with_renderer(forms.PermissionsRenderer),
           fs.groups.label(u'Groupes'),
           fs.email_sms.label(u'Passerelle SMS (courriel)').with_renderer(forms.EmailSmsRenderer),
           fs.dob.label(u'Date de naissance').with_renderer(forms.DateFieldRendererFr),
           ]
    fs.configure(include=inc)
    return fs

class UsersController(BaseController):

    @has_perm('admin')
    def index(self):
        c.list = model.User.query().order_by('firstname, lastname').all()

        return render('/users/index.html')


    @has_perm('admin')
    def edit(self, id):
        # New or modify
        if id:
            c.usr = model.User.query.get(id)
        else:
            c.usr = model.User

        c.permissions_list = model.permissions_list

        fs = gen_fieldset(c.usr)
        fs = fs.bind(c.usr, data=request.POST or None)
        
        if not id:
            # Require password if it's first adding..
            fs.insert_after('passwd2', fs.alert)
            fs.configure(options=[fs.passwd1.required()])

        if request.POST and fs.validate():
            fs.sync()
            if fs.passwd1.value:
                fs.model.password = fs.passwd1.value
                push_flash(INFO, u"Le mot de passe de l'usager a été modifié")
            if fs.alert.value:
                ### TODO: send a notification e-mail here
                push_flash(INFO, u"Un courriel de notification a été envoyé")
            meta.Session.commit()
            push_flash(SUCCESS, u"Usager sauvegardé avec succès")
            redirect_to(controller='users', action='index')

        c.fieldset = fs
        return render('/users/edit.html')


## in vigilia/lib/base.py

rom vigilia import forms

Initial URL


Initial Description
This is based on FormEncode 1.2 + two patches you get here:
 http://code.google.com/p/formalchemy/issues/detail?id=83
and here:
 http://code.google.com/p/formalchemy/issues/detail?id=84
(at this point, they might be included in the official release).

Initial Title
FormAlchemy example with custom validator, renderers, forms - Pylons app

Initial Tags


Initial Language
Python