mirror of
https://github.com/Mailu/Mailu.git
synced 2025-03-17 20:57:54 +02:00
Add self-service domain registration
This commit is contained in:
parent
1c26c9e376
commit
381e76511d
@ -27,6 +27,7 @@ default_config = {
|
||||
'BOOTSTRAP_SERVE_LOCAL': True,
|
||||
'RATELIMIT_STORAGE_URL': 'redis://redis',
|
||||
'DEBUG': False,
|
||||
'DOMAIN_REGISTRATION': False,
|
||||
# Statistics management
|
||||
'INSTANCE_ID_PATH': '/data/instance',
|
||||
'STATS_ENDPOINT': '0.{}.stats.mailu.io',
|
||||
|
@ -52,6 +52,15 @@ class DomainForm(flask_wtf.FlaskForm):
|
||||
submit = fields.SubmitField(_('Create'))
|
||||
|
||||
|
||||
class DomainSignupForm(flask_wtf.FlaskForm):
|
||||
name = fields.StringField(_('Domain name'), [validators.DataRequired()])
|
||||
localpart = fields.StringField(_('Initial admin'), [validators.DataRequired()])
|
||||
pw = fields.PasswordField(_('Admin password'), [validators.DataRequired()])
|
||||
pw2 = fields.PasswordField(_('Confirm password'), [validators.EqualTo('pw')])
|
||||
captcha = flask_wtf.RecaptchaField()
|
||||
submit = fields.SubmitField(_('Create'))
|
||||
|
||||
|
||||
class AlternativeForm(flask_wtf.FlaskForm):
|
||||
name = fields.StringField(_('Alternative name'), [validators.DataRequired()])
|
||||
submit = fields.SubmitField(_('Create'))
|
||||
|
36
core/admin/mailu/ui/templates/domain/signup.html
Normal file
36
core/admin/mailu/ui/templates/domain/signup.html
Normal file
@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Register a domain{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
{% call macros.box(title="Requirements") %}
|
||||
<p>{% trans %}In order to register a new domain, you must first setup the
|
||||
domain zone so that the domain <code>MX</code> points to this server{% endtrans %}
|
||||
(<code>{{ config["HOSTNAMES"].split(",")[0] }}</code>).
|
||||
</p>
|
||||
<p>
|
||||
{% trans %}If you do not know how to setup an <code>MX</code> record for your DNS zone,
|
||||
please contact your DNS provider or administrator. Also, please wait a
|
||||
couple minutes after the <code>MX</code> is set so the local server cache
|
||||
expires.{% endtrans %}
|
||||
</p>
|
||||
{% endcall %}
|
||||
|
||||
{% call macros.box() %}
|
||||
{% if form.localpart %}
|
||||
{{ macros.form_fields((form.localpart, form.name), append='<span class="input-group-addon">@</span>') }}
|
||||
{{ macros.form_fields((form.pw, form.pw2)) }}
|
||||
{% else %}
|
||||
{{ macros.form_field(form.name) }}
|
||||
{% endif %}
|
||||
{{ macros.form_field(form.captcha) }}
|
||||
{{ macros.form_field(form.submit) }}
|
||||
{% endcall %}
|
||||
</form>
|
||||
{% endblock %}
|
@ -92,6 +92,13 @@
|
||||
<i class="fa fa-life-ring"></i> <span>{% trans %}Help{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% if config['DOMAIN_REGISTRATION'] %}
|
||||
<li>
|
||||
<a href="{{ url_for('.domain_signup') }}">
|
||||
<i class="fa fa-plus-square"></i> <span>{% trans %}Register a domain{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated %}
|
||||
<li>
|
||||
<a href="{{ url_for('.logout') }}">
|
||||
|
@ -2,7 +2,9 @@ from mailu import app, db, models
|
||||
from mailu.ui import ui, forms, access
|
||||
|
||||
import flask
|
||||
import flask_login
|
||||
import wtforms_components
|
||||
import dns.resolver
|
||||
|
||||
|
||||
@ui.route('/domain', methods=['GET'])
|
||||
@ -73,3 +75,52 @@ def domain_genkeys(domain_name):
|
||||
domain.generate_dkim_key()
|
||||
return flask.redirect(
|
||||
flask.url_for(".domain_details", domain_name=domain_name))
|
||||
|
||||
|
||||
@ui.route('/domain/signup', methods=['GET', 'POST'])
|
||||
def domain_signup(domain_name=None):
|
||||
if not app.config['DOMAIN_REGISTRATION']:
|
||||
flask.abort(403)
|
||||
form = forms.DomainSignupForm()
|
||||
if flask_login.current_user.is_authenticated:
|
||||
del form.localpart
|
||||
del form.pw
|
||||
del form.pw2
|
||||
if form.validate_on_submit():
|
||||
conflicting_domain = models.Domain.query.get(form.name.data)
|
||||
conflicting_alternative = models.Alternative.query.get(form.name.data)
|
||||
conflicting_relay = models.Relay.query.get(form.name.data)
|
||||
hostnames = app.config['HOSTNAMES'].split(',')
|
||||
if conflicting_domain or conflicting_alternative or conflicting_relay:
|
||||
flask.flash('Domain %s is already used' % form.name.data, 'error')
|
||||
else:
|
||||
# Check if the domain MX actually points to this server
|
||||
try:
|
||||
mxok = any(str(rset).split()[-1][:-1] in hostnames
|
||||
for rset in dns.resolver.query(form.name.data, 'MX'))
|
||||
except Exception as e:
|
||||
mxok = False
|
||||
if mxok:
|
||||
# Actually create the domain
|
||||
domain = models.Domain()
|
||||
form.populate_obj(domain)
|
||||
domain.max_quota_bytes = app.config['DEFAULT_QUOTA']
|
||||
domain.max_users = 10
|
||||
domain.max_aliases = 10
|
||||
db.session.add(domain)
|
||||
if flask_login.current_user.is_authenticated:
|
||||
user = models.User.query.get(flask_login.current_user.email)
|
||||
else:
|
||||
user = models.User()
|
||||
user.domain = domain
|
||||
form.populate_obj(user)
|
||||
user.set_password(form.pw.data)
|
||||
user.quota_bytes = domain.max_quota_bytes
|
||||
db.session.add(user)
|
||||
domain.managers.append(user)
|
||||
db.session.commit()
|
||||
flask.flash('Domain %s created' % domain)
|
||||
return flask.redirect(flask.url_for('.domain_list'))
|
||||
else:
|
||||
flask.flash('The MX record was not properly set', 'error')
|
||||
return flask.render_template('domain/signup.html', form=form)
|
||||
|
@ -16,3 +16,4 @@ docker-py
|
||||
tabulate
|
||||
PyYAML
|
||||
PyOpenSSL
|
||||
dnspython
|
||||
|
Loading…
x
Reference in New Issue
Block a user