mirror of
https://github.com/Mailu/Mailu.git
synced 2024-12-14 10:53:30 +02:00
Merge branch 'master' into feature-auth-tokens
This commit is contained in:
commit
23bb932785
@ -33,6 +33,9 @@ POSTMASTER=admin
|
|||||||
# Choose how secure connections will behave (value: letsencrypt, cert, notls)
|
# Choose how secure connections will behave (value: letsencrypt, cert, notls)
|
||||||
TLS_FLAVOR=cert
|
TLS_FLAVOR=cert
|
||||||
|
|
||||||
|
# Authentication rate limit (per source IP address)
|
||||||
|
AUTH_RATELIMIT=10/minute;1000/hour
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
# Optional features
|
# Optional features
|
||||||
###################################
|
###################################
|
||||||
@ -85,6 +88,12 @@ WEB_ADMIN=/admin
|
|||||||
# Path to the webmail if enabled
|
# Path to the webmail if enabled
|
||||||
WEB_WEBMAIL=/webmail
|
WEB_WEBMAIL=/webmail
|
||||||
|
|
||||||
|
# Website name
|
||||||
|
SITENAME=Mailu
|
||||||
|
|
||||||
|
# Linked Website URL
|
||||||
|
WEBSITE=https://mailu.io
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
# Advanced settings
|
# Advanced settings
|
||||||
###################################
|
###################################
|
||||||
|
@ -5,6 +5,7 @@ import flask_login
|
|||||||
import flask_script
|
import flask_script
|
||||||
import flask_migrate
|
import flask_migrate
|
||||||
import flask_babel
|
import flask_babel
|
||||||
|
import flask_limiter
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import docker
|
import docker
|
||||||
@ -20,6 +21,8 @@ default_config = {
|
|||||||
'HOSTNAMES': 'mail.mailu.io',
|
'HOSTNAMES': 'mail.mailu.io',
|
||||||
'DOMAIN': 'mailu.io',
|
'DOMAIN': 'mailu.io',
|
||||||
'POSTMASTER': 'postmaster',
|
'POSTMASTER': 'postmaster',
|
||||||
|
'SITENAME': 'Mailu',
|
||||||
|
'WEBSITE': 'https://mailu.io',
|
||||||
'DEBUG': False,
|
'DEBUG': False,
|
||||||
'BOOTSTRAP_SERVE_LOCAL': True,
|
'BOOTSTRAP_SERVE_LOCAL': True,
|
||||||
'DKIM_PATH': '/dkim/{domain}.{selector}.key',
|
'DKIM_PATH': '/dkim/{domain}.{selector}.key',
|
||||||
@ -32,6 +35,9 @@ default_config = {
|
|||||||
'TLS_FLAVOR': 'cert',
|
'TLS_FLAVOR': 'cert',
|
||||||
'CERTS_PATH': '/certs',
|
'CERTS_PATH': '/certs',
|
||||||
'PASSWORD_SCHEME': 'SHA512-CRYPT',
|
'PASSWORD_SCHEME': 'SHA512-CRYPT',
|
||||||
|
'WEBMAIL': 'none',
|
||||||
|
'AUTH_RATELIMIT': '10/minute;1000/hour',
|
||||||
|
'RATELIMIT_STORAGE_URL': 'redis://redis'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Load configuration from the environment if available
|
# Load configuration from the environment if available
|
||||||
@ -42,6 +48,7 @@ for key, value in default_config.items():
|
|||||||
flask_bootstrap.Bootstrap(app)
|
flask_bootstrap.Bootstrap(app)
|
||||||
db = flask_sqlalchemy.SQLAlchemy(app)
|
db = flask_sqlalchemy.SQLAlchemy(app)
|
||||||
migrate = flask_migrate.Migrate(app, db)
|
migrate = flask_migrate.Migrate(app, db)
|
||||||
|
limiter = flask_limiter.Limiter(app, key_func=lambda: current_user.username)
|
||||||
|
|
||||||
# Debugging toolbar
|
# Debugging toolbar
|
||||||
if app.config.get("DEBUG"):
|
if app.config.get("DEBUG"):
|
||||||
@ -72,8 +79,11 @@ def handle_needs_login():
|
|||||||
)
|
)
|
||||||
|
|
||||||
@app.context_processor
|
@app.context_processor
|
||||||
def inject_user():
|
def inject_defaults():
|
||||||
return dict(current_user=flask_login.current_user)
|
return dict(
|
||||||
|
current_user=flask_login.current_user,
|
||||||
|
config=app.config
|
||||||
|
)
|
||||||
|
|
||||||
# Import views
|
# Import views
|
||||||
from mailu import ui, internal
|
from mailu import ui, internal
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
from mailu import db, models
|
from mailu import db, models, app, limiter
|
||||||
from mailu.internal import internal, nginx
|
from mailu.internal import internal, nginx
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
|
|
||||||
|
|
||||||
@internal.route("/auth/email")
|
@internal.route("/auth/email")
|
||||||
|
@limiter.limit(
|
||||||
|
app.config["AUTH_RATELIMIT"],
|
||||||
|
lambda: flask.request.headers["Client-Ip"]
|
||||||
|
)
|
||||||
def nginx_authentication():
|
def nginx_authentication():
|
||||||
""" Main authentication endpoint for Nginx email server
|
""" Main authentication endpoint for Nginx email server
|
||||||
"""
|
"""
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
{% trans %}Add a global administrator{% endtrans %}
|
{% trans %}Add a global administrator{% endtrans %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
|
{% call macros.box() %}
|
||||||
<form class="form" method="post" role="form">
|
<form class="form" method="post" role="form">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ macros.form_field(form.admin, id='admin') }}
|
{{ macros.form_field(form.admin, id='admin') }}
|
||||||
@ -13,4 +14,5 @@
|
|||||||
$("#admin").select2();
|
$("#admin").select2();
|
||||||
</script>
|
</script>
|
||||||
</form>
|
</form>
|
||||||
|
{% endcall %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -10,9 +10,8 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box %}
|
{% block content %}
|
||||||
<table class="table table-bordered">
|
{% call macros.table() %}
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans %}Actions{% endtrans %}</th>
|
<th>{% trans %}Actions{% endtrans %}</th>
|
||||||
<th>{% trans %}Email{% endtrans %}</th>
|
<th>{% trans %}Email{% endtrans %}</th>
|
||||||
@ -25,6 +24,5 @@
|
|||||||
<td>{{ admin }}</td>
|
<td>{{ admin }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
{% endcall %}
|
||||||
</table>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
{{ domain }}
|
{{ domain }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
|
{% call macros.box() %}
|
||||||
<form class="form" method="post" role="form">
|
<form class="form" method="post" role="form">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ macros.form_field(form.localpart, append='<span class="input-group-addon">@'+domain.name+'</span>') }}
|
{{ macros.form_field(form.localpart, append='<span class="input-group-addon">@'+domain.name+'</span>') }}
|
||||||
@ -23,4 +24,5 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
</form>
|
</form>
|
||||||
|
{% endcall %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -12,9 +12,8 @@
|
|||||||
<a class="btn btn-primary" href="{{ url_for('.alias_create', domain_name=domain.name) }}">{% trans %}Add alias{% endtrans %}</a>
|
<a class="btn btn-primary" href="{{ url_for('.alias_create', domain_name=domain.name) }}">{% trans %}Add alias{% endtrans %}</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box %}
|
{% block content %}
|
||||||
<table class="table table-bordered">
|
{% call macros.table() %}
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans %}Actions{% endtrans %}</th>
|
<th>{% trans %}Actions{% endtrans %}</th>
|
||||||
<th>{% trans %}Email{% endtrans %}</th>
|
<th>{% trans %}Email{% endtrans %}</th>
|
||||||
@ -36,6 +35,5 @@
|
|||||||
<td>{{ alias.updated_at or '' }}</td>
|
<td>{{ alias.updated_at or '' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
{% endcall %}
|
||||||
</table>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -12,9 +12,8 @@
|
|||||||
<a class="btn btn-primary" href="{{ url_for('.alternative_create', domain_name=domain.name) }}">{% trans %}Add alternative{% endtrans %}</a>
|
<a class="btn btn-primary" href="{{ url_for('.alternative_create', domain_name=domain.name) }}">{% trans %}Add alternative{% endtrans %}</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box %}
|
{% block content %}
|
||||||
<table class="table table-bordered">
|
{% call macros.table() %}
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans %}Actions{% endtrans %}</th>
|
<th>{% trans %}Actions{% endtrans %}</th>
|
||||||
<th>{% trans %}Name{% endtrans %}</th>
|
<th>{% trans %}Name{% endtrans %}</th>
|
||||||
@ -29,6 +28,5 @@
|
|||||||
<td>{{ alternative.created_at }}</td>
|
<td>{{ alternative.created_at }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
{% endcall %}
|
||||||
</table>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -8,11 +8,13 @@
|
|||||||
{% trans %}from{% endtrans %} {{ from_address }}
|
{% trans %}from{% endtrans %} {{ from_address }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
|
{% call macros.box() %}
|
||||||
<form class="form" method="post" role="form">
|
<form class="form" method="post" role="form">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ macros.form_field(form.announcement_subject) }}
|
{{ macros.form_field(form.announcement_subject) }}
|
||||||
{{ macros.form_field(form.announcement_body, rows=10) }}
|
{{ macros.form_field(form.announcement_body, rows=10) }}
|
||||||
{{ macros.form_field(form.submit) }}
|
{{ macros.form_field(form.submit) }}
|
||||||
</form>
|
</form>
|
||||||
|
{% endcall %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -53,22 +53,7 @@ class="hold-transition skin-blue sidebar-mini"
|
|||||||
|
|
||||||
<section class="content">
|
<section class="content">
|
||||||
{{ utils.flashed_messages(container=False) }}
|
{{ utils.flashed_messages(container=False) }}
|
||||||
{% block content %}
|
{% block content %}{% endblock %}
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<div class="box">
|
|
||||||
{% block box %}
|
|
||||||
<div class="box-header">
|
|
||||||
{% block box_title %}{% endblock %}
|
|
||||||
</div>
|
|
||||||
<div class="box-body">
|
|
||||||
{% block box_content %}{% endblock %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<footer class="main-footer">
|
<footer class="main-footer">
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
{{ action }}
|
{{ action }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
|
{% call macros.box(theme="warning") %}
|
||||||
<p>{% trans action %}You are about to {{ action }}. Please confirm your action.{% endtrans %}</p>
|
<p>{% trans action %}You are about to {{ action }}. Please confirm your action.{% endtrans %}</p>
|
||||||
{{ macros.form(form) }}
|
{{ macros.form(form) }}
|
||||||
|
{% endcall %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
{{ action }}
|
{{ action }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
<p>{% trans action %}An error occurred while talking to the Docker server.{% endtrans %}</p>
|
<p>{% trans action %}An error occurred while talking to the Docker server.{% endtrans %}</p>
|
||||||
<pre>{{ error }}</pre>
|
<pre>{{ error }}</pre>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
{% trans %}New domain{% endtrans %}
|
{% trans %}New domain{% endtrans %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
|
{% call macros.box() %}
|
||||||
<form class="form" method="post" role="form">
|
<form class="form" method="post" role="form">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ macros.form_field(form.name) }}
|
{{ macros.form_field(form.name) }}
|
||||||
@ -15,4 +16,5 @@
|
|||||||
{{ macros.form_field(form.comment) }}
|
{{ macros.form_field(form.comment) }}
|
||||||
{{ macros.form_field(form.submit) }}
|
{{ macros.form_field(form.submit) }}
|
||||||
</form>
|
</form>
|
||||||
|
{% endcall %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -14,10 +14,9 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box %}
|
{% block content %}
|
||||||
|
{% call macros.table() %}
|
||||||
{% set hostname = config["HOSTNAMES"].split(",")[0] %}
|
{% set hostname = config["HOSTNAMES"].split(",")[0] %}
|
||||||
<table class="table table-bordered">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans %}Domain name{% endtrans %}</th>
|
<th>{% trans %}Domain name{% endtrans %}</th>
|
||||||
<td>{{ domain.name }}</td>
|
<td>{{ domain.name }}</td>
|
||||||
@ -46,6 +45,5 @@
|
|||||||
<td><pre>_dmarc.{{ domain.name }}. 600 IN TXT "v=DMARC1; p=reject;{% if config["DMARC_RUA"] %} rua=mailto:{{ config["DMARC_RUA"] }}@{{ config["DOMAIN"] }};{% endif %}{% if config["DMARC_RUF"] %} ruf=mailto:{{ config["DMARC_RUF"] }}@{{ config["DOMAIN"] }};{% endif %} adkim=s; aspf=s"</pre></td>
|
<td><pre>_dmarc.{{ domain.name }}. 600 IN TXT "v=DMARC1; p=reject;{% if config["DMARC_RUA"] %} rua=mailto:{{ config["DMARC_RUA"] }}@{{ config["DOMAIN"] }};{% endif %}{% if config["DMARC_RUF"] %} ruf=mailto:{{ config["DMARC_RUF"] }}@{{ config["DOMAIN"] }};{% endif %} adkim=s; aspf=s"</pre></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tbody>
|
{% endcall %}
|
||||||
</table>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -10,9 +10,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box %}
|
{% block content %}
|
||||||
<table class="table table-bordered">
|
{% call macros.table() %}
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans %}Actions{% endtrans %}</th>
|
<th>{% trans %}Actions{% endtrans %}</th>
|
||||||
<th>{% trans %}Manage{% endtrans %}</th>
|
<th>{% trans %}Manage{% endtrans %}</th>
|
||||||
@ -48,6 +47,5 @@
|
|||||||
<td>{{ domain.updated_at or '' }}</td>
|
<td>{{ domain.updated_at or '' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
{% endcall %}
|
||||||
</table>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% extends "form.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% trans %}Add a fetched account{% endtrans %}
|
{% trans %}Add a fetched account{% endtrans %}
|
||||||
@ -7,3 +7,21 @@
|
|||||||
{% block subtitle %}
|
{% block subtitle %}
|
||||||
{{ user }}
|
{{ user }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form class="form" method="post" role="form">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{% call macros.box(title="Remote server") %}
|
||||||
|
{{ macros.form_field(form.protocol) }}
|
||||||
|
{{ macros.form_fields((form.host, form.port)) }}
|
||||||
|
{{ macros.form_field(form.tls) }}
|
||||||
|
{% endcall %}
|
||||||
|
|
||||||
|
{% call macros.box(title="Authentication") %}
|
||||||
|
{{ macros.form_field(form.username) }}
|
||||||
|
{{ macros.form_field(form.password) }}
|
||||||
|
{% endcall %}
|
||||||
|
|
||||||
|
{{ macros.form_field(form.submit) }}
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% extends "form.html" %}
|
{% extends "fetch/create.html" %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% trans %}Update a fetched account{% endtrans %}
|
{% trans %}Update a fetched account{% endtrans %}
|
||||||
|
@ -12,9 +12,8 @@
|
|||||||
<a class="btn btn-primary" href="{{ url_for('.fetch_create', user_email=user.email) }}">{% trans %}Add an account{% endtrans %}</a>
|
<a class="btn btn-primary" href="{{ url_for('.fetch_create', user_email=user.email) }}">{% trans %}Add an account{% endtrans %}</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box %}
|
{% block content %}
|
||||||
<table class="table table-bordered">
|
{% call macros.table() %}
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans %}Actions{% endtrans %}</th>
|
<th>{% trans %}Actions{% endtrans %}</th>
|
||||||
<th>{% trans %}Endpoint{% endtrans %}</th>
|
<th>{% trans %}Endpoint{% endtrans %}</th>
|
||||||
@ -40,6 +39,5 @@
|
|||||||
<td>{{ fetch.updated_at or '' }}</td>
|
<td>{{ fetch.updated_at or '' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
{% endcall %}
|
||||||
</table>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
|
{% call macros.box() %}
|
||||||
{{ macros.form(form) }}
|
{{ macros.form(form) }}
|
||||||
|
{% endcall %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
{% macro render_field(field, label_visible=true) -%}
|
|
||||||
<div class="form-group {% if field.errors %}has-error{% endif %} {{ kwargs.pop('class_', '') }}">
|
|
||||||
{% if field.type != 'HiddenField' and label_visible %}
|
|
||||||
<label for="{{ field.id }}" class="control-label">{{ field.label }}</label>
|
|
||||||
{% endif %}
|
|
||||||
{{ field(class_='form-control', **kwargs) }}
|
|
||||||
{% if field.errors %}
|
|
||||||
{% for e in field.errors %}
|
|
||||||
<p class="help-block">{{ e }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{%- endmacro %}
|
|
@ -1,5 +0,0 @@
|
|||||||
{% extends "general.html" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
Test
|
|
||||||
{% endblock %}
|
|
@ -1,17 +1,4 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "form.html" %}
|
||||||
|
|
||||||
{% block sidebar %}
|
|
||||||
<section class="sidebar">
|
|
||||||
<ul class="sidebar-menu">
|
|
||||||
<li class="header">{% trans %}Your account{% endtrans %}</li>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<i class="fa fa-sign-in"></i> <span>{% trans %}Sign in{% endtrans %}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% trans %}Sign in{% endtrans %}
|
{% trans %}Sign in{% endtrans %}
|
||||||
@ -20,7 +7,3 @@
|
|||||||
{% block subtitle %}
|
{% block subtitle %}
|
||||||
{% trans %}to access the administration tools{% endtrans %}
|
{% trans %}to access the administration tools{% endtrans %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
|
||||||
{{ macros.form(form) }}
|
|
||||||
{% endblock %}
|
|
||||||
|
@ -63,3 +63,36 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</form>
|
</form>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro box(title=None, theme="primary", header=True) %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="box box-{{ theme }}">
|
||||||
|
{% if header %}
|
||||||
|
<div class="box-header">
|
||||||
|
{% if title %}
|
||||||
|
<h3 class="box-title">{{ title }}</h3>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="box-body">
|
||||||
|
{{ caller() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro table(theme="primary") %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="box box-{{ theme }}">
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<tbody>
|
||||||
|
{{ caller() }}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
{{ domain }}
|
{{ domain }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
|
{% call macros.box() %}
|
||||||
<form class="form" method="post" role="form">
|
<form class="form" method="post" role="form">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ macros.form_field(form.manager, id='manager') }}
|
{{ macros.form_field(form.manager, id='manager') }}
|
||||||
@ -17,4 +18,5 @@
|
|||||||
$("#manager").select2();
|
$("#manager").select2();
|
||||||
</script>
|
</script>
|
||||||
</form>
|
</form>
|
||||||
|
{% endcall %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -12,9 +12,8 @@
|
|||||||
<a class="btn btn-primary" href="{{ url_for('.manager_create', domain_name=domain.name) }}">{% trans %}Add manager{% endtrans %}</a>
|
<a class="btn btn-primary" href="{{ url_for('.manager_create', domain_name=domain.name) }}">{% trans %}Add manager{% endtrans %}</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box %}
|
{% block content %}
|
||||||
<table class="table table-bordered">
|
{% call macros.table() %}
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans %}Actions{% endtrans %}</th>
|
<th>{% trans %}Actions{% endtrans %}</th>
|
||||||
<th>{% trans %}Email{% endtrans %}</th>
|
<th>{% trans %}Email{% endtrans %}</th>
|
||||||
@ -27,6 +26,5 @@
|
|||||||
<td>{{ manager }}</td>
|
<td>{{ manager }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
{% endcall %}
|
||||||
</table>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -10,9 +10,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box %}
|
{% block content %}
|
||||||
<table class="table table-bordered">
|
{% call macros.table() %}
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans %}Actions{% endtrans %}</th>
|
<th>{% trans %}Actions{% endtrans %}</th>
|
||||||
<th>{% trans %}Domain name{% endtrans %}</th>
|
<th>{% trans %}Domain name{% endtrans %}</th>
|
||||||
@ -34,6 +33,5 @@
|
|||||||
<td>{{ relay.updated_at or '' }}</td>
|
<td>{{ relay.updated_at or '' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
{% endcall %}
|
||||||
</table>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -4,9 +4,8 @@
|
|||||||
{% trans %}Services status{% endtrans %}
|
{% trans %}Services status{% endtrans %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box %}
|
{% block content %}
|
||||||
<table class="table table-bordered">
|
{% call table() %}
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans %}Service{% endtrans %}</th>
|
<th>{% trans %}Service{% endtrans %}</th>
|
||||||
<th>{% trans %}Status{% endtrans %}</th>
|
<th>{% trans %}Status{% endtrans %}</th>
|
||||||
@ -25,6 +24,5 @@
|
|||||||
<td>{{ container['Image']['Created'] }}
|
<td>{{ container['Image']['Created'] }}
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
{% endcall %}
|
||||||
</table>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
<section class="sidebar">
|
<section class="sidebar">
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
<h4 class="text-center text-primary">{{ current_user }}</h4>
|
<h4 class="text-center text-primary">{{ current_user }}</h4>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<ul class="sidebar-menu">
|
<ul class="sidebar-menu">
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
<li class="header">{% trans %}My account{% endtrans %}</li>
|
<li class="header">{% trans %}My account{% endtrans %}</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('.user_settings') }}">
|
<a href="{{ url_for('.user_settings') }}">
|
||||||
@ -33,11 +36,7 @@
|
|||||||
<i class="fa fa-ticket"></i> <span>{% trans %}Authentication tokens{% endtrans %}</span>
|
<i class="fa fa-ticket"></i> <span>{% trans %}Authentication tokens{% endtrans %}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a href="{{ url_for('.logout') }}">
|
|
||||||
<i class="fa fa-sign-out"></i> <span>{% trans %}Sign out{% endtrans %}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="header">{% trans %}Administration{% endtrans %}</li>
|
<li class="header">{% trans %}Administration{% endtrans %}</li>
|
||||||
{% if current_user.global_admin %}
|
{% if current_user.global_admin %}
|
||||||
<li>
|
<li>
|
||||||
@ -68,11 +67,38 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<li class="header">{% trans %}Go to{% endtrans %}</li>
|
||||||
|
{% if config["WEBMAIL"] != "none" %}
|
||||||
|
<li>
|
||||||
|
<a href="/webmail/">
|
||||||
|
<i class="fa fa-envelope-o"></i> <span>{% trans %}Webmail{% endtrans %}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li>
|
||||||
|
<a href="https://mailu.io">
|
||||||
|
<i class="fa fa-globe"></i> <span>{% trans %}Website{% endtrans %}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/Mailu/Mailu">
|
<a href="https://github.com/Mailu/Mailu">
|
||||||
<i class="fa fa-life-ring"></i> <span>{% trans %}Help{% endtrans %}</span>
|
<i class="fa fa-life-ring"></i> <span>{% trans %}Help{% endtrans %}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ url_for('.logout') }}">
|
||||||
|
<i class="fa fa-sign-out"></i> <span>{% trans %}Sign out{% endtrans %}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li>
|
||||||
|
<a href="#">
|
||||||
|
<i class="fa fa-sign-in"></i> <span>{% trans %}Sign in{% endtrans %}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
@ -8,17 +8,24 @@
|
|||||||
{{ domain.name }}
|
{{ domain.name }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
<form class="form" method="post" role="form">
|
<form class="form" method="post" role="form">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
|
|
||||||
|
{% call macros.box("General") %}
|
||||||
{{ macros.form_field(form.localpart, append='<span class="input-group-addon">@'+domain.name+'</span>') }}
|
{{ macros.form_field(form.localpart, append='<span class="input-group-addon">@'+domain.name+'</span>') }}
|
||||||
{{ macros.form_fields((form.pw, form.pw2)) }}
|
{{ macros.form_fields((form.pw, form.pw2)) }}
|
||||||
|
{{ macros.form_field(form.comment) }}
|
||||||
|
{% endcall %}
|
||||||
|
|
||||||
|
{% call macros.box("Features and quotas", theme="success") %}
|
||||||
{{ macros.form_field(form.quota_bytes, step=1000000000, max=(max_quota_bytes or domain.max_quota_bytes or 50000000000),
|
{{ macros.form_field(form.quota_bytes, step=1000000000, max=(max_quota_bytes or domain.max_quota_bytes or 50000000000),
|
||||||
prepend='<span class="input-group-addon"><span id="quota">'+(form.quota_bytes.data//1000000000).__str__()+'</span> GiB</span>',
|
prepend='<span class="input-group-addon"><span id="quota">'+(form.quota_bytes.data//1000000000).__str__()+'</span> GiB</span>',
|
||||||
oninput='$("#quota").text(this.value/1000000000);') }}
|
oninput='$("#quota").text(this.value/1000000000);') }}
|
||||||
{{ macros.form_field(form.enable_imap) }}
|
{{ macros.form_field(form.enable_imap) }}
|
||||||
{{ macros.form_field(form.enable_pop) }}
|
{{ macros.form_field(form.enable_pop) }}
|
||||||
{{ macros.form_field(form.comment) }}
|
{% endcall %}
|
||||||
|
|
||||||
{{ macros.form_field(form.submit) }}
|
{{ macros.form_field(form.submit) }}
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
{{ user }}
|
{{ user }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
|
{% call macros.box() %}
|
||||||
<form class="form" method="post" role="form">
|
<form class="form" method="post" role="form">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ macros.form_field(form.forward_enabled,
|
{{ macros.form_field(form.forward_enabled,
|
||||||
@ -20,4 +21,5 @@
|
|||||||
**{("enabled" if user.forward_enabled else "disabled"): ""}) }}
|
**{("enabled" if user.forward_enabled else "disabled"): ""}) }}
|
||||||
{{ macros.form_field(form.submit) }}
|
{{ macros.form_field(form.submit) }}
|
||||||
</form>
|
</form>
|
||||||
|
{% endcall %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -12,9 +12,8 @@
|
|||||||
<a class="btn btn-primary" href="{{ url_for('.user_create', domain_name=domain.name) }}">{% trans %}Add user{% endtrans %}</a>
|
<a class="btn btn-primary" href="{{ url_for('.user_create', domain_name=domain.name) }}">{% trans %}Add user{% endtrans %}</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box %}
|
{% block content %}
|
||||||
<table class="table table-bordered">
|
{% call macros.table() %}
|
||||||
<tbody>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans %}Actions{% endtrans %}</th>
|
<th>{% trans %}Actions{% endtrans %}</th>
|
||||||
<th>{% trans %}User settings{% endtrans %}</th>
|
<th>{% trans %}User settings{% endtrans %}</th>
|
||||||
@ -36,7 +35,6 @@
|
|||||||
<a href="{{ url_for('.user_forward', user_email=user.email) }}" title="{% trans %}Auto-forward{% endtrans %}"><i class="fa fa-share"></i></a>
|
<a href="{{ url_for('.user_forward', user_email=user.email) }}" title="{% trans %}Auto-forward{% endtrans %}"><i class="fa fa-share"></i></a>
|
||||||
<a href="{{ url_for('.user_reply', user_email=user.email) }}" title="{% trans %}Auto-reply{% endtrans %}"><i class="fa fa-plane"></i></a>
|
<a href="{{ url_for('.user_reply', user_email=user.email) }}" title="{% trans %}Auto-reply{% endtrans %}"><i class="fa fa-plane"></i></a>
|
||||||
<a href="{{ url_for('.fetch_list', user_email=user.email) }}" title="{% trans %}Fetched accounts{% endtrans %}"><i class="fa fa-download"></i></a>
|
<a href="{{ url_for('.fetch_list', user_email=user.email) }}" title="{% trans %}Fetched accounts{% endtrans %}"><i class="fa fa-download"></i></a>
|
||||||
<a href="{{ url_for('.token_list', user_email=user.email) }}" title="{% trans %}Authentication tokens{% endtrans %}"><i class="fa fa-ticket"></i></a>
|
|
||||||
</td>
|
</td>
|
||||||
<td>{{ user }}</td>
|
<td>{{ user }}</td>
|
||||||
<td>
|
<td>
|
||||||
@ -49,6 +47,5 @@
|
|||||||
<td>{{ user.updated_at or '' }}</td>
|
<td>{{ user.updated_at or '' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
{% endcall %}
|
||||||
</table>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
{{ user }}
|
{{ user }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
|
{% call macros.box() %}
|
||||||
<form class="form" method="post" role="form">
|
<form class="form" method="post" role="form">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
{{ macros.form_field(form.reply_enabled,
|
{{ macros.form_field(form.reply_enabled,
|
||||||
@ -20,4 +21,5 @@
|
|||||||
**{("rw" if user.reply_enabled else "readonly"): ""}) }}
|
**{("rw" if user.reply_enabled else "readonly"): ""}) }}
|
||||||
{{ macros.form_field(form.submit) }}
|
{{ macros.form_field(form.submit) }}
|
||||||
</form>
|
</form>
|
||||||
|
{% endcall %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -8,14 +8,19 @@
|
|||||||
{{ user }}
|
{{ user }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block box_content %}
|
{% block content %}
|
||||||
<form class="form" method="post" role="form">
|
<form class="form" method="post" role="form">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
|
{% call macros.box(title="General settings") %}
|
||||||
{{ macros.form_field(form.displayed_name) }}
|
{{ macros.form_field(form.displayed_name) }}
|
||||||
|
{% endcall %}
|
||||||
|
|
||||||
|
{% call macros.box(title="Antispam") %}
|
||||||
{{ macros.form_field(form.spam_enabled) }}
|
{{ macros.form_field(form.spam_enabled) }}
|
||||||
{{ macros.form_field(form.spam_threshold, step=1, max=100,
|
{{ macros.form_field(form.spam_threshold, step=1, max=100,
|
||||||
prepend='<span class="input-group-addon"><span id="threshold">'+form.spam_threshold.data.__str__()+'</span> / 100</span>',
|
prepend='<span class="input-group-addon"><span id="threshold">'+form.spam_threshold.data.__str__()+'</span> / 100</span>',
|
||||||
oninput='$("#threshold").text(this.value);') }}
|
oninput='$("#threshold").text(this.value);') }}
|
||||||
|
{% endcall %}
|
||||||
{{ macros.form_field(form.submit) }}
|
{{ macros.form_field(form.submit) }}
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -62,8 +62,7 @@ def domain_delete(domain_name):
|
|||||||
@access.domain_admin(models.Domain, 'domain_name')
|
@access.domain_admin(models.Domain, 'domain_name')
|
||||||
def domain_details(domain_name):
|
def domain_details(domain_name):
|
||||||
domain = models.Domain.query.get(domain_name) or flask.abort(404)
|
domain = models.Domain.query.get(domain_name) or flask.abort(404)
|
||||||
return flask.render_template('domain/details.html', domain=domain,
|
return flask.render_template('domain/details.html', domain=domain)
|
||||||
config=app.config)
|
|
||||||
|
|
||||||
|
|
||||||
@ui.route('/domain/genkeys/<domain_name>', methods=['GET', 'POST'])
|
@ui.route('/domain/genkeys/<domain_name>', methods=['GET', 'POST'])
|
||||||
|
@ -15,6 +15,7 @@ Flask==0.12.2
|
|||||||
Flask-Babel==0.11.2
|
Flask-Babel==0.11.2
|
||||||
Flask-Bootstrap==3.3.7.1
|
Flask-Bootstrap==3.3.7.1
|
||||||
Flask-DebugToolbar==0.10.1
|
Flask-DebugToolbar==0.10.1
|
||||||
|
Flask-Limiter==0.9.5.1
|
||||||
Flask-Login==0.4.0
|
Flask-Login==0.4.0
|
||||||
Flask-Migrate==2.1.1
|
Flask-Migrate==2.1.1
|
||||||
Flask-Script==2.0.6
|
Flask-Script==2.0.6
|
||||||
@ -26,6 +27,7 @@ infinity==1.4
|
|||||||
intervals==0.8.0
|
intervals==0.8.0
|
||||||
itsdangerous==0.24
|
itsdangerous==0.24
|
||||||
Jinja2==2.9.6
|
Jinja2==2.9.6
|
||||||
|
limits==1.2.1
|
||||||
Mako==1.0.7
|
Mako==1.0.7
|
||||||
MarkupSafe==1.0
|
MarkupSafe==1.0
|
||||||
passlib==1.7.1
|
passlib==1.7.1
|
||||||
@ -35,6 +37,7 @@ python-dateutil==2.6.1
|
|||||||
python-editor==1.0.3
|
python-editor==1.0.3
|
||||||
pytz==2017.2
|
pytz==2017.2
|
||||||
PyYAML==3.12
|
PyYAML==3.12
|
||||||
|
redis==2.10.6
|
||||||
requests==2.18.4
|
requests==2.18.4
|
||||||
six==1.11.0
|
six==1.11.0
|
||||||
SQLAlchemy==1.1.14
|
SQLAlchemy==1.1.14
|
||||||
|
@ -7,6 +7,8 @@ Flask-migrate
|
|||||||
Flask-script
|
Flask-script
|
||||||
Flask-wtf
|
Flask-wtf
|
||||||
Flask-debugtoolbar
|
Flask-debugtoolbar
|
||||||
|
Flask-limiter
|
||||||
|
redis
|
||||||
WTForms-Components
|
WTForms-Components
|
||||||
passlib
|
passlib
|
||||||
gunicorn
|
gunicorn
|
||||||
|
Loading…
Reference in New Issue
Block a user