Enable self-service account signup
This commit is contained in:
@@ -60,6 +60,7 @@ class Domain(Base):
|
||||
max_users = db.Column(db.Integer, nullable=False, default=0)
|
||||
max_aliases = db.Column(db.Integer, nullable=False, default=0)
|
||||
max_quota_bytes = db.Column(db.Integer(), nullable=False, default=0)
|
||||
signup_enabled = db.Column(db.Boolean(), nullable=False, default=False)
|
||||
|
||||
@property
|
||||
def dkim_key(self):
|
||||
|
||||
@@ -47,6 +47,7 @@ class DomainForm(flask_wtf.FlaskForm):
|
||||
max_users = fields_.IntegerField(_('Maximum user count'), default=10)
|
||||
max_aliases = fields_.IntegerField(_('Maximum alias count'), default=10)
|
||||
max_quota_bytes = fields_.IntegerSliderField(_('Maximum user quota'), default=0)
|
||||
signup_enabled = fields.BooleanField(_('Enable sign-up'), default=False)
|
||||
comment = fields.StringField(_('Comment'))
|
||||
submit = fields.SubmitField(_('Create'))
|
||||
|
||||
@@ -74,6 +75,13 @@ class UserForm(flask_wtf.FlaskForm):
|
||||
submit = fields.SubmitField(_('Save'))
|
||||
|
||||
|
||||
class UserSignupForm(flask_wtf.FlaskForm):
|
||||
localpart = fields.StringField(_('Email address'))
|
||||
pw = fields.PasswordField(_('Password'), [validators.DataRequired()])
|
||||
pw2 = fields.PasswordField(_('Confirm password'), [validators.EqualTo('pw')])
|
||||
submit = fields.SubmitField(_('Sign up'))
|
||||
|
||||
|
||||
class UserSettingsForm(flask_wtf.FlaskForm):
|
||||
displayed_name = fields.StringField(_('Displayed name'))
|
||||
spam_enabled = fields.BooleanField(_('Enable spam filter'))
|
||||
|
||||
@@ -100,10 +100,17 @@
|
||||
</li>
|
||||
{% else %}
|
||||
<li>
|
||||
<a href="#">
|
||||
<a href="{{ url_for('.login') }}">
|
||||
<i class="fa fa-sign-in"></i> <span>{% trans %}Sign in{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% if signup_domains %}
|
||||
<li>
|
||||
<a href="{{ url_for('.user_signup') }}">
|
||||
<i class="fa fa-user-plus"></i> <span>{% trans %}Sign up{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
20
core/admin/mailu/ui/templates/user/signup.html
Normal file
20
core/admin/mailu/ui/templates/user/signup.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Sign up{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block subtitle %}
|
||||
{{ domain }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{% call macros.box() %}
|
||||
{{ macros.form_field(form.localpart, append='<span class="input-group-addon">@'+domain.name+'</span>') }}
|
||||
{{ macros.form_fields((form.pw, form.pw2)) }}
|
||||
{{ macros.form_field(form.submit) }}
|
||||
{% endcall %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
26
core/admin/mailu/ui/templates/user/signup_domain.html
Normal file
26
core/admin/mailu/ui/templates/user/signup_domain.html
Normal file
@@ -0,0 +1,26 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Sign up{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block subtitle %}
|
||||
{% trans %}pick a domain for the new account{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
<tr>
|
||||
<th>{% trans %}Domain{% endtrans %}</th>
|
||||
<th>{% trans %}Available slots{% endtrans %}</th>
|
||||
<th>{% trans %}Quota{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for domain_name, domain in available_domains.items() %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('.user_signup', domain_name=domain_name) }}">{{ domain_name }}</a></td>
|
||||
<td>{{ domain.max_users - domain.users if domain.max_users else '∞' }}</td>
|
||||
<td>{{ domain.max_quota_bytes or config['DEFAULT_QUOTA'] | filesizeformat }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
@@ -153,3 +153,35 @@ def user_reply(user_email):
|
||||
return flask.redirect(
|
||||
flask.url_for('.user_list', domain_name=user.domain.name))
|
||||
return flask.render_template('user/reply.html', form=form, user=user)
|
||||
|
||||
|
||||
@ui.route('/user/signup', methods=['GET', 'POST'])
|
||||
@ui.route('/user/signup/<domain_name>', methods=['GET', 'POST'])
|
||||
def user_signup(domain_name=None):
|
||||
available_domains = {
|
||||
domain.name: domain
|
||||
for domain in models.Domain.query.filter_by(signup_enabled=True).all()
|
||||
if not domain.max_users or len(domain.users) < domain.max_users
|
||||
}
|
||||
if not available_domains:
|
||||
flask.flash('No domain available for registration')
|
||||
if not domain_name:
|
||||
return flask.render_template('user/signup_domain.html',
|
||||
available_domains=available_domains)
|
||||
domain = available_domains.get(domain_name) or flask.abort(404)
|
||||
quota_bytes = min(config['DEFAULT_QUOTA'], domain.max_quota_bytes)
|
||||
form = forms.UserSignupForm()
|
||||
if form.validate_on_submit():
|
||||
if domain.has_email(form.localpart.data):
|
||||
flask.flash('Email is already used', 'error')
|
||||
else:
|
||||
user = models.User(domain=domain)
|
||||
form.populate_obj(user)
|
||||
user.set_password(form.pw.data)
|
||||
user.quota_bytes = quota_bytes
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
user.send_welcome()
|
||||
flask.flash('Successfully signed up %s' % user)
|
||||
return flask.redirect(flask.url_for('.index'))
|
||||
return flask.render_template('user/signup.html', domain=domain, form=form)
|
||||
|
||||
Reference in New Issue
Block a user