mirror of
https://github.com/Mailu/Mailu.git
synced 2024-12-14 10:53:30 +02:00
Merge #1800
1800: AdminLTE 3 r=mergify[bot] a=DjVinnii ## What type of PR? Enhancement ## What does this PR do? This PR implements AdminLTE 3 for the admin interface. It also includes the implementation of DataTables and a language selector. ### Related issue(s) - closes: #1567 - closes: #1764 ## Prerequistes - [x] Unless it's docs or a minor change: add [changelog](https://mailu.io/master/contributors/guide.html#changelog) entry file. Co-authored-by: Vincent Kling <vincentkling@msn.com> Co-authored-by: DjVinnii <vincentkling@msn.com> Co-authored-by: Dimitri Huisman <52963853+Diman0@users.noreply.github.com> Co-authored-by: Diman0 <diman@huisman.xyz> Co-authored-by: Dimitri Huisman <diman@huisman.xyz>
This commit is contained in:
commit
71cc8b0a81
@ -1,7 +1,8 @@
|
||||
# First stage to build assets
|
||||
ARG DISTRO=alpine:3.14
|
||||
ARG ARCH=""
|
||||
FROM ${ARCH}node:8 as assets
|
||||
|
||||
FROM ${ARCH}node:16 as assets
|
||||
COPY --from=balenalib/rpi-alpine:3.14 /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static
|
||||
|
||||
COPY package.json ./
|
||||
|
@ -20,3 +20,4 @@
|
||||
.sidebar-toggle {
|
||||
padding: unset !important;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,17 @@
|
||||
require('./app.css');
|
||||
|
||||
import 'select2';
|
||||
import 'admin-lte/plugins/select2/js/select2.js';
|
||||
import 'admin-lte/plugins/datatables/jquery.dataTables.js';
|
||||
import 'admin-lte/plugins/datatables-bs4/js/dataTables.bootstrap4.js';
|
||||
import 'admin-lte/plugins/datatables-responsive/js/dataTables.responsive.js';
|
||||
import 'admin-lte/plugins/datatables-responsive/js/responsive.bootstrap4.js';
|
||||
|
||||
jQuery("document").ready(function() {
|
||||
jQuery(".mailselect").select2({
|
||||
tags: true,
|
||||
tokenSeparators: [',', ' ']
|
||||
})
|
||||
});
|
||||
jQuery(".dataTable").DataTable({
|
||||
"responsive": true,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,19 +1,22 @@
|
||||
// jQuery
|
||||
import jQuery from 'jquery';
|
||||
import 'select2/dist/css/select2.css';
|
||||
import 'admin-lte/plugins/select2/css/select2.css';
|
||||
|
||||
// bootstrap
|
||||
import 'bootstrap/less/bootstrap.less';
|
||||
import 'bootstrap';
|
||||
// import 'bootstrap/less/bootstrap.less';
|
||||
// import 'bootstrap';
|
||||
|
||||
// FA
|
||||
import 'font-awesome/scss/font-awesome.scss';
|
||||
// FontAwesome
|
||||
import 'admin-lte/plugins/fontawesome-free/css/fontawesome.css';
|
||||
import 'admin-lte/plugins/fontawesome-free/css/regular.css';
|
||||
import 'admin-lte/plugins/fontawesome-free/css/solid.css';
|
||||
|
||||
// AdminLTE
|
||||
import 'admin-lte/build/less/AdminLTE-without-plugins.less';
|
||||
import 'admin-lte/build/less/select2.less';
|
||||
import 'admin-lte/build/less/skins/skin-blue.less';
|
||||
import 'admin-lte/build/scss/adminlte.scss';
|
||||
import 'admin-lte/plugins/datatables-bs4/css/dataTables.bootstrap4.css';
|
||||
import 'admin-lte/plugins/datatables-responsive/css/responsive.bootstrap4.css';
|
||||
import 'admin-lte/plugins/bootstrap/js/bootstrap.js';
|
||||
import 'admin-lte/build/js/AdminLTE.js';
|
||||
import 'admin-lte/build/js/Layout.js';
|
||||
import 'admin-lte/build/js/ControlSidebar.js';
|
||||
import 'admin-lte/build/js/PushMenu.js';
|
||||
import 'admin-lte/build/js/BoxRefresh.js';
|
||||
|
@ -5,7 +5,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.box() %}
|
||||
{% call macros.card() %}
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ macros.form_field(form.admin, class_='mailselect') }}
|
||||
|
@ -5,24 +5,28 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block main_action %}
|
||||
<a class="btn btn-primary" href="{{ url_for('.admin_create') }}">
|
||||
<a class="btn btn-primary float-right" href="{{ url_for('.admin_create') }}">
|
||||
{% trans %}Add administrator{% endtrans %}
|
||||
</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for admin in admins %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.admin_delete', admin=admin.email) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ admin }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for admin in admins %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.admin_delete', admin=admin.email) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ admin }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -9,10 +9,10 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.box() %}
|
||||
{% call macros.card() %}
|
||||
<form class="form" method="post" role="form">
|
||||
{{ 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-text">@'+domain.name+'</span>') }}
|
||||
{{ macros.form_field(form.wildcard) }}
|
||||
{{ macros.form_field(form.destination, class_='mailselect') }}
|
||||
{{ macros.form_field(form.comment) }}
|
||||
|
@ -9,31 +9,35 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block main_action %}
|
||||
<a class="btn btn-primary" href="{{ url_for('.alias_create', domain_name=domain.name) }}">{% trans %}Add alias{% endtrans %}</a>
|
||||
<a class="btn btn-primary float-right" href="{{ url_for('.alias_create', domain_name=domain.name) }}">{% trans %}Add alias{% endtrans %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
<th>{% trans %}Destination{% endtrans %}</th>
|
||||
<th>{% trans %}Comment{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
<th>{% trans %}Last edit{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for alias in domain.aliases %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.alias_edit', alias=alias.email) }}" title="{% trans %}Edit{% endtrans %}"><i class="fa fa-pencil"></i></a>
|
||||
<a href="{{ url_for('.alias_delete', alias=alias.email) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ alias }}</td>
|
||||
<td>{{ alias.destination|join(', ') or '-' }}</td>
|
||||
<td>{{ alias.comment or '' }}</td>
|
||||
<td>{{ alias.created_at }}</td>
|
||||
<td>{{ alias.updated_at or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
<th>{% trans %}Destination{% endtrans %}</th>
|
||||
<th>{% trans %}Comment{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
<th>{% trans %}Last edit{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for alias in domain.aliases %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.alias_edit', alias=alias.email) }}" title="{% trans %}Edit{% endtrans %}"><i class="fa fa-pencil"></i></a>
|
||||
<a href="{{ url_for('.alias_delete', alias=alias.email) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ alias }}</td>
|
||||
<td>{{ alias.destination|join(', ') or '-' }}</td>
|
||||
<td>{{ alias.comment or '' }}</td>
|
||||
<td>{{ alias.created_at }}</td>
|
||||
<td>{{ alias.updated_at or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -9,24 +9,28 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block main_action %}
|
||||
<a class="btn btn-primary" href="{{ url_for('.alternative_create', domain_name=domain.name) }}">{% trans %}Add alternative{% endtrans %}</a>
|
||||
<a class="btn btn-primary float-right" href="{{ url_for('.alternative_create', domain_name=domain.name) }}">{% trans %}Add alternative{% endtrans %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Name{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for alternative in domain.alternatives %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.alternative_delete', alternative=alternative.name) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ alternative }}</td>
|
||||
<td>{{ alternative.created_at }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Name{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for alternative in domain.alternatives %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.alternative_delete', alternative=alternative.name) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ alternative }}</td>
|
||||
<td>{{ alternative.created_at }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -5,7 +5,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.box() %}
|
||||
{% call macros.card() %}
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ macros.form_field(form.announcement_subject) }}
|
||||
|
@ -8,44 +8,58 @@
|
||||
<link rel="stylesheet" href="{{ url_for('.static', filename='app.css') }}">
|
||||
<title>Mailu-Admin - {{ config["SITENAME"] }}</title>
|
||||
</head>
|
||||
<body class="hold-transition skin-blue sidebar-mini">
|
||||
<body class="hold-transition sidebar-mini layout-fixed">
|
||||
<div class="wrapper">
|
||||
<header class="main-header">
|
||||
<div class="logo">
|
||||
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
</a>
|
||||
<a href="{{ config["WEB_ADMIN"] }}">
|
||||
<span class="logo-lg">{{ config["SITENAME"] }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
<aside class="main-sidebar">
|
||||
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link" data-toggle="dropdown" href="#" aria-expanded="false">{{ session['language'] }}</a>
|
||||
<div class="dropdown-menu dropdown-menu-right p-0">
|
||||
{% for language in session['available_languages'] %}
|
||||
<a class="dropdown-item {% if language == session['language'] %}active{% endif %} " href="{{ url_for('.set_language', language=language) }}">{{ language }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<aside class="main-sidebar sidebar-dark-primary">
|
||||
<a href="{{ config["WEB_ADMIN"] }}" class="brand-link">
|
||||
<span class="brand-text font-weight-light">{{ config["SITENAME"] }}</span>
|
||||
</a>
|
||||
{% block sidebar %}
|
||||
{% include "sidebar.html" %}
|
||||
{% endblock %}
|
||||
</aside>
|
||||
<div class="content-wrapper">
|
||||
<section class="content-header">
|
||||
<div class="pull-right">
|
||||
{% block main_action %}
|
||||
{% endblock %}
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1 class="m-0">{% block title %}{% endblock %}</h1>
|
||||
<small>{% block subtitle %}{% endblock %}</small>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
{% block main_action %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h1>
|
||||
{% block title %}{% endblock %}
|
||||
<small>{% block subtitle %}{% endblock %}</small>
|
||||
</h1>
|
||||
</section>
|
||||
|
||||
<section class="content">
|
||||
<div class="content">
|
||||
{{ utils.flashed_messages(container=False) }}
|
||||
{% block content %}{% endblock %}
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="main-footer">
|
||||
Built with <i class="fa fa-heart"></i> using <a class="white-text" href="http://flask.pocoo.org/">Flask</a> and
|
||||
<a class="white-text" href="https://almsaeedstudio.com/preview">AdminLTE</a>
|
||||
<span class="pull-right"><i class="fa fa-code-fork"></i> on <a class="white-text" href="https://github.com/Mailu/Mailu">Github</a></a></span>
|
||||
<a class="white-text" href="https://adminlte.io/themes/v3/index3.html">AdminLTE</a>
|
||||
<span class="pull-right"><i class="fa fa-code-fork"></i>on <a class="white-text" href="https://github.com/Mailu/Mailu">Github</a></a></span>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="{{ url_for('.static', filename='vendor.js') }}"></script>
|
||||
|
@ -1,3 +1,5 @@
|
||||
<!--TODO add translations for: configure your client, Incoming mail and Outgoing mail-->
|
||||
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
@ -9,8 +11,7 @@ configure your email client
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.box(title="Incoming mail") %}
|
||||
<table class="table table-bordered">
|
||||
{% call macros.table(title="Incoming mail", datatable=False) %}
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{% trans %}Mail protocol{% endtrans %}</th>
|
||||
@ -33,11 +34,9 @@ configure your email client
|
||||
<td><pre>*******</pre></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endcall %}
|
||||
|
||||
{% call macros.box(title="Outgoing mail") %}
|
||||
<table class="table table-bordered">
|
||||
{% call macros.table(title="Outgoing mail", datatable=False) %}
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{% trans %}Mail protocol{% endtrans %}</th>
|
||||
@ -60,6 +59,5 @@ configure your email client
|
||||
<td><pre>*******</pre></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -9,7 +9,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.box(theme="warning") %}
|
||||
{% call macros.card(theme="warning") %}
|
||||
<p>{% trans action %}You are about to {{ action }}. Please confirm your action.{% endtrans %}</p>
|
||||
{{ macros.form(form) }}
|
||||
{% endcall %}
|
||||
|
@ -5,13 +5,13 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.box() %}
|
||||
{% call macros.card() %}
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ macros.form_field(form.name) }}
|
||||
{{ macros.form_fields((form.max_users, form.max_aliases)) }}
|
||||
{{ macros.form_field(form.max_quota_bytes, step=1000000000, max=50000000000,
|
||||
prepend='<span class="input-group-addon"><span id="quota">'+((form.max_quota_bytes.data//1000000000).__str__() if form.max_quota_bytes.data else '∞')+'</span> GiB</span>',
|
||||
prepend='<span class="input-group-text"><span id="quota">'+((form.max_quota_bytes.data//1000000000).__str__() if form.max_quota_bytes.data else '∞')+'</span> GiB</span>',
|
||||
oninput='$("#quota").text(this.value == 0 ? "∞" : this.value/1000000000);') }}
|
||||
{{ macros.form_field(form.signup_enabled) }}
|
||||
{{ macros.form_field(form.comment) }}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
{% block main_action %}
|
||||
{% if current_user.global_admin %}
|
||||
<a class="btn btn-primary" href="{{ url_for(".domain_genkeys", domain_name=domain.name) }}">
|
||||
<a class="btn btn-primary float-right" href="{{ url_for(".domain_genkeys", domain_name=domain.name) }}">
|
||||
{% if domain.dkim_publickey %}
|
||||
{% trans %}Regenerate keys{% endtrans %}
|
||||
{% else %}
|
||||
@ -21,7 +21,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
{% call macros.table(datatable=False) %}
|
||||
{% set hostname = config["HOSTNAMES"].split(",")[0] %}
|
||||
<tr>
|
||||
<th>{% trans %}Domain name{% endtrans %}</th>
|
||||
|
@ -6,46 +6,50 @@
|
||||
|
||||
{% block main_action %}
|
||||
{% if current_user.global_admin %}
|
||||
<a class="btn btn-primary" href="{{ url_for('.domain_create') }}">{% trans %}New domain{% endtrans %}</a>
|
||||
<a class="btn btn-primary float-right" href="{{ url_for('.domain_create') }}">{% trans %}New domain{% endtrans %}</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Manage{% endtrans %}</th>
|
||||
<th>{% trans %}Domain name{% endtrans %}</th>
|
||||
<th>{% trans %}Mailbox count{% endtrans %}</th>
|
||||
<th>{% trans %}Alias count{% endtrans %}</th>
|
||||
<th>{% trans %}Comment{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
<th>{% trans %}Last edit{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for domain in current_user.get_managed_domains() %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.domain_details', domain_name=domain.name) }}" title="{% trans %}Details{% endtrans %}"><i class="fa fa-list"></i></a>
|
||||
{% if current_user.global_admin %}
|
||||
<a href="{{ url_for('.domain_edit', domain_name=domain.name) }}" title="{% trans %}Edit{% endtrans %}"><i class="fa fa-pencil"></i></a>
|
||||
<a href="{{ url_for('.domain_delete', domain_name=domain.name) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('.user_list', domain_name=domain.name) }}" title="{% trans %}Users{% endtrans %}"><i class="fa fa-envelope-o"></i></a>
|
||||
<a href="{{ url_for('.alias_list', domain_name=domain.name) }}" title="{% trans %}Aliases{% endtrans %}"><i class="fa fa-at"></i></a>
|
||||
<a href="{{ url_for('.manager_list', domain_name=domain.name) }}" title="{% trans %}Managers{% endtrans %}"><i class="fa fa-user"></i></a>
|
||||
{% if current_user.global_admin %}
|
||||
<a href="{{ url_for('.alternative_list', domain_name=domain.name) }}" title="{% trans %}Alternatives{% endtrans %}"><i class="fa fa-asterisk"></i></a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ domain.name }}</td>
|
||||
<td>{{ domain.users | count }} / {{ '∞' if domain.max_users == -1 else domain.max_users }}</td>
|
||||
<td>{{ domain.aliases | count }} / {{ '∞' if domain.max_aliases == -1 else domain.max_aliases }}</td>
|
||||
<td>{{ domain.comment or '' }}</td>
|
||||
<td>{{ domain.created_at }}</td>
|
||||
<td>{{ domain.updated_at or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Manage{% endtrans %}</th>
|
||||
<th>{% trans %}Domain name{% endtrans %}</th>
|
||||
<th>{% trans %}Mailbox count{% endtrans %}</th>
|
||||
<th>{% trans %}Alias count{% endtrans %}</th>
|
||||
<th>{% trans %}Comment{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
<th>{% trans %}Last edit{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for domain in current_user.get_managed_domains() %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.domain_details', domain_name=domain.name) }}" title="{% trans %}Details{% endtrans %}"><i class="fa fa-list"></i></a>
|
||||
{% if current_user.global_admin %}
|
||||
<a href="{{ url_for('.domain_edit', domain_name=domain.name) }}" title="{% trans %}Edit{% endtrans %}"><i class="fas fa-pencil-alt"></i></a>
|
||||
<a href="{{ url_for('.domain_delete', domain_name=domain.name) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('.user_list', domain_name=domain.name) }}" title="{% trans %}Users{% endtrans %}"><i class="far fa-envelope"></i></a>
|
||||
<a href="{{ url_for('.alias_list', domain_name=domain.name) }}" title="{% trans %}Aliases{% endtrans %}"><i class="fa fa-at"></i></a>
|
||||
<a href="{{ url_for('.manager_list', domain_name=domain.name) }}" title="{% trans %}Managers{% endtrans %}"><i class="fa fa-user"></i></a>
|
||||
{% if current_user.global_admin %}
|
||||
<a href="{{ url_for('.alternative_list', domain_name=domain.name) }}" title="{% trans %}Alternatives{% endtrans %}"><i class="fa fa-asterisk"></i></a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ domain.name }}</td>
|
||||
<td>{{ domain.users | count }} / {{ '∞' if domain.max_users == -1 else domain.max_users }}</td>
|
||||
<td>{{ domain.aliases | count }} / {{ '∞' if domain.max_aliases == -1 else domain.max_aliases }}</td>
|
||||
<td>{{ domain.comment or '' }}</td>
|
||||
<td>{{ domain.created_at }}</td>
|
||||
<td>{{ domain.updated_at or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -9,7 +9,7 @@
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
{% call macros.box(title="Requirements") %}
|
||||
{% call macros.card(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>).
|
||||
@ -22,9 +22,9 @@
|
||||
</p>
|
||||
{% endcall %}
|
||||
|
||||
{% call macros.box() %}
|
||||
{% call macros.card() %}
|
||||
{% if form.localpart %}
|
||||
{{ macros.form_fields((form.localpart, form.name), append='<span class="input-group-addon">@</span>') }}
|
||||
{{ macros.form_fields((form.localpart, form.name), append='<span class="input-group-text">@</span>') }}
|
||||
{{ macros.form_fields((form.pw, form.pw2)) }}
|
||||
{% else %}
|
||||
{{ macros.form_field(form.name) }}
|
||||
|
@ -11,18 +11,18 @@
|
||||
{% block content %}
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{% call macros.box(title="Remote server") %}
|
||||
{% call macros.card(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") %}
|
||||
{% call macros.card(title="Authentication") %}
|
||||
{{ macros.form_field(form.username) }}
|
||||
{{ macros.form_field(form.password) }}
|
||||
{% endcall %}
|
||||
|
||||
{% call macros.box(title="Settings") %}
|
||||
{% call macros.card(title="Settings") %}
|
||||
{{ macros.form_field(form.keep) }}
|
||||
{% endcall %}
|
||||
|
||||
|
@ -9,35 +9,39 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block main_action %}
|
||||
<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 float-right" href="{{ url_for('.fetch_create', user_email=user.email) }}">{% trans %}Add an account{% endtrans %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Endpoint{% endtrans %}</th>
|
||||
<th>{% trans %}Username{% endtrans %}</th>
|
||||
<th>{% trans %}Keep emails{% endtrans %}</th>
|
||||
<th>{% trans %}Last check{% endtrans %}</th>
|
||||
<th>{% trans %}Status{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
<th>{% trans %}Last edit{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for fetch in user.fetches %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.fetch_edit', fetch_id=fetch.id) }}" title="{% trans %}Edit{% endtrans %}"><i class="fa fa-pencil"></i></a>
|
||||
<a href="{{ url_for('.fetch_delete', fetch_id=fetch.id) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ fetch.protocol }}{{ 's' if fetch.tls else '' }}://{{ fetch.host }}:{{ fetch.port }}</td>
|
||||
<td>{{ fetch.username }}</td>
|
||||
<td>{% if fetch.keep %}{% trans %}yes{% endtrans %}{% else %}{% trans %}no{% endtrans %}{% endif %}</td>
|
||||
<td>{{ fetch.last_check or '-' }}</td>
|
||||
<td>{{ fetch.error or '-' }}</td>
|
||||
<td>{{ fetch.created_at }}</td>
|
||||
<td>{{ fetch.updated_at or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Endpoint{% endtrans %}</th>
|
||||
<th>{% trans %}Username{% endtrans %}</th>
|
||||
<th>{% trans %}Keep emails{% endtrans %}</th>
|
||||
<th>{% trans %}Last check{% endtrans %}</th>
|
||||
<th>{% trans %}Status{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
<th>{% trans %}Last edit{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for fetch in user.fetches %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.fetch_edit', fetch_id=fetch.id) }}" title="{% trans %}Edit{% endtrans %}"><i class="fa fa-pencil"></i></a>
|
||||
<a href="{{ url_for('.fetch_delete', fetch_id=fetch.id) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ fetch.protocol }}{{ 's' if fetch.tls else '' }}://{{ fetch.host }}:{{ fetch.port }}</td>
|
||||
<td>{{ fetch.username }}</td>
|
||||
<td>{% if fetch.keep %}{% trans %}yes{% endtrans %}{% else %}{% trans %}no{% endtrans %}{% endif %}</td>
|
||||
<td>{{ fetch.last_check or '-' }}</td>
|
||||
<td>{{ fetch.error or '-' }}</td>
|
||||
<td>{{ fetch.created_at }}</td>
|
||||
<td>{{ fetch.updated_at or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.box() %}
|
||||
{% call macros.card() %}
|
||||
{{ macros.form(form) }}
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -37,9 +37,10 @@
|
||||
{{ field.label if label else '' }}
|
||||
{% else %}
|
||||
{{ field.label if label else '' }}{{ form_field_errors(field) }}
|
||||
{% if prepend or append %}<div class="input-group">{% endif %}
|
||||
{{ prepend|safe }}{{ field(class_="form-control " + class_, **kwargs) }}{{ append|safe }}
|
||||
{% if prepend or append %}</div>{% endif %}
|
||||
{% if prepend %}<div class="input-group-prepend">{% endif %}
|
||||
{% if append %}<div class="input-group-append">{% endif %}
|
||||
{{ prepend|safe }}{{ field(class_="form-control " + class_, **kwargs) }}{{ append|safe }}
|
||||
{% if prepend or append %}</div>{% endif %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@ -64,18 +65,18 @@
|
||||
</form>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro box(title=None, theme="primary", header=True) %}
|
||||
{% macro card(title=None, theme="primary", header=True) %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="box box-{{ theme }}">
|
||||
<div class="card card-outline card-{{ theme }}">
|
||||
{% if header %}
|
||||
<div class="box-header">
|
||||
<div class="card-header border-0">
|
||||
{% if title %}
|
||||
<h3 class="box-title">{{ title }}</h3>
|
||||
<h3 class="card-title">{{ title }}</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
{{ caller() }}
|
||||
</div>
|
||||
</div>
|
||||
@ -83,15 +84,20 @@
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro table(theme="primary") %}
|
||||
{% macro table(title=None, theme="primary", datatable=True) %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="box box-{{ theme }}">
|
||||
<table class="table table-bordered">
|
||||
<tbody>
|
||||
<div class="card card-outline card-{{ theme }}">
|
||||
<div class="card-header border-0">
|
||||
{% if title %}
|
||||
<h3 class="card-title">{{ title }}</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-bordered {% if datatable %} dataTable {% endif %}">
|
||||
{{ caller() }}
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -9,7 +9,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.box() %}
|
||||
{% call macros.card() %}
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ macros.form_field(form.manager, class_='mailselect') }}
|
||||
|
@ -9,15 +9,18 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block main_action %}
|
||||
<a class="btn btn-primary" href="{{ url_for('.manager_create', domain_name=domain.name) }}">{% trans %}Add manager{% endtrans %}</a>
|
||||
<a class="btn btn-primary float-right" href="{{ url_for('.manager_create', domain_name=domain.name) }}">{% trans %}Add manager{% endtrans %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
</tr>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for manager in domain.managers %}
|
||||
<tr>
|
||||
<td>
|
||||
@ -26,5 +29,6 @@
|
||||
<td>{{ manager }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -6,32 +6,36 @@
|
||||
|
||||
{% block main_action %}
|
||||
{% if current_user.global_admin %}
|
||||
<a class="btn btn-primary" href="{{ url_for('.relay_create') }}">{% trans %}New relayed domain{% endtrans %}</a>
|
||||
<a class="btn btn-primary float-right" href="{{ url_for('.relay_create') }}">{% trans %}New relayed domain{% endtrans %}</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Domain name{% endtrans %}</th>
|
||||
<th>{% trans %}Remote host{% endtrans %}</th>
|
||||
<th>{% trans %}Comment{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
<th>{% trans %}Last edit{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for relay in relays %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.relay_edit', relay_name=relay.name) }}" title="{% trans %}Edit{% endtrans %}"><i class="fa fa-pencil"></i></a>
|
||||
<a href="{{ url_for('.relay_delete', relay_name=relay.name) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ relay.name }}</td>
|
||||
<td>{{ relay.smtp or '-' }}</td>
|
||||
<td>{{ relay.comment or '' }}</td>
|
||||
<td>{{ relay.created_at }}</td>
|
||||
<td>{{ relay.updated_at or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Domain name{% endtrans %}</th>
|
||||
<th>{% trans %}Remote host{% endtrans %}</th>
|
||||
<th>{% trans %}Comment{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
<th>{% trans %}Last edit{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for relay in relays %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.relay_edit', relay_name=relay.name) }}" title="{% trans %}Edit{% endtrans %}"><i class="fa fa-pencil"></i></a>
|
||||
<a href="{{ url_for('.relay_delete', relay_name=relay.name) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ relay.name }}</td>
|
||||
<td>{{ relay.smtp or '-' }}</td>
|
||||
<td>{{ relay.comment or '' }}</td>
|
||||
<td>{{ relay.created_at }}</td>
|
||||
<td>{{ relay.updated_at or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -1,120 +1,144 @@
|
||||
<section class="sidebar">
|
||||
<div class="sidebar">
|
||||
{% if current_user.is_authenticated %}
|
||||
<h4 class="text-center text-primary">{{ current_user }}</h4>
|
||||
<div class="user-panel mt-3 pb-3 mb-3 d-flex">
|
||||
<div class="info">
|
||||
<span class="text-center text-primary">{{ current_user }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<ul class="sidebar-menu" data-widget="tree">
|
||||
{% if current_user.is_authenticated %}
|
||||
<li class="header">{% trans %}My account{% endtrans %}</li>
|
||||
<li>
|
||||
<a href="{{ url_for('.user_settings') }}">
|
||||
<i class="fa fa-wrench"></i> <span>{% trans %}Settings{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url_for('.user_password') }}">
|
||||
<i class="fa fa-lock"></i> <span>{% trans %}Update password{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url_for('.user_reply') }}">
|
||||
<i class="fa fa-plane"></i> <span>{% trans %}Auto-reply{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url_for('.fetch_list') }}">
|
||||
<i class="fa fa-download"></i> <span>{% trans %}Fetched accounts{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url_for('.token_list') }}">
|
||||
<i class="fa fa-ticket"></i> <span>{% trans %}Authentication tokens{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<nav class="mt-2">
|
||||
<ul class="nav nav-pills nav-sidebar flex-column" role="menu">
|
||||
{% if current_user.is_authenticated %}
|
||||
<li class="nav-header">{% trans %}My account{% endtrans %}</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.user_settings') }}" class="nav-link">
|
||||
<i class="nav-icon fa fa-wrench"></i>
|
||||
<p class="text">{% trans %}Settings{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.user_password') }}" class="nav-link">
|
||||
<i class="nav-icon fa fa-lock"></i>
|
||||
<p class="text">{% trans %}Update password{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.user_reply') }}" class="nav-link">
|
||||
<i class="nav-icon fa fa-plane"></i>
|
||||
<p class="text">{% trans %}Auto-reply{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.fetch_list') }}" class="nav-link">
|
||||
<i class="nav-icon fas fa-download"></i>
|
||||
<p class="text">{% trans %}Fetched accounts{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.token_list') }}" class="nav-link">
|
||||
<i class="nav-icon fas fa-ticket-alt"></i>
|
||||
<p class="text">{% trans %}Authentication tokens{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{% if current_user.manager_of or current_user.global_admin %}
|
||||
<li class="header">{% trans %}Administration{% endtrans %}</li>
|
||||
{% endif %}
|
||||
{% if current_user.global_admin %}
|
||||
<li>
|
||||
<a href="{{ url_for('.announcement') }}">
|
||||
<i class="fa fa-bullhorn"></i> <span>{% trans %}Announcement{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url_for('.admin_list') }}">
|
||||
<i class="fa fa-user"></i> <span>{% trans %}Administrators{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ url_for('.relay_list') }}">
|
||||
<i class="fa fa-reply-all"></i> <span>{% trans %}Relayed domains{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ config["WEB_ADMIN"] }}/antispam/" target="_blank">
|
||||
<i class="fa fa-trash-o"></i> <span>{% trans %}Antispam{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if current_user.manager_of or current_user.global_admin %}
|
||||
<li>
|
||||
<a href="{{ url_for('.domain_list') }}">
|
||||
<i class="fa fa-envelope"></i> <span>{% trans %}Mail domains{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if current_user.manager_of or current_user.global_admin %}
|
||||
<li class="nav-header">{% trans %}Administration{% endtrans %}</li>
|
||||
{% endif %}
|
||||
{% if current_user.global_admin %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.announcement') }}" class="nav-link">
|
||||
<i class="nav-icon fa fa-bullhorn"></i>
|
||||
<p class="text">{% trans %}Announcement{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.admin_list') }}" class="nav-link">
|
||||
<i class="nav-icon fa fa-user"></i>
|
||||
<p class="text">{% trans %}Administrators{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.relay_list') }}" class="nav-link">
|
||||
<i class="nav-icon fa fa-reply-all"></i>
|
||||
<p class="text">{% trans %}Relayed domains{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ config["WEB_ADMIN"] }}/antispam/" target="_blank" class="nav-link">
|
||||
<i class="nav-icon fas fa-trash-alt"></i>
|
||||
<p class="text">{% trans %}Antispam{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if current_user.manager_of or current_user.global_admin %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.domain_list') }}" class="nav-link">
|
||||
<i class="nav-icon fa fa-envelope"></i>
|
||||
<p class="text">{% trans %}Mail domains{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<li class="header">{% trans %}Go to{% endtrans %}</li>
|
||||
{% if config["WEBMAIL"] != "none" %}
|
||||
<li>
|
||||
<a href="{{ config["WEB_WEBMAIL"] }}" target="_blank">
|
||||
<i class="fa fa-envelope-o"></i> <span>{% trans %}Webmail{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a href="{{ url_for('.client') }}">
|
||||
<i class="fa fa-laptop"></i> <span>{% trans %}Client setup{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ config["WEBSITE"] }}" target="_blank">
|
||||
<i class="fa fa-globe"></i> <span>{% trans %}Website{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://mailu.io" target="_blank">
|
||||
<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') }}">
|
||||
<i class="fa fa-sign-out"></i> <span>{% trans %}Sign out{% endtrans %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li>
|
||||
<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>
|
||||
<li class="nav-header">{% trans %}Go to{% endtrans %}</li>
|
||||
{% if config["WEBMAIL"] != "none" %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ config["WEB_WEBMAIL"] }}" target="_blank" class="nav-link">
|
||||
<i class="nav-icon far fa-envelope"></i>
|
||||
<p class="text">{% trans %}Webmail{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.client') }}" class="nav-link">
|
||||
<i class="nav-icon fa fa-laptop"></i>
|
||||
<p class="text">{% trans %}Client setup{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ config["WEBSITE"] }}" target="_blank" class="nav-link">
|
||||
<i class="nav-icon fa fa-globe"></i>
|
||||
<p class="text">{% trans %}Website{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://mailu.io" target="_blank" class="nav-link">
|
||||
<i class="nav-icon fa fa-life-ring"></i>
|
||||
<p class="text">{% trans %}Help{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
{% if config['DOMAIN_REGISTRATION'] %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.domain_signup') }}" class="nav-link">
|
||||
<i class="nav-icon fa fa-plus-square"></i>
|
||||
<p class="text">{% trans %}Register a domain{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.logout') }}" class="nav-link">
|
||||
<i class="nav-icon fas fa-sign-out-alt"></i>
|
||||
<p class="text">{% trans %}Sign out{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.login') }}" class="nav-link">
|
||||
<i class="nav-icon fas fa-sign-in-alt"></i>
|
||||
<p class="text">{% trans %}Sign in{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
{% if signup_domains %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ url_for('.user_signup') }}" class="nav-link">
|
||||
<i class="nav-icon fa fa-user-plus"></i>
|
||||
<p class="text">{% trans %}Sign up{% endtrans %}</p>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
@ -9,26 +9,30 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block main_action %}
|
||||
<a class="btn btn-primary" href="{{ url_for('.token_create', user_email=user.email) }}">{% trans %}New token{% endtrans %}</a>
|
||||
<a class="btn btn-primary float-right" href="{{ url_for('.token_create', user_email=user.email) }}">{% trans %}New token{% endtrans %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Comment{% endtrans %}</th>
|
||||
<th>{% trans %}Authorized IP{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for token in user.tokens %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.token_delete', token_id=token.id) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ token.comment }}</td>
|
||||
<td>{{ token.ip or "any" }}</td>
|
||||
<td>{{ token.created_at }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}Comment{% endtrans %}</th>
|
||||
<th>{% trans %}Authorized IP{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for token in user.tokens %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('.token_delete', token_id=token.id) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>{{ token.comment }}</td>
|
||||
<td>{{ token.ip or "any" }}</td>
|
||||
<td>{{ token.created_at }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -12,17 +12,17 @@
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
{% call macros.box(_("General")) %}
|
||||
{{ macros.form_field(form.localpart, append='<span class="input-group-addon">@'+domain.name+'</span>') }}
|
||||
{% call macros.card(_("General")) %}
|
||||
{{ macros.form_field(form.localpart, append='<span class="input-group-text">@'+domain.name+'</span>') }}
|
||||
{{ macros.form_fields((form.pw, form.pw2)) }}
|
||||
{{ macros.form_field(form.displayed_name) }}
|
||||
{{ macros.form_field(form.comment) }}
|
||||
{{ macros.form_field(form.enabled) }}
|
||||
{% endcall %}
|
||||
|
||||
{% call macros.box(_("Features and quotas"), theme="success") %}
|
||||
{% call macros.card(_("Features and quotas"), theme="success") %}
|
||||
{{ 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__() if form.quota_bytes.data else '∞')+'</span> GiB</span>',
|
||||
prepend='<span class="input-group-text"><span id="quota">'+((form.quota_bytes.data//1000000000).__str__() if form.quota_bytes.data else '∞')+'</span> GiB</span>',
|
||||
oninput='$("#quota").text(this.value == 0 ? "∞" : this.value/1000000000);') }}
|
||||
{{ macros.form_field(form.enable_imap) }}
|
||||
{{ macros.form_field(form.enable_pop) }}
|
||||
|
@ -9,7 +9,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.box() %}
|
||||
{% call macros.card() %}
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ macros.form_field(form.forward_enabled,
|
||||
|
@ -9,45 +9,46 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block main_action %}
|
||||
<a class="btn btn-primary" href="{{ url_for('.user_create', domain_name=domain.name) }}">{% trans %}Add user{% endtrans %}</a>
|
||||
<a class="btn btn-primary float-right" href="{{ url_for('.user_create', domain_name=domain.name) }}">{% trans %}Add user{% endtrans %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.table() %}
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}User settings{% endtrans %}</th>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
<th>{% trans %}Features{% endtrans %}</th>
|
||||
<th>{% trans %}Storage Quota{% endtrans %}</th>
|
||||
<th>{% trans %}Sending Quota{% endtrans %}</th>
|
||||
<th>{% trans %}Comment{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
<th>{% trans %}Last edit{% endtrans %}</th>
|
||||
</tr>
|
||||
{% for user in domain.users %}
|
||||
<tr {% if not user.enabled %}class="warning"{% endif %}>
|
||||
<td>
|
||||
<a href="{{ url_for('.user_edit', user_email=user.email) }}" title="{% trans %}Edit{% endtrans %}"><i class="fa fa-pencil"></i></a>
|
||||
<a href="{{ url_for('.user_delete', user_email=user.email) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('.user_settings', user_email=user.email) }}" title="{% trans %}Settings{% endtrans %}"><i class="fa fa-wrench"></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>
|
||||
</td>
|
||||
<td>{{ user }}</td>
|
||||
<td>
|
||||
{% if user.enable_imap %}<span class="label label-info">imap</span>{% endif %}
|
||||
{% if user.enable_pop %}<span class="label label-info">pop3</span>{% endif %}
|
||||
</td>
|
||||
<td>{{ user.quota_bytes_used | filesizeformat }} / {{ (user.quota_bytes | filesizeformat) if user.quota_bytes else '∞' }}</td>
|
||||
{% set limiter = user.sender_limiter %}
|
||||
<td>{{ limiter.get_window_stats()[1] }} / {{ limiter.limit }}</td>
|
||||
<td>{{ user.comment or '-' }}</td>
|
||||
<td>{{ user.created_at }}</td>
|
||||
<td>{{ user.updated_at or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}Actions{% endtrans %}</th>
|
||||
<th>{% trans %}User settings{% endtrans %}</th>
|
||||
<th>{% trans %}Email{% endtrans %}</th>
|
||||
<th>{% trans %}Features{% endtrans %}</th>
|
||||
<th>{% trans %}Quota{% endtrans %}</th>
|
||||
<th>{% trans %}Comment{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
<th>{% trans %}Last edit{% endtrans %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in domain.users %}
|
||||
<tr {% if not user.enabled %}class="warning"{% endif %}>
|
||||
<td>
|
||||
<a href="{{ url_for('.user_edit', user_email=user.email) }}" title="{% trans %}Edit{% endtrans %}"><i class="fas fa-pencil-alt"></i></a>
|
||||
<a href="{{ url_for('.user_delete', user_email=user.email) }}" title="{% trans %}Delete{% endtrans %}"><i class="fa fa-trash"></i></a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('.user_settings', user_email=user.email) }}" title="{% trans %}Settings{% endtrans %}"><i class="fa fa-wrench"></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>
|
||||
</td>
|
||||
<td>{{ user }}</td>
|
||||
<td>
|
||||
{% if user.enable_imap %}<span class="badge bg-info">imap</span>{% endif %}
|
||||
{% if user.enable_pop %}<span class="badge bg-info">pop3</span>{% endif %}
|
||||
</td>
|
||||
<td>{{ user.quota_bytes_used | filesizeformat }} / {{ (user.quota_bytes | filesizeformat) if user.quota_bytes else '∞' }}</td>
|
||||
<td>{{ user.comment or '-' }}</td>
|
||||
<td>{{ user.created_at }}</td>
|
||||
<td>{{ user.updated_at or '' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endcall %}
|
||||
{% endblock %}
|
||||
|
@ -9,7 +9,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% call macros.box() %}
|
||||
{% call macros.card() %}
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ macros.form_field(form.reply_enabled,
|
||||
|
@ -12,18 +12,18 @@
|
||||
<form class="form" method="post" role="form">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
{% call macros.box(title=_("Displayed name")) %}
|
||||
{% call macros.card(title=_("Displayed name")) %}
|
||||
{{ macros.form_field(form.displayed_name) }}
|
||||
{% endcall %}
|
||||
|
||||
{% call macros.box(title=_("Antispam")) %}
|
||||
{% call macros.card(title=_("Antispam")) %}
|
||||
{{ macros.form_field(form.spam_enabled) }}
|
||||
{{ 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-text"><span id="threshold">'+form.spam_threshold.data.__str__()+'</span> / 100</span>',
|
||||
oninput='$("#threshold").text(this.value);') }}
|
||||
{% endcall %}
|
||||
|
||||
{% call macros.box(title=_("Auto-forward")) %}
|
||||
{% call macros.card(title=_("Auto-forward")) %}
|
||||
{{ macros.form_field(form.forward_enabled,
|
||||
onchange="if(this.checked){$('#forward_destination,#forward_keep').removeAttr('disabled')}
|
||||
else{$('#forward_destination,#forward_keep').attr('disabled', '')}") }}
|
||||
|
@ -11,8 +11,8 @@
|
||||
{% 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>') }}
|
||||
{% call macros.card() %}
|
||||
{{ macros.form_field(form.localpart, append='<span class="input-group-text">@'+domain.name+'</span>') }}
|
||||
{{ macros.form_fields((form.pw, form.pw2)) }}
|
||||
{% if form.captcha %}
|
||||
{{ macros.form_field(form.captcha) }}
|
||||
|
@ -1,4 +1,4 @@
|
||||
__all__ = [
|
||||
'admins', 'aliases', 'alternatives', 'base', 'domains', 'fetches',
|
||||
'managers', 'users', 'relays', 'tokens'
|
||||
'managers', 'users', 'relays', 'tokens', 'languages'
|
||||
]
|
||||
|
9
core/admin/mailu/ui/views/languages.py
Normal file
9
core/admin/mailu/ui/views/languages.py
Normal file
@ -0,0 +1,9 @@
|
||||
from mailu.ui import ui, forms, access
|
||||
|
||||
import flask
|
||||
|
||||
|
||||
@ui.route('/language/<language>', methods=['GET'])
|
||||
def set_language(language=None):
|
||||
flask.session['language'] = language
|
||||
return flask.redirect(flask.url_for('.user_settings'))
|
@ -46,8 +46,16 @@ babel = flask_babel.Babel()
|
||||
@babel.localeselector
|
||||
def get_locale():
|
||||
""" selects locale for translation """
|
||||
translations = [str(translation) for translation in babel.list_translations()]
|
||||
return flask.request.accept_languages.best_match(translations)
|
||||
translations = list(map(str, babel.list_translations()))
|
||||
flask.session['available_languages'] = translations
|
||||
|
||||
try:
|
||||
language = flask.session['language']
|
||||
except KeyError:
|
||||
language = flask.request.accept_languages.best_match(translations)
|
||||
flask.session['language'] = language
|
||||
|
||||
return language
|
||||
|
||||
|
||||
# Proxy fixer
|
||||
|
@ -12,20 +12,20 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.14.6",
|
||||
"admin-lte": "^2.4.18",
|
||||
"babel-loader": "^8.0.6",
|
||||
"css-loader": "^2.1.1",
|
||||
"expose-loader": "^0.7.5",
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"admin-lte": "^3.1.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"css-loader": "^6.2.0",
|
||||
"expose-loader": "^3.0.0",
|
||||
"jquery": "^3.6.0",
|
||||
"less": "^3.13.1",
|
||||
"less-loader": "^5.0.0",
|
||||
"mini-css-extract-plugin": "^1.2.1",
|
||||
"node-sass": "^4.13.1",
|
||||
"sass-loader": "^7.3.1",
|
||||
"less": "^4.1.1",
|
||||
"less-loader": "^10.0.1",
|
||||
"mini-css-extract-plugin": "^2.2.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"sass-loader": "^12.1.0",
|
||||
"select2": "^4.0.13",
|
||||
"url-loader": "^2.3.0",
|
||||
"webpack": "^4.33.0",
|
||||
"webpack-cli": "^3.3.12"
|
||||
"webpack": "^5.50.0",
|
||||
"webpack-cli": "^4.7.2"
|
||||
}
|
||||
}
|
||||
|
@ -30,19 +30,23 @@ module.exports = {
|
||||
test: /\.css$/,
|
||||
use: [css.loader, 'css-loader']
|
||||
},
|
||||
{
|
||||
test: /\.woff($|\?)|\.woff2($|\?)|\.ttf($|\?)|\.eot($|\?)|\.svg($|\?)/,
|
||||
use: ['url-loader']
|
||||
},
|
||||
{
|
||||
// Exposes jQuery for use outside Webpack build
|
||||
test: require.resolve('jquery'),
|
||||
use: [{
|
||||
loader: 'expose-loader',
|
||||
options: 'jQuery'
|
||||
}, {
|
||||
loader: 'expose-loader',
|
||||
options: '$'
|
||||
options: {
|
||||
exposes: [
|
||||
{
|
||||
globalName: '$',
|
||||
override: true,
|
||||
},
|
||||
{
|
||||
globalName: 'jQuery',
|
||||
override: true,
|
||||
},
|
||||
]
|
||||
},
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
1
towncrier/newsfragments/1567.feature
Normal file
1
towncrier/newsfragments/1567.feature
Normal file
@ -0,0 +1 @@
|
||||
Implement a language selector for the admin interface.
|
1
towncrier/newsfragments/1764.feature
Normal file
1
towncrier/newsfragments/1764.feature
Normal file
@ -0,0 +1 @@
|
||||
Implement AdminLTE 3 for the admin interface.
|
Loading…
Reference in New Issue
Block a user