From 5f36e6f4f2539c663c4af987ec8b5842294b1ec4 Mon Sep 17 00:00:00 2001 From: Pierre Jaury Date: Thu, 11 Aug 2016 13:33:04 +0200 Subject: [PATCH] Related to #19, implement domain specific field and database type --- admin/freeposte/admin/forms.py | 30 ++++++++++++++++++- admin/freeposte/admin/models.py | 20 ++++++++++++- .../admin/templates/alias/create.html | 2 +- admin/freeposte/admin/views/aliases.py | 8 ----- 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/admin/freeposte/admin/forms.py b/admin/freeposte/admin/forms.py index 9881b7cc..eec6bc0a 100644 --- a/admin/freeposte/admin/forms.py +++ b/admin/freeposte/admin/forms.py @@ -1,6 +1,34 @@ from flask_wtf import Form from wtforms import validators, fields, widgets from wtforms_components import fields as fields_ +from flask.ext import login as flask_login + +import re + + +class DestinationField(fields.SelectMultipleField): + """ Allow for multiple emails selection from current user choices and + additional email addresses. + """ + + validator = re.compile(r'^.+@([^.@][^@]+)$', re.IGNORECASE) + + def iter_choices(self): + managed = [ + str(email) + for email in flask_login.current_user.get_managed_emails() + ] + for email in managed: + selected = self.data is not None and self.coerce(email) in self.data + yield (email, email, selected) + for email in self.data: + if email not in managed: + yield (email, email, True) + + def pre_validate(self, form): + for item in self.data: + if not self.validator.match(item): + raise validators.ValidationError("Invalid email address.") class LoginForm(Form): @@ -58,7 +86,7 @@ class UserReplyForm(Form): class AliasForm(Form): localpart = fields.StringField('Alias', [validators.DataRequired()]) - destination = fields.SelectField('Destination') + destination = DestinationField('Destination') comment = fields.StringField('Comment') submit = fields.SubmitField('Create') diff --git a/admin/freeposte/admin/models.py b/admin/freeposte/admin/models.py index f2a2338c..77a3368f 100644 --- a/admin/freeposte/admin/models.py +++ b/admin/freeposte/admin/models.py @@ -18,6 +18,24 @@ managers = db.Table('manager', ) +class CommaSeparatedList(db.TypeDecorator): + """ Stores a list as a comma-separated string, compatible with Postfix. + """ + + impl = db.String + + def process_bind_param(self, value, dialect): + if type(value) is not list: + raise TypeError("Shoud be a list") + for item in value: + if "," in item: + raise ValueError("No item should contain a comma") + return ",".join(value) + + def process_result_value(self, value, dialect): + return value.split(",") + + class Base(db.Model): """ Base class for all models """ @@ -169,7 +187,7 @@ class Alias(Email): """ An alias is an email address that redirects to some destination. """ domain = db.relationship(Domain, backref='aliases') - destination = db.Column(db.String(), nullable=False) + destination = db.Column(CommaSeparatedList, nullable=False) class Fetch(Base): diff --git a/admin/freeposte/admin/templates/alias/create.html b/admin/freeposte/admin/templates/alias/create.html index cb1ab25c..ba52c657 100644 --- a/admin/freeposte/admin/templates/alias/create.html +++ b/admin/freeposte/admin/templates/alias/create.html @@ -12,7 +12,7 @@ Create alias
{{ form.hidden_tag() }} {{ macros.form_field(form.localpart, append='@'+domain.name+'') }} - {{ macros.form_field(form.destination, id='destination', multiple='multiple') }} + {{ macros.form_field(form.destination, id='destination') }} {{ macros.form_field(form.comment) }} {{ macros.form_field(form.submit) }}