[web] implemented twig templating system (#4264)

Signed-off-by: Kristian Feldsam <feldsam@gmail.com>
This commit is contained in:
Kristian Feldsam
2021-09-22 20:47:10 +02:00
committed by GitHub
parent 2c5628c0e5
commit 0b64967ec5
406 changed files with 34659 additions and 7423 deletions

View File

@@ -0,0 +1,70 @@
{% extends 'base.twig' %}
{% block content %}
<ul class="nav nav-tabs responsive-tabs" role="tablist">
<li class="dropdown active">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.admin.access }}<span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="active" data-dont-remember="1" role="presentation"><a href="#tab-config-admins" aria-controls="tab-config-admins" role="tab" data-toggle="tab">{{ lang.admin.admins }}</a></li>
<!-- <li role="presentation"><a href="#tab-config-ldap-admins" aria-controls="tab-config-ldap-admins" role="tab" data-toggle="tab">{{ lang.admin.admins_ldap }}</a></li> -->
<li role="presentation"><a href="#tab-config-oauth2" aria-controls="tab-config-oauth2" role="tab" data-toggle="tab">{{ lang.admin.oauth2_apps }}</a></li>
<li role="presentation"><a href="#tab-config-rspamd" aria-controls="tab-config-rspamd" role="tab" data-toggle="tab">Rspamd UI</a></li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.admin.configuration }}<span class="caret"></span></a>
<ul class="dropdown-menu">
<li role="presentation"><a href="#tab-config-dkim" aria-controls="tab-config-dkim" role="tab" data-toggle="tab">{{ lang.admin.dkim_keys }}</a></li>
<li role="presentation"><a href="#tab-config-fwdhosts" aria-controls="tab-config-fwdhosts" role="tab" data-toggle="tab">{{ lang.admin.forwarding_hosts }}</a></li>
<li role="presentation"><a href="#tab-config-f2b" aria-controls="tab-config-f2b" role="tab" data-toggle="tab">{{ lang.admin.f2b_parameters }}</a></li>
<li role="presentation"><a href="#tab-config-quarantine" aria-controls="tab-config-quarantine" role="tab" data-toggle="tab">{{ lang.admin.quarantine }}</a></li>
<li role="presentation"><a href="#tab-config-quota" aria-controls="tab-config-quota" role="tab" data-toggle="tab">{{ lang.admin.quota_notifications }}</a></li>
<li role="presentation"><a href="#tab-config-rsettings" aria-controls="tab-config-rsettings" role="tab" data-toggle="tab">{{ lang.admin.rspamd_settings_map }}</a></li>
<li role="presentation"><a href="#tab-config-password-policy" aria-controls="tab-config-password-policy" role="tab" data-toggle="tab">{{ lang.admin.password_policy }}</a></li>
<li role="presentation"><a href="#tab-config-customize" aria-controls="tab-config-customize" role="tab" data-toggle="tab">{{ lang.admin.customize }}</a></li>
</ul>
</li>
<li role="presentation"><a href="#tab-routing" aria-controls="tab-routing" role="tab" data-toggle="tab">{{ lang.admin.routing }}</a></li>
<li role="presentation"><a href="#tab-sys-mails" aria-controls="tab-sys-mails" role="tab" data-toggle="tab">{{ lang.admin.sys_mails }}</a></li>
<li role="presentation"><a href="#tab-mailq" aria-controls="tab-mailq" role="tab" data-toggle="tab">{{ lang.admin.queue_manager }}</a></li>
<li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.admin.rspamd_global_filters }}
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li role="presentation"><a href="#tab-globalfilter-regex" aria-controls="tab-globalfilter-regex" role="tab" data-toggle="tab">{{ lang.admin.regex_maps }}</a></li>
</ul>
</li>
</ul>
<div class="row">
<div class="col-md-12">
{% include 'admin/tab-config-admins.twig' %}
{% include 'admin/tab-ldap.twig' %}
{% include 'admin/tab-config-oauth2.twig' %}
{% include 'admin/tab-config-rspamd.twig' %}
{% include 'admin/tab-routing.twig' %}
{% include 'admin/tab-config-dkim.twig' %}
{% include 'admin/tab-config-fwdhosts.twig' %}
{% include 'admin/tab-config-f2b.twig' %}
{% include 'admin/tab-config-quarantine.twig' %}
{% include 'admin/tab-config-quota.twig' %}
{% include 'admin/tab-config-rsettings.twig' %}
{% include 'admin/tab-config-customize.twig' %}
{% include 'admin/tab-config-password-policy.twig' %}
{% include 'admin/tab-sys-mails.twig' %}
{% include 'admin/tab-mailq.twig' %}
{% include 'admin/tab-globalfilter-regex.twig' %}
</div> <!-- /col-md-12 -->
</div> <!-- /row -->
{% include 'modals/admin.twig' %}
<script type='text/javascript'>
var lang = {{ lang_admin|raw }};
var admin_username = '{{ mailcow_cc_username }}';
var csrf_token = '{{ csrf_token }}';
var pagination_size = '{{ pagination_size }}';
var log_pagination_size = '{{ log_pagination_size }}';
</script>
{% endblock %}

View File

@@ -0,0 +1,250 @@
<div class="tab-content" style="padding-top:20px">
<div role="tabpanel" class="tab-pane active" id="tab-config-admins">
<div class="panel panel-danger">
<div class="panel-heading xs-show">{{ lang.admin.admin_details }}</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-condensed" id="adminstable"></table>
</div>
<div class="mass-actions-admin">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="admins" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<div class="clearfix visible-xs"></div>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="admins" data-api-url='edit/admin' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="admins" data-api-url='edit/admin' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="admins" data-api-url='edit/admin' data-api-attr='{"disable_tfa":"1"}' href="#">{{ lang.tfa.disable_tfa }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="admins" data-api-url='delete/admin' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-id="add_admin" data-toggle="modal" data-target="#addAdminModal" href="#"><i class="bi bi-person-plus-fill"></i> {{ lang.admin.add_admin }}</a>
</div>
</div>
{# TFA #}
<legend style="margin-top:20px">
{{ lang.tfa.tfa }}
</legend>
<div class="row">
<div class="col-sm-3 col-xs-5 text-right">{{ lang.tfa.tfa }}:</div>
<div class="col-sm-9 col-xs-7">
<p id="tfa_pretty">{{ tfa_data.pretty }}</p>
{% include 'tfa_keys.twig' %}
<br>
</div>
</div>
<div class="row">
<div class="col-sm-3 col-xs-5 text-right">{{ lang.tfa.set_tfa }}:</div>
<div class="col-sm-9 col-xs-7">
<select data-style="btn btn-sm dropdown-toggle bs-placeholder btn-default" data-width="fit" id="selectTFA" class="selectpicker" title="{{ lang.tfa.select }}">
<option value="yubi_otp">{{ lang.tfa.yubi_otp }}</option>
<option value="u2f">{{ lang.tfa.u2f }}</option>
<option value="totp">{{ lang.tfa.totp }}</option>
<option value="none">{{ lang.tfa.none }}</option>
</select>
</div>
</div>
{# FIDO2 #}
<legend style="margin-top:20px">
<i class="bi bi-shield-fill-check"></i>
{{ lang.fido2.fido2_auth }}</legend>
<div class="row">
<div class="col-sm-3 col-xs-12 text-right text-xs-left space20">{{ lang.fido2.known_ids }}:</div>
<div class="col-sm-9 col-xs-12">
<div class="table-responsive">
<table class="table table-striped table-hover table-condensed" id="fido2_keys">
<tr>
<th>ID</th>
<th style="min-width:240px;text-align: right">{{ lang.admin.action }}</th>
</tr>
{% include 'fido2.twig' %}
</table>
</div>
<br>
</div>
</div>
<div class="row">
<div class="col-sm-offset-3 col-sm-9">
<div class="btn-group">
<button class="btn btn-sm btn-xs-lg btn-primary" id="register-fido2">{{ lang.fido2.set_fido2 }}</button>
<button type="button" class="btn btn-sm btn-xs-lg btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" id="register-fido2-touchid" style="line-height:1.4;"><i class="bi bi-shield-fill-check"></i> {{ lang.fido2.set_fido2_touchid }}</a></li>
</ul>
</div>
</div>
</div>
<br>
<div class="row" id="status-fido2">
<div class="col-sm-3 col-xs-5 text-right">{{ lang.fido2.register_status }}:</div>
<div class="col-sm-9 col-xs-7">
<div id="fido2-alerts">-</div>
</div>
<br>
</div>
<legend style="cursor:pointer;margin-top:40px" data-target="#license" unselectable="on" data-toggle="collapse">
<i style="font-size:10pt;" class="bi bi-plus-square"></i> {{ lang.admin.guid_and_license }}
</legend>
<div id="license" class="collapse">
<form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
<div class="form-group">
<label class="control-label col-sm-3" for="guid">{{ lang.admin.guid }}:</label>
<div class="col-sm-9">
<div class="input-group">
<span class="input-group-addon">
<i class="bi bi-suit-heart{% if gal.valid == true %}-fill text-danger{% endif %}"></i>
</span>
<input type="text" id="guid" class="form-control" value="{{ license_guid }}" readonly>
</div>
<p class="help-block">
{{ lang.admin.customer_id }}: {{ gal.c|raw|default('?') }} -
{{ lang.admin.service_id }}: {{ gal.s|raw|default('?') }} -
{{ lang.admin.sal_level }}: {{ gal.m|raw|default('?') }}
</p>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<p class="help-block">{{ lang.admin.license_info|raw }}</p>
<div class="btn-group">
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" name="license_validate_now" type="submit" href="#">{{ lang.admin.validate_license_now }}</button>
</div>
</div>
</div>
</form>
</div>
<legend style="cursor:pointer;" data-target="#admin_api" unselectable="on" data-toggle="collapse">
<i style="font-size:10pt;" class="bi bi-plus-square"></i> API
</legend>
<div id="admin_api" class="collapse">
<div class="row">
<div class="col-lg-12">
<p class="help-block">{{ lang.admin.api_info|raw }}</p>
</div>
<div class="col-lg-6">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"><i class="bi bi-file-earmark-arrow-down"></i> {{ lang.admin.api_read_only }}</h4>
</div>
<div class="panel-body">
<form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
<div class="form-group">
<label class="control-label col-sm-3" for="allow_from_ro">{{ lang.admin.api_allow_from }}:</label>
<div class="col-sm-9">
<textarea class="form-control textarea-code" rows="7" name="allow_from" id="allow_from_ro" {% if api.ro.skip_ip_check %}disabled{% endif %} required>{{ api.ro.allow_from }}</textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<label>
<input type="checkbox" name="skip_ip_check" id="skip_ip_check_ro" {% if api.ro.skip_ip_check %}checked{% endif %}> {{ lang.admin.api_skip_ip_check }}
</label>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3">{{ lang.admin.api_key }}:</label>
<div class="col-sm-9">
<pre>{{ api.ro.api_key|default('-') }}</pre>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<label>
<input type="checkbox" name="active" {% if api.ro.active %}checked{% endif %}> {{ lang.admin.activate_api }}
</label>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" name="admin_api[ro]" type="submit" href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default admin-ays-dialog" name="admin_api_regen_key[ro]" type="submit" href="#" {% if not api.ro.api_key %}disabled{% endif %}>{{ lang.admin.regen_api_key }}</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"><i class="bi bi-file-earmark-diff"></i> {{ lang.admin.api_read_write }}</h4>
</div>
<div class="panel-body">
<form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
<div class="form-group">
<label class="control-label col-sm-3" for="allow_from_rw">{{ lang.admin.api_allow_from }}:</label>
<div class="col-sm-9">
<textarea class="form-control textarea-code" rows="7" name="allow_from" id="allow_from_rw" {% if api.rw.skip_ip_check %}disabled{% endif %} required>{{ api.rw.allow_from }}</textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<label>
<input type="checkbox" name="skip_ip_check" id="skip_ip_check_rw" {% if api.rw.skip_ip_check %}checked{% endif %}> {{ lang.admin.api_skip_ip_check }}
</label>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="admin_api_key">{{ lang.admin.api_key }}:</label>
<div class="col-sm-9">
<pre>{{ api.rw.api_key|default('-') }}</pre>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<label>
<input type="checkbox" name="active" {% if api.rw.active %}checked{% endif %}> {{ lang.admin.activate_api }}
</label>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" name="admin_api[rw]" type="submit" href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default admin-ays-dialog" name="admin_api_regen_key[rw]" type="submit" {% if not api.rw.api_key %}disabled{% endif %} href="#">{{ lang.admin.regen_api_key }}</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading xs-show">{{ lang.admin.domain_admins }}</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-condensed" id="domainadminstable"></table>
</div>
<div class="mass-actions-admin">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="domain_admins" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="domain_admins" data-api-url='edit/domain-admin' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="domain_admins" data-api-url='edit/domain-admin' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="domain_admins" data-api-url='edit/domain-admin' data-api-attr='{"disable_tfa":"1"}' href="#">{{ lang.tfa.disable_tfa }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="domain_admins" data-api-url='delete/domain-admin' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-id="add_domain_admin" data-toggle="modal" data-target="#addDomainAdminModal" href="#"><i class="bi bi-person-plus-fill"></i> {{ lang.admin.add_domain_admin }}</a>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,108 @@
<div role="tabpanel" class="tab-pane" id="tab-config-customize">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.customize }}</div>
<div class="panel-body">
<legend><i class="bi bi-file-image"></i> {{ lang.admin.change_logo }}</legend>
<p class="help-block">{{ lang.admin.logo_info }}</p>
<form class="form-inline" role="form" method="post" enctype="multipart/form-data">
<p>
<input type="file" name="main_logo" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml"><br>
<button name="submit_main_logo" type="submit" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default"><i class="bi bi-upload"></i> {{ lang.admin.upload }}</button>
</p>
</form>
{% if logo %}
<div class="row">
<div class="col-sm-3">
<div class="thumbnail">
<img class="img-thumbnail" src="{{ logo }}" alt="mailcow logo">
<div class="caption">
<span class="label label-info">{{ logo_specs.geometry.width }}x{{ logo_specs.geometry.height }} px</span>
<span class="label label-info">{{ logo_specs.mimetype }}</span>
<span class="label label-info">{{ logo_specs.fileSize }}</span>
</div>
</div>
<hr>
<form class="form-inline" role="form" method="post">
<p><button name="reset_main_logo" type="submit" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default">{{ lang.admin.reset_default }}</button></p>
</form>
</div>
</div>
{% endif %}
<legend>{{ lang.admin.app_links }}</legend>
<p class="help-block">{{ lang.admin.merged_vars_hint }}</p>
<form class="form-inline" data-id="app_links" role="form" method="post">
<table class="table table-condensed" style="white-space: nowrap;" id="app_link_table">
<tr>
<th>{{ lang.admin.app_name }}</th>
<th>{{ lang.admin.link }}</th>
<th>&nbsp;</th>
</tr>
{% for row in app_links %}
{% for key, val in row %}
<tr>
<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required value="{{ key }}"></td>
<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required value="{{ val }}"></td>
<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-default" type="button">{{ lang.admin.remove_row }}</a></td>
</tr>
{% endfor %}
{% endfor %}
{% for app in mailcow_apps %}
<tr>
<td><input class="input-sm input-xs-lg form-control" value="{{ app.name }}" disabled></td>
<td><input class="input-sm input-xs-lg form-control" value="{{ app.link }}" disabled></td>
<td>&nbsp;</td>
</tr>
{% endfor %}
</table>
<p><div class="btn-group">
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-item="admin" data-id="app_links" data-reload="no" data-api-url='edit/app_links' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" type="button" id="add_app_link_row">{{ lang.admin.add_row }}</button>
<div class="clearfix visible-xs"></div>
</div></p>
</form>
<legend data-target="#ui_texts" style="padding-top:20px" unselectable="on">{{ lang.admin.ui_texts }}</legend>
<div id="ui_texts">
<form class="form" data-id="uitexts" role="form" method="post">
<div class="form-group">
<label for="uitests_title_name">{{ lang.admin.title_name }}:</label>
<input type="text" class="form-control" id="uitests_title_name" name="title_name" placeholder="mailcow UI" value="{{ ui_texts.title_name }}">
</div>
<div class="form-group">
<label for="uitests_main_name">{{ lang.admin.main_name }}:</label>
<input type="text" class="form-control" id="uitests_main_name" name="main_name" placeholder="mailcow UI" value="{{ ui_texts.main_name }}">
</div>
<div class="form-group">
<label for="uitests_apps_name">{{ lang.admin.apps_name }}:</label>
<input type="text" class="form-control" id="uitests_apps_name" name="apps_name" placeholder="{{ lang.header.apps }}" value="{{ ui_texts.apps_name }}">
</div>
<div class="form-group">
<label for="help_text">{{ lang.admin.help_text }}:</label>
<textarea class="form-control" id="help_text" name="help_text" rows="7">{{ ui_texts.help_text }}</textarea>
</div>
<hr>
<div class="form-group">
<p class="help-block">{{ lang.admin.ui_header_announcement_help }}</p>
<label for="ui_announcement_type">{{ lang.admin.ui_header_announcement }}:</label>
<p><select multiple data-width="100%" id="ui_announcement_type" name="ui_announcement_type" class="selectpicker show-tick" data-max-options="1" title="{{ lang.admin.ui_header_announcement_select }}">
<option {% if ui_texts.ui_announcement_type == 'info' %}selected{% endif %} value="info">{{ lang.admin.ui_header_announcement_type_info }}</option>
<option {% if ui_texts.ui_announcement_type == 'warning' %}selected{% endif %} value="warning">{{ lang.admin.ui_header_announcement_type_warning }}</option>
<option {% if ui_texts.ui_announcement_type == 'danger' %}selected{% endif %} value="danger">{{ lang.admin.ui_header_announcement_type_danger }}</option>
</select></p>
<p><textarea class="form-control" id="ui_announcement_text" name="ui_announcement_text" rows="7">{{ ui_texts.ui_announcement_text }}</textarea></p>
<div class="checkbox">
<label>
<input type="checkbox" name="ui_announcement_active" class="form-check-input" {% if ui_texts.ui_announcement_active == 1 %}checked{% endif %}> {{ lang.admin.ui_header_announcement_active }}
</label>
</div>
</div>
<hr>
<div class="form-group">
<label for="ui_footer">{{ lang.admin.ui_footer }}:</label>
<textarea class="form-control" id="ui_footer" name="ui_footer" rows="7">{{ ui_texts.ui_footer }}</textarea>
</div>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-item="ui" data-id="uitexts" data-api-url='edit/ui_texts' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,178 @@
<div role="tabpanel" class="tab-pane" id="tab-config-dkim">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.dkim_keys }}</div>
<div class="panel-body">
<div class="btn-group" data-toggle="button" style="margin-bottom: 20px;">
<a class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default active" href="#" data-toggle="collapse" data-target=".dkim_key_valid">{{ lang.admin.dkim_key_valid }}</a>
<a class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default active" href="#" data-toggle="collapse" data-target=".dkim_key_unused">{{ lang.admin.dkim_key_unused }}</a>
<a class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default active" href="#" data-toggle="collapse" data-target=".dkim_key_missing">{{ lang.admin.dkim_key_missing }}</a>
<div class="clearfix visible-xs"></div>
</div>
{% for domain, domain_data in dkim_domains %}
{% if domain_data.dkim %}
<div class="row collapse in dkim_key_valid">
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="{{ domain }}"></div>
<div class="col-md-3">
<p>{{ lang.admin.domain }}: <strong>{{ domain }}</strong>
<p class="dkim-label"><span class="label label-success">{{ lang.admin.dkim_key_valid }}</span></p>
<p class="dkim-label"><span class="label label-primary">{{ lang.admin.dkim_domains_selector }} '{{ domain_data.dkim.dkim_selector }}'</span></p>
<p class="dkim-label"><span class="label label-info">{{ domain_data.dkim.length }} bit</span></p>
</p>
</div>
<div class="col-md-8">
<pre>{{ domain_data.dkim.dkim_txt }}</pre>
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="{{ domain_data.dkim.privkey }}"><small><i class="bi bi-arrow-return-right"></i> {{ lang.admin.dkim_private_key }}</small></p>
</div>
<hr class="visible-xs visible-sm">
</div>
{% else %}
<div class="row collapse in dkim_key_missing">
<div class="col-md-1"><input class="dkim_missing" type="checkbox" data-id="dkim" name="multi_select" value="{{ domain }}" disabled></div>
<div class="col-md-3">
<p>{{ lang.admin.domain }}: <strong>{{ domain }}</strong><br><span class="label label-danger">{{ lang.admin.dkim_key_missing }}</span></p>
</div>
<div class="col-md-8"><pre>-</pre></div>
<hr class="visible-xs visible-sm">
</div>
{% endif %}
{% for alias_domain, alias_domain_data in domain_data.alias_domains %}
{% if alias_domain_data.dkim %}
<div class="row collapse in dkim_key_valid">
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="{{ alias_domain }}"></div>
<div class="col-md-2 col-md-offset-1">
<p><small>↳ Alias-Domain: <strong>{{ alias_domain }}</strong></small>
<p class="dkim-label"><span class="label label-success">{{ lang.admin.dkim_key_valid }}</span></p>
<p class="dkim-label"><span class="label label-primary">Selector '{{ alias_domain_data.dkim.dkim_selector }}'</span></p>
<p class="dkim-label"><span class="label label-info">{{ alias_domain_data.dkim.length }} bit</span></p>
</p>
</div>
<div class="col-md-8">
<pre>{{ alias_domain_data.dkim.dkim_txt }}</pre>
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="{{ alias_domain_data.dkim.privkey }}"><small><i class="bi bi-arrow-return-right"></i> Private key</small></p>
</div>
<hr class="visible-xs visible-sm">
</div>
{% else %}
<div class="row collapse in dkim_key_missing">
<div class="col-md-1"><input class="dkim_missing" type="checkbox" data-id="dkim" name="multi_select" value="{{ alias_domain }}" disabled></div>
<div class="col-md-2 col-md-offset-1">
<p><small>↳ Alias-Domain: <strong>{{ alias_domain }}</strong><br></small><span class="label label-danger">{{ lang.admin.dkim_key_missing }}</span></p>
</div>
<div class="col-md-8"><pre>-</pre></div>
<hr class="visible-xs visible-sm">
</div>
{% endif %}
{% endfor %}
{% endfor %}
{% for blind, data in dkim_blind_domains|filter(data => data.dkim is not null) %}
<div class="row collapse in dkim_key_unused">
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="{{ blind }}"></div>
<div class="col-md-3">
<p>{{ lang.admin.domain }}: <strong>{{ blind }}</strong>
<p class="dkim-label"><span class="label label-warning">{{ lang.admin.dkim_key_unused }}</span></p>
<p class="dkim-label"><span class="label label-primary">Selector '{{ data.dkim.dkim_selector }}'</span></p>
<p class="dkim-label"><span class="label label-info">{{ data.dkim.length }} bit</span></p>
</p>
</div>
<div class="col-md-8">
<pre>{{ data.dkim.dkim_txt }}</pre>
<p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="{{ data.dkim.privkey }}"><small><i class="bi bi-arrow-return-right"></i> Private key</small></p>
</div>
<hr class="visible-xs visible-sm">
</div>
{% endfor %}
<div class="mass-actions-admin">
<div class="btn-group btn-group-sm">
<button type="button" id="toggle_multi_select_all" data-id="dkim" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</button>
<button type="button" data-action="delete_selected" name="delete_selected" data-id="dkim" data-api-url="delete/dkim" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger"><i class="bi bi-trash"></i> {{ lang.admin.remove }}</button>
<div class="clearfix visible-xs"></div>
</div>
</div>
<legend style="margin-top:40px">{{ lang.admin.dkim_add_key }}</legend>
<form class="form" data-id="dkim" role="form" method="post">
<div class="form-group">
<label for="dkim_add_domains">{{ lang.admin.domain_s }}</label>
<input class="form-control input-sm" id="dkim_add_domains" name="domains" placeholder="example.org, example.com" required>
<small><i class="bi bi-arrow-return-right"></i> <a href="#" id="dkim_missing_keys">{{ lang.admin.dkim_domains_wo_keys }}</a></small>
</div>
<div class="form-group">
<label for="dkim_selector">{{ lang.admin.dkim_domains_selector }}</label>
<input class="form-control input-sm" id="dkim_selector" name="dkim_selector" value="dkim" required>
</div>
<div class="form-group">
<select data-style="btn btn-default btn-sm" class="form-control" id="key_size" name="key_size" title="{{ lang.admin.dkim_key_length }}" required>
<option data-subtext="bits">1024</option>
<option data-subtext="bits">2048</option>
</select>
</div>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="dkim" data-api-url='add/dkim' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.add }}</button>
</form>
<legend data-target="#import_dkim" style="margin-top:40px;cursor:pointer" unselectable="on" data-toggle="collapse">
<i style="font-size:10pt;" class="bi bi-plus-square"></i> {{ lang.admin.import_private_key }}
</legend>
<div id="import_dkim" class="collapse">
<form class="form" data-id="dkim_import" role="form" method="post">
<div class="form-group">
<label for="dkim_import_domain">{{ lang.admin.domain }}:</label>
<input class="form-control input-sm" id="dkim_import_domain" name="domain" placeholder="example.org" required>
</div>
<div class="form-group">
<label for="dkim_import_selector">{{ lang.admin.dkim_domains_selector }}:</label>
<input class="form-control input-sm" id="dkim_import_selector" name="dkim_selector" value="dkim" required>
</div>
<div class="form-group">
<label for="private_key_file">{{ lang.admin.private_key }}: (RSA PKCS#8)</label>
<textarea class="form-control input-sm" rows="10" name="private_key_file" id="private_key_file" required placeholder="-----BEGIN RSA KEY-----"></textarea>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="overwrite_existing" value="1"> {{ lang.admin.dkim_overwrite_key }}
</label>
</div>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="dkim_import" data-api-url='add/dkim_import' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.import }}</button>
</form>
</div>
<legend data-target="#duplicate_dkim" style="margin-top:40px;cursor:pointer" unselectable="on" data-toggle="collapse">
<i style="font-size:10pt;" class="bi bi-plus-square"></i> {{ lang.admin.duplicate_dkim }}
</legend>
<div id="duplicate_dkim" class="collapse">
<form class="form-horizontal" data-id="dkim_duplicate" role="form" method="post">
<div class="form-group">
<label class="control-label col-sm-2" for="from_domain">{{ lang.admin.dkim_from }}:</label>
<div class="col-sm-10">
<select data-style="btn btn-default btn-sm"
data-live-search="true"
data-id="dkim_duplicate"
title="{{ lang.admin.dkim_from_title }}"
name="from_domain" id="from_domain" class="full-width-select form-control" required>
{% for dkim_domain in dkim_domains_with_keys %}
<option value="{{ dkim_domain }}">{{ dkim_domain }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="to_domain">{{ lang.admin.dkim_to }}:</label>
<div class="col-sm-10">
<select
data-live-search="true"
data-style="btn btn-default btn-sm"
data-id="dkim_duplicate"
title="{{ lang.admin.dkim_to_title }}"
name="to_domain" id="to_domain" class="full-width-select form-control" multiple required>
{% for domain in all_domains %}
<option value="{{ domain }}">{{ domain }}</option>
{% endfor %}
</select>
</div>
</div>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="dkim_duplicate" data-api-url='add/dkim_duplicate' data-api-attr='{}' href="#"><i class="bi bi-clipboard-plus"></i> {{ lang.admin.duplicate }}</button>
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,109 @@
<div role="tabpanel" class="tab-pane" id="tab-config-f2b">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.f2b_parameters }}</div>
<div class="panel-body">
<form class="form" data-id="f2b" role="form" method="post">
<div class="form-group">
<label for="f2b_ban_time">{{ lang.admin.f2b_ban_time }}:</label>
<input type="number" class="form-control" id="f2b_ban_time" name="ban_time" value="{{ f2b_data.ban_time }}" required>
</div>
<div class="form-group">
<label for="f2b_max_attempts">{{ lang.admin.f2b_max_attempts }}:</label>
<input type="number" class="form-control" id="f2b_max_attempts" name="max_attempts" value="{{ f2b_data.max_attempts }}" required>
</div>
<div class="form-group">
<label for="f2b_retry_window">{{ lang.admin.f2b_retry_window }}:</label>
<input type="number" class="form-control" id="f2b_retry_window" name="retry_window" value="{{ f2b_data.retry_window }}" required>
</div>
<div class="form-group">
<label for="f2b_netban_ipv4">{{ lang.admin.f2b_netban_ipv4 }}:</label>
<div class="input-group">
<span class="input-group-addon">/</span>
<input type="number" class="form-control" id="f2b_netban_ipv4" name="netban_ipv4" value="{{ f2b_data.netban_ipv4 }}" required>
</div>
</div>
<div class="form-group">
<label for="f2b_netban_ipv6">{{ lang.admin.f2b_netban_ipv6 }}:</label>
<div class="input-group">
<span class="input-group-addon">/</span>
<input type="number" class="form-control" id="f2b_netban_ipv6" name="netban_ipv6" value="{{ f2b_data.netban_ipv6 }}" required>
</div>
</div>
<hr>
<p class="help-block">{{ lang.admin.f2b_list_info|raw }}</p>
<div class="form-group">
<label for="f2b_whitelist">{{ lang.admin.f2b_whitelist }}:</label>
<textarea class="form-control" id="f2b_whitelist" name="whitelist" rows="5">{{ f2b_data.whitelist }}</textarea>
</div>
<div class="form-group">
<label for="f2b_blacklist">{{ lang.admin.f2b_blacklist }}:</label>
<textarea class="form-control" id="f2b_blacklist" name="blacklist" rows="5">{{ f2b_data.blacklist }}</textarea>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-item="self" data-id="f2b" data-api-url='edit/fail2ban' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<a href="#" role="button" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-toggle="modal" data-container="netfilter-mailcow" data-target="#RestartContainer"><i class="bi bi-arrow-repeat"></i> {{ lang.header.restart_netfilter }}</a>
<div class="clearfix visible-xs"></div>
</div>
</form>
<legend data-target="#f2b_regex_filters" style="margin-top:40px;cursor:pointer" unselectable="on" data-toggle="collapse">
<i style="font-size:10pt;" class="bi bi-plus-square"></i> {{ lang.admin.f2b_filter }}
</legend>
<div id="f2b_regex_filters" class="collapse">
<p class="help-block">{{ lang.admin.f2b_regex_info }}</p>
<form class="form-inline" data-id="f2b_regex" role="form" method="post">
<table class="table table-condensed" id="f2b_regex_table">
<tr>
<th width="50px">ID</th>
<th>RegExp</th>
<th width="100px">&nbsp;</th>
</tr>
{% for regex_id, regex_val in f2b_data.regex %}
<tr>
<td><input disabled class="input-sm input-xs-lg form-control" style="text-align:center" data-id="f2b_regex" type="text" name="app" required value="{{ regex_id }}"></td>
<td><input class="input-sm input-xs-lg form-control regex-input" data-id="f2b_regex" type="text" name="regex" required value="{{ regex_val }}"></td>
<td><a href="#" role="button" class="btn btn-xs btn-xs-lg btn-default" type="button">{{ lang.admin.remove_row }}</a></td>
</tr>
{% endfor %}
</table>
<p><div class="btn-group">
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-item="admin" data-id="f2b_regex" data-reload="no" data-api-url='edit/fail2ban' data-api-attr='{"action":"edit-regex"}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default admin-ays-dialog" data-action="edit_selected" data-item="self" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"reset-regex"}' href="#">{{ lang.admin.reset_default }}</button>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" type="button" id="add_f2b_regex_row"><i class="bi bi-plus-lg"></i> {{ lang.admin.add_row }}</button>
</div></p>
</form>
</div>
<p class="help-block">{{ lang.admin.ban_list_info|raw }}</p>
{% if not f2b_data.active_bans and not f2b_data.perm_bans %}
<i>{{ lang.admin.no_active_bans }}</i>
{% endif %}
{% for active_ban in f2b_data.active_bans %}
<p>
<span class="label label-info" style="padding:4px;font-size:85%;">
<i class="bi bi-funnel-fill"></i>
<a href="https://bgp.he.net/ip/{{ active_ban.ip }}" target="_blank" style="color:white">
{{ active_ban.network }}
</a>
({{ active_ban.banned_until }}) -
{% if active_ban.queued_for_unban == 0 %}
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"unban"}' href="#">[{{ lang.admin.queue_unban }}]</a>
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"whitelist"}' href="#">[whitelist]</a>
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"blacklist"}' href="#">[blacklist (<b>needs restart</b>)]</a>
{% else %}
<i>{{ lang.admin.unban_pending }}</i>
{% endif %}
</span>
</p>
{% endfor %}
<hr>
{% for perm_ban in f2b_data.perm_bans %}
<span class="label label-danger" style="padding: 0.1em 0.4em 0.1em;">
<i class="bi bi-funnel-fill"></i>
<a href="https://bgp.he.net/ip/{{ perm_ban.ip }}" target="_blank" style="color:white">
{{ perm_ban.network }}
</a>
</span>
{% endfor %}
</div>
</div>
</div>

View File

@@ -0,0 +1,39 @@
<div role="tabpanel" class="tab-pane" id="tab-config-fwdhosts">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.forwarding_hosts }}</div>
<div class="panel-body">
<p style="margin-bottom:40px">{{ lang.admin.forwarding_hosts_hint }}</p>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="forwardinghoststable"></table>
</div>
<div class="mass-actions-admin">
<div class="btn-group btn-group-sm">
<button type="button" id="toggle_multi_select_all" data-id="fwdhosts" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default">{{ lang.mailbox.toggle_all }}</button>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu top100">
<li><a data-action="edit_selected" data-id="fwdhosts" data-api-url='edit/fwdhost' data-api-attr='{"keep_spam":"0"}' href="#">Enable spam filter</a></li>
<li><a data-action="edit_selected" data-id="fwdhosts" data-api-url='edit/fwdhost' data-api-attr='{"keep_spam":"1"}' href="#">Disable spam filter</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="fwdhosts" data-api-url='delete/fwdhost' href="#">{{ lang.admin.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
</div>
</div>
<legend>{{ lang.admin.add_forwarding_host }}</legend>
<p class="help-block">{{ lang.admin.forwarding_hosts_add_hint }}</p>
<form class="form" data-id="fwdhost" role="form" method="post">
<div class="form-group">
<label for="fwdhost_hostname">{{ lang.admin.host }}</label>
<input class="form-control" id="fwdhost_hostname" name="hostname" placeholder="example.org" required>
</div>
<div class="form-group">
<select data-width="200px" class="form-control" id="filter_spam" name="filter_spam" title="{{ lang.user.spamfilter }}" required>
<option value="1">{{ lang.admin.active }}</option>
<option value="0">{{ lang.admin.inactive }}</option>
</select>
</div>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="fwdhost" data-api-url='add/fwdhost' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.add }}</button>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,26 @@
<div role="tabpanel" class="tab-pane" id="tab-config-oauth2">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.oauth2_apps }}</div>
<div class="panel-body">
<p>{{ lang.admin.oauth2_info|raw }}</p>
<div class="table-responsive">
<table class="table table-striped" id="oauth2clientstable"></table>
</div>
<div class="mass-actions-admin">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="oauth2_clients" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="delete_selected" data-id="oauth2_clients" data-api-url='delete/oauth2-client' href="#">{{ lang.mailbox.remove }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="oauth2_clients" data-api-url='edit/oauth2-client' data-api-attr='{"revoke_tokens":"1"}' href="#">{{ lang.admin.oauth2_revoke_tokens }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="oauth2_clients" data-api-url='edit/oauth2-client' data-api-attr='{"renew_secret":"1"}' href="#">{{ lang.admin.oauth2_renew_secret }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-id="add_oauth2_client" data-toggle="modal" data-target="#addOAuth2ClientModal" href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.oauth2_add_client }}</a>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,35 @@
<div role="tabpanel" class="tab-pane" id="tab-config-password-policy">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.password_policy }}</div>
<div class="panel-body">
<form class="form-horizontal" data-id="passwordpolicy" role="form" method="post">
{% for name, value in password_complexity %}
{% if name == 'length' %}
<div class="form-group">
<label class="control-label col-sm-3" for="length">{{ lang.admin.password_length }}:</label>
<div class="col-sm-2">
<input type="number" class="form-control" min="3" max="64" name="length" id="length" value="{{ value }}" required>
</div>
</div>
{% else %}
<input type="hidden" name="{{ name }}" value="0">
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<label>
<input type="checkbox" name="{{ name }}" id="{{ name }}" value="1" {% if value == 1 %}checked{% endif %}> {{ lang.admin['password_policy_'~name] }}
</label>
</div>
</div>
{% endif %}
{% endfor %}
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<div class="btn-group">
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-item="passwordpolicy" data-action="edit_selected" data-id="passwordpolicy" data-api-url='edit/passwordpolicy' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,90 @@
<div role="tabpanel" class="tab-pane" id="tab-config-quarantine">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.quarantine }}</div>
<div class="panel-body">
{% if not q_data.retention_size or not q_data.max_size %}
<div class="alert alert-info">{{ lang.quarantine.disabled_by_config }}</div>
{% endif %}
<form class="form-horizontal" data-id="quarantine" role="form" method="post">
<div class="form-group">
<label class="col-sm-4 control-label" for="quarantine_retention_size">{{ lang.admin.quarantine_retention_size|raw }}</label>
<div class="col-sm-8">
<input type="number" class="form-control" id="quarantine_retention_size" name="retention_size" value="{{ q_data.retention_size }}" placeholder="0" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label" for="quarantine_max_size">{{ lang.admin.quarantine_max_size|raw }}</label>
<div class="col-sm-8">
<input type="number" class="form-control" id="quarantine_max_size" name="max_size" value="{{ q_data.max_size }}" placeholder="0" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label" for="quarantine_max_score">{{ lang.admin.quarantine_max_score|raw }}</label>
<div class="col-sm-8">
<input type="number" class="form-control" id="quarantine_max_score" name="max_score" value="{{ q_data.max_score }}" placeholder="9999.0">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label" for="quarantine_max_age">{{ lang.admin.quarantine_max_age|raw }}</label>
<div class="col-sm-8">
<input type="number" class="form-control" id="quarantine_max_age" name="max_age" value="{{ q_data.max_age }}" min="1" required>
</div>
</div>
<hr>
<div class="form-group">
<label class="col-sm-4 control-label" for="quarantine_redirect"><i class="bi bi-box-arrow-right"></i> {{ lang.admin.quarantine_redirect|raw }}</label>
<div class="col-sm-8">
<input type="email" class="form-control" id="quarantine_redirect" name="redirect" value="{{ q_data.redirect }}" placeholder="">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label" for="quarantine_bcc"><i class="bi bi-files"></i> {{ lang.admin.quarantine_bcc|raw }}</label>
<div class="col-sm-8">
<input type="email" class="form-control" id="quarantine_bcc" name="bcc" value="{{ q_data.bcc }}" placeholder="">
</div>
</div>
<hr>
<div class="form-group">
<label class="col-sm-4 control-label" for="quarantine_sender">{{ lang.admin.quarantine_notification_sender }}:</label>
<div class="col-sm-8">
<input type="email" class="form-control" id="quarantine_sender" name="sender" value="{{ q_data.sender }}" placeholder="quarantine@localhost">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label" for="quarantine_subject">{{ lang.admin.quarantine_notification_subject }}:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="quarantine_subject" name="subject" value="{{ q_data.subject }}" placeholder="Spam Quarantine Notification">
</div>
</div>
<hr>
<div class="form-group">
<label class="col-sm-4 control-label" for="quarantine_release_format">{{ lang.admin.quarantine_release_format }}:</label>
<div class="col-sm-8">
<select data-width="100%" id="quarantine_release_format" name="release_format" class="selectpicker" title="{{ lang.tfa.select }}">
<option {% if q_data.release_format == 'raw' %}selected{% endif %} value="raw">{{ lang.admin.quarantine_release_format_raw }}</option>
<option {% if q_data.release_format == 'attachment' %}selected{% endif %} value="attachment">{{ lang.admin.quarantine_release_format_att }}</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label" for="exclude_domains">{{ lang.admin.quarantine_exclude_domains }}:</label>
<div class="col-sm-8">
<select data-width="100%" name="exclude_domains" class="selectpicker" title="{{ lang.tfa.select }}" multiple>
{% for domain in all_domains %}
<option {% if domain in q_data.exclude_domains|keys %}selected{% endif %}>{{ domain }}</option>
{% endfor %}
</select>
</div>
</div>
<hr>
<legend data-target="#quarantine_template" style="cursor:pointer" unselectable="on" data-toggle="collapse">
<i style="font-size:10pt;" class="bi bi-plus-square"></i> {{ lang.admin.quarantine_notification_html|raw }}
</legend>
<div id="quarantine_template" class="collapse" >
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code" rows="40" name="html_tmpl">{{ q_data.html_tmpl|raw }}</textarea>
</div>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-item="self" data-id="quarantine" data-api-url='edit/quarantine' data-api-attr='{"action":"settings"}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,47 @@
<div role="tabpanel" class="tab-pane" id="tab-config-quota">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.quota_notifications }}</div>
<div class="panel-body">
<p>{{ lang.admin.quota_notifications_info }}</p>
<form class="form" role="form" data-id="quota_notification" method="post">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="quota_notification_sender">{{ lang.admin.quota_notification_sender }}:</label>
<input type="email" class="form-control" id="quota_notification_sender" name="sender" value="{{ qn_data.sender }}" placeholder="quota-warning@localhost">
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="quota_notification_subject">{{ lang.admin.quota_notification_subject }}:</label>
<input type="text" class="form-control" id="quota_notification_subject" name="subject" value="{{ qn_data.subject }}" placeholder="Quota warning">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<legend data-target="#quota_template" style="cursor:pointer" unselectable="on" data-toggle="collapse">
<i style="font-size:10pt;" class="bi bi-plus-square"></i> {{ lang.admin.quarantine_notification_html|raw }}
</legend>
<div id="quota_template" class="collapse">
<!-- <small>{{ lang.admin.quota_notifications_vars }}</small><br><br>-->
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code collapse in" rows="20" name="html_tmpl">{{ qn_data.html_tmpl|raw }}</textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-10">
<div class="form-group">
<br>
<a type="button" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected"
data-item="quota_notification"
data-id="quota_notification"
data-api-url='edit/quota_notification'
data-api-attr='{}'><i class="bi bi-check-lg"></i> {{ lang.user.save_changes }}</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,71 @@
<div role="tabpanel" class="tab-pane" id="tab-config-rsettings">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.rspamd_settings_map }}</div>
<div class="panel-body">
<legend data-target="#active_settings_map" style="cursor:pointer" unselectable="on" data-toggle="collapse">
<i style="font-size:10pt;" class="bi bi-plus-square"></i> {{ lang.admin.active_rspamd_settings_map }}
</legend>
<div id="active_settings_map" class="collapse" >
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code" rows="20" name="settings_map" readonly>{{ rsettings_map }}</textarea>
</div>
<br>
<form class="form" data-id="rsettings" role="form" method="post">
<div class="row">
<div class="col-sm-3">
<div class="list-group">
{% if not rsettings %}
{% endif %}
{% for rsetting in rsettings %}
<a href="#{{ rsetting.details.id }}" class="list-group-item list-group-item-{% if rsetting.details.active %}success{% endif %}" data-dont-remember="1" data-toggle="tab">{{ rsetting.details.desc }} (ID #{{ rsetting.id }})</a>
{% else %}
<span class="list-group-item"><em>{{ lang.admin.rsetting_none }}</em></span>
{% endfor %}
<a href="#" class="list-group-item list-group-item-default"
data-id="add_domain_admin"
data-toggle="modal"
data-dont-remember="1"
data-target="#addRsettingModal"
data-toggle="tab">{{ lang.admin.rsetting_add_rule }}</a>
</div>
</div>
<div class="col-sm-9">
<div class="tab-content">
{% if not rsettings %}
<div id="none" class="tab-pane active">
<p class="help-block">{{ lang.admin.rsetting_none }}</p>
</div>
{% else %}
<div id="none" class="tab-pane active">
<p class="help-block">{{ lang.admin.rsetting_no_selection }}</p>
</div>
{% for rsetting in rsettings %}
<div id="{{ rsetting.details.id }}" class="tab-pane">
<form class="form" data-id="rsettings" role="form" method="post">
<input type="hidden" name="active" value="0">
<div class="form-group">
<label for="rsettings_desc">{{ lang.admin.rsetting_desc }}:</label>
<input type="text" class="form-control" id="rsettings_desc" name="desc" value="{{ rsetting.details.desc }}">
</div>
<div class="form-group">
<label for="rsettings_content">{{ lang.admin.rsetting_content }}:</label>
<textarea class="form-control" id="rsettings_content" name="content" rows="10">{{ rsetting.details.content }}</textarea>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="active" value="1" {% if rsetting.details.active %}checked{% endif %}> {{ lang.admin.active }}
</label>
</div>
<button class="btn btn-sm btn-success" data-action="edit_selected" data-item="{{ rsetting.details.id }}" data-id="rsettings" data-api-url='edit/rsetting' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<button class="btn btn-sm btn-danger" data-action="delete_selected" data-item="{{ rsetting.details.id }}" data-id="rsettings" data-api-url="delete/rsetting" data-api-attr='{}' href="#">{{ lang.admin.remove }}</button>
</form>
</div>
{% endfor %}
{% endif %}
</div>
</div>
</div>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,45 @@
<div role="tabpanel" class="tab-pane" id="tab-config-rspamd">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Rspamd UI</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-xs-12 visible-xs">
<img class="img-responsive" src="/img/rspamd_logo.png" alt="Rspamd UI">
</div>
<div class="col-sm-9 col-xs-12">
<form class="form-horizontal" autocapitalize="none" data-id="admin" autocorrect="off" role="form" method="post">
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<label>
<a href="/rspamd/" target="_blank"><i class="bi bi-window"></i> Rspamd UI</a>
</label>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="rspamd_ui_pass">{{ lang.admin.password }}:</label>
<div class="col-sm-9">
<input type="password" class="form-control" id="rspamd_ui_pass" name="rspamd_ui_pass" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="rspamd_ui_pass2">{{ lang.admin.password_repeat }}:</label>
<div class="col-sm-9">
<input type="password" class="form-control" id="rspamd_ui_pass2" name="rspamd_ui_pass2" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" id="rspamd_ui" name="rspamd_ui" href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
</div>
</div>
</form>
</div>
<div class="col-sm-3 hidden-xs">
<img class="img-responsive" src="/img/rspamd_logo.png" alt="Rspamd UI">
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,48 @@
<div role="tabpanel" class="tab-pane" id="tab-globalfilter-regex">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.admin.rspamd_global_filters }}
</div>
<div class="panel-body">
<p>{{ lang.admin.rspamd_global_filters_info }}</p>
<div id="confirm_show_rspamd_global_filters"{% if show_rspamd_global_filters %} class="hidden"{% endif %}>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<label>
<input type="checkbox" id="show_rspamd_global_filters"> {{ lang.admin.rspamd_global_filters_agree }}
</label>
</div>
</div>
</div>
<div id="rspamd_global_filters"{% if show_rspamd_global_filters != true %} class="hidden"{% endif %}>
<hr>
<span class="anchor" id="regexmaps"></span>
<h4>{{ lang.admin.regex_maps }}</h4>
<p>{{ lang.admin.rspamd_global_filters_regex|raw }}</p>
<ul>
{% for rspamd_regex_desc, rspamd_regex_map in rspamd_regex_maps %}
<li><a href="#{{ rspamd_regex_map.map }}">{{ rspamd_regex_desc }}</a> (<small>{{ rspamd_regex_map.map }}</small>)</li>
{% endfor %}
</ul>
{% for rspamd_regex_desc, rspamd_regex_map in rspamd_regex_maps %}
<hr>
<span class="anchor" id="{{ rspamd_regex_map.map }}"></span>
<form class="form-horizontal" data-cached-form="false" data-id="{{ rspamd_regex_map.map }}" role="form" method="post">
<div class="form-group">
<label class="control-label col-sm-3" for="{{ rspamd_regex_map.map }}">{{ rspamd_regex_desc }}<br><small>{{ rspamd_regex_map.map }}</small></label>
<div class="col-sm-9">
<textarea id="{{ rspamd_regex_map.map }}" spellcheck="false" autocorrect="off" autocapitalize="none" class="form-control textarea-code" rows="10" name="rspamd_map_data" required>{{ rspamd_regex_map.data }}</textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default validate_rspamd_regex" data-regex-map="{{ rspamd_regex_map.map }}" href="#">{{ lang.add.validate }}</button>
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success submit_rspamd_regex" data-action="edit_selected" data-id="{{ rspamd_regex_map.map }}" data-item="{{ rspamd_regex_map.map }}" data-api-url='edit/rspamd-map' data-api-attr='{}' href="#" disabled>{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% endfor %}
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,7 @@
<div role="tabpanel" class="tab-pane" id="tab-config-ldap-admins">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.admins_ldap }}</div>
<div class="panel-body">
</div>
</div>
</div>

View File

@@ -0,0 +1,44 @@
<div role="tabpanel" class="tab-pane" id="tab-mailq">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.admin.queue_manager }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_queue" data-table="queuetable">{{ lang.admin.refresh }}</button>
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-condensed" id="queuetable"></table>
</div>
<div class="mass-actions-admin">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="mailqitems" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu top33">
<li><a data-toggle="tooltip" title="postqueue -i" data-action="edit_selected" data-id="mailqitems" data-api-url='edit/mailq' data-api-attr='{"action":"deliver"}' href="#">{{ lang.admin.queue_deliver_mail }}</a></li>
<li><a data-toggle="tooltip" title="postsuper -H" data-action="edit_selected" data-id="mailqitems" data-api-url='edit/mailq' data-api-attr='{"action":"unhold"}' href="#">{{ lang.admin.queue_unhold_mail }}</a></li>
<li><a data-toggle="tooltip" title="postsuper -h" data-action="edit_selected" data-id="mailqitems" data-api-url='edit/mailq' data-api-attr='{"action":"hold"}' href="#">{{ lang.admin.queue_hold_mail }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-toggle="tooltip" title="postsuper -d" data-action="delete_selected" data-id="mailqitems" data-api-url='delete/mailq' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-primary"
data-action="edit_selected"
data-item="mailqitems-all"
data-api-url='edit/mailq'
data-api-attr='{"action":"flush"}'
data-toggle="tooltip" title="postqueue -f"
href="#"><i class="bi bi-check-all"></i> {{ lang.admin.flush_queue }}</a>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger"
id="super_delete"
data-action="edit_selected"
data-item="mailqitems-all"
data-api-url='edit/mailq'
data-api-attr='{"action":"super_delete"}'
data-toggle="tooltip" title="postsuper -d ALL"
href="#"><i class="bi bi-trash"></i> {{ lang.admin.delete_queue }}</a>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,104 @@
<div role="tabpanel" class="tab-pane" id="tab-routing">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.relayhosts }}</div>
<div class="panel-body">
<p style="margin-bottom:40px">{{ lang.admin.relayhosts_hint|raw }}</p>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="relayhoststable"></table>
</div>
<div class="mass-actions-admin">
<div class="btn-group btn-group-sm">
<button type="button" id="toggle_multi_select_all" data-id="rlyhosts" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default">{{ lang.mailbox.toggle_all }}</button>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu top100">
<li><a data-action="edit_selected" data-id="rlyhosts" data-api-url='edit/relayhost' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="rlyhosts" data-api-url='edit/relayhost' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="rlyhosts" data-api-url='delete/relayhost' href="#">{{ lang.admin.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
</div>
</div>
<legend>{{ lang.admin.add_relayhost }}</legend>
<p class="help-block">{{ lang.admin.add_relayhost_hint }}</p>
<div class="row">
<div class="col-md-8">
<form class="form" data-id="rlyhost" role="form" method="post">
<div class="form-group">
<label for="rlyhost_hostname">{{ lang.admin.host }}</label>
<input class="form-control" id="rlyhost_hostname" name="hostname" placeholder='[0.0.0.0], [0.0.0.0]:25, host:25, host, [host]:25' required>
</div>
<div class="form-group">
<label for="rlyhost_username">{{ lang.admin.username }}</label>
<input class="form-control" id="rlyhost_username" name="username">
</div>
<div class="form-group">
<label for="rlyhost_password">{{ lang.admin.password }}</label>
<input class="form-control" id="rlyhost_password" name="password">
</div>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="rlyhost" data-api-url='add/relayhost' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.add }}</button>
</form>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.transport_maps }}</div>
<div class="panel-body">
<p style="margin-bottom:40px">{{ lang.admin.transports_hint|raw }}</p>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="transportstable"></table>
</div>
<div class="mass-actions-admin">
<div class="btn-group btn-group-sm">
<button type="button" id="toggle_multi_select_all" data-id="transports" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default">{{ lang.mailbox.toggle_all }}</button>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu top100">
<li><a data-action="edit_selected" data-id="transports" data-api-url='edit/transport' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="transports" data-api-url='edit/transport' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="transports" data-api-url='delete/transport' href="#">{{ lang.admin.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
</div>
</div>
<legend>{{ lang.admin.add_transport }}</legend>
<p class="help-block">{{ lang.admin.add_transports_hint }}</p>
<div class="row">
<div class="col-md-8">
<form class="form" data-id="transport" role="form" method="post">
<div class="form-group">
<label for="transport_destination">{{ lang.admin.destination }}</label>
<input class="form-control" id="transport_destination" name="destination" placeholder='{{ lang.admin.transport_dest_format }}' required>
</div>
<div class="form-group">
<label for="transport_nexthop">{{ lang.admin.nexthop }}</label>
<input class="form-control" id="transport_nexthop" name="nexthop" placeholder='host:25, host, [host]:25, [0.0.0.0]:25' required>
</div>
<div class="form-group">
<label for="transport_username">{{ lang.admin.username }}</label>
<input class="form-control" id="transport_username" name="username">
</div>
<div class="form-group">
<label for="transport_password">{{ lang.admin.password }}</label>
<input class="form-control" id="transport_password" name="password">
</div>
<div class="form-group">
<label>
<input type="checkbox" name="is_mx_based" value="1"> {{ lang.admin.lookup_mx|raw }}
</label>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="active" value="1"> {{ lang.admin.active }}
</label>
</div>
<p class="help-block">{{ lang.admin.credentials_transport_warning|raw }}</p>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="transport" data-api-url='add/transport' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.add }}</button>
</form>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,70 @@
<div role="tabpanel" class="tab-pane" id="tab-sys-mails">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.admin.sys_mails }}</div>
<div class="panel-body">
<form class="form-horizontal" autocapitalize="none" data-id="admin" autocorrect="off" role="form" method="post">
<div class="form-group">
<label class="control-label col-sm-2" for="admin_mass_from">{{ lang.admin.from }}:</label>
<div class="col-sm-10">
<input type="email" class="form-control" id="admin_mass_from" name="mass_from" value="noreply@{{ mailcow_hostname }}" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="admin_mass_subject">{{ lang.admin.subject }}:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="admin_mass_subject" name="mass_subject" required>
</div>
</div>
{% for domain in all_domains %}
{% endfor %}
<div class="form-group">
<label class="control-label col-sm-2" for="mass_subject">{{ lang.admin.include_exclude }}:
<p class="help-block">{{ lang.admin.include_exclude_info|raw }}</p>
</label>
<div class="col-sm-5">
<label class="control-label" for="mass_exclude">{{ lang.admin.excludes }}:</label>
<select id="mass_exclude" name="mass_exclude[]" data-live-search="true" data-width="100%" size="30" multiple>
{% for mailbox in mailboxes %}
<option>{{ mailbox }}</option>
{% endfor %}
</select>
</div>
<div class="col-sm-5">
<label class="control-label" for="mass_include">{{ lang.admin.includes }}:</label>
<select id="mass_include" name="mass_include[]" data-live-search="true" data-width="100%" size="30" multiple>
{% for mailbox in mailboxes %}
<option>{{ mailbox }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mass_text">{{ lang.admin.text }}:</label>
<div class="col-sm-10">
<textarea class="form-control" rows="10" name="mass_text" id="mass_text" required></textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mass_html">{{ lang.admin.html }} ({{ lang.admin.optional }}):</label>
<div class="col-sm-10">
<textarea class="form-control" rows="10" name="mass_html" id="mass_html"></textarea>
<p class="small"><i class="bi bi-arrow-return-right"></i> <a target="_blank" href="https://templates.mailchimp.com/resources/html-to-text/">{{ lang.admin.convert_html_to_text }}</a></p>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<label>
<input type="checkbox" id="mass_disarm"> {{ lang.admin.activate_send }}
</label>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" type="submit" id="mass_send" name="mass_send" disabled><i class="bi bi-envelope-fill"></i> {{ lang.admin.send }}</button>
</div>
</div>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,397 @@
<!DOCTYPE html>
<html lang="{{ mailcow_locale|default('en') }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
<meta name="theme-color" content="#F5D76E"/>
<meta http-equiv="Referrer-Policy" content="same-origin">
<title>{{ ui_texts.title_name }}</title>
<link rel="stylesheet" href="{{ css_path }}">
{% if theme != 'lumen' %}
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.7/{{ theme }}/bootstrap.min.css">
{% endif %}
<link rel="shortcut icon" href="/favicon.png" type="image/png">
<link rel="icon" href="/favicon.png" type="image/png">
</head>
<body id="top">
<div class="overlay"></div>
{% block navbar %}
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/"><img alt="mailcow-logo" src="{{ logo|default('/img/cow_mailcow.svg') }}"></a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
{% if mailcow_locale %}
<li class="dropdown{% if available_languages|length == 1 %}lang-link-disabled{% endif %}">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="flag-icon flag-icon-{{ mailcow_locale }}"></span><span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{% for key, val in available_languages %}
<li{% if mailcow_locale == key %} class="active"{% endif %}>
<a href="?{{ query_string({'lang': key}) }}">
<span class="flag-icon flag-icon-{{ key }}"></span>{{ val }}
</a>
</li>
{% endfor %}
</ul>
</li>
{% endif %}
{% if mailcow_cc_role %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ lang.header.mailcow_settings }} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{% if mailcow_cc_role == 'admin' %}
<li {% if is_uri('admin') %}class="active"{% endif %}><a href="/admin">{{ lang.header.administration }}</a></li>
<li {% if is_uri('debug') %}class="active"{% endif %}><a href="/debug">{{ lang.header.debug }}</a></li>
{% endif %}
{% if mailcow_cc_role == 'admin' or mailcow_cc_role == 'domainadmin' %}
<li {% if is_uri('mailbox') %}class="active"{% endif %}><a href="/mailbox">{{ lang.header.mailboxes }}</a></li>
{% endif %}
{% if mailcow_cc_role != 'admin' %}
<li {% if is_uri('user') %}class="active"{% endif %}><a href="/user">{{ lang.header.user_settings }}</a></li>
{% endif %}
</ul>
</li>
<li {% if is_uri('quarantine') %}class="active"{% endif %}><a href="/quarantine"><i class="bi bi-inbox-fill"></i> {{ lang.header.quarantine }}</a></li>
{% endif %}
{% if mailcow_cc_role == 'admin' and not skip_sogo %}
<li><a href data-toggle="modal" data-container="sogo-mailcow" data-target="#RestartContainer"><i class="bi bi-arrow-repeat"></i> {{ lang.header.restart_sogo }}</a></li>
{% endif %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="bi bi-link-45deg"></i> {{ ui_texts.apps_name }} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
{% for app in mailcow_apps %}
{% if not skip_sogo or not is_uri('SOGo', app.link) %}
<li {% if app.description %}title="{{ app.description }}"{% endif %}>
<a href="{{ app.link }}">{{ app.name }}</a>
</li>
{% endif %}
{% endfor %}
{% for row in app_links %}
{% for key, val in row %}
<li><a href="{{ val }}">{{ key }}</a></li>
{% endfor %}
{% endfor %}
</ul>
</li>
{% if not dual_login and mailcow_cc_username %}
<li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia">{{ mailcow_cc_username }}</b> <i class="bi bi-power"></i></a></li>
{% elseif dual_login %}
<li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia">{{ mailcow_cc_username }} <span class="text-info">({{ dual_login.username }})</span> </b><i class="bi bi-power"></i></a></li>
{% endif %}
{% if not is_master %}
<li class="text-warning slave-info">[ slave ]</li>
{% endif %}
</ul>
</div><!--/.nav-collapse -->
</div><!--/.container-fluid -->
</nav>
{% endblock navbar %}
<form action="/" method="post" id="logout"><input type="hidden" name="logout"></form>
{% if ui_texts.ui_announcement_text and ui_texts.ui_announcement_active and not is_root_uri %}
<div class="container">
<div class="alert alert-{{ ui_texts.ui_announcement_type }}">{{ ui_texts.ui_announcement_text|rot13 }}</div>
</div>
{% endif %}
<div class="container">
{% block content %}{% endblock %}
</div>
{% include 'modals/footer.twig' %}
<script src="{{ js_path }}"></script>
<script>
var lang_footer = {{ lang_footer|raw }};
var lang_acl = {{ lang_acl|raw }};
var lang_tfa = {{ lang_tfa|raw }};
var lang_fido2 = {{ lang_fido2|raw }};
var docker_timeout = {{ docker_timeout|raw }} * 1000;
$(window).scroll(function() {
sessionStorage.scrollTop = $(this).scrollTop();
});
// Select language and reopen active URL without POST
function setLang(sel) {
$.post( '{{ uri }}', {lang: sel} );
window.location.href = window.location.pathname + window.location.search;
}
// FIDO2 functions
function arrayBufferToBase64(buffer) {
let binary = '';
let bytes = new Uint8Array(buffer);
let len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa(binary);
}
function recursiveBase64StrToArrayBuffer(obj) {
let prefix = '=?BINARY?B?';
let suffix = '?=';
if (typeof obj === 'object') {
for (let key in obj) {
if (typeof obj[key] === 'string') {
let str = obj[key];
if (str.substring(0, prefix.length) === prefix && str.substring(str.length - suffix.length) === suffix) {
str = str.substring(prefix.length, str.length - suffix.length);
let binary_string = window.atob(str);
let len = binary_string.length;
let bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
obj[key] = bytes.buffer;
}
} else {
recursiveBase64StrToArrayBuffer(obj[key]);
}
}
}
}
$(window).load(function() {
$(".overlay").hide();
});
$(document).ready(function() {
$(document).on('shown.bs.modal', function(e) {
modal_id = $(e.relatedTarget).data('target');
$(modal_id).attr("aria-hidden","false");
});
// TFA, CSRF, Alerts in footer.inc.php
// Other general functions in mailcow.js
{% for alert_type, alert_msg in aletrs %}
mailcow_alert_box(alert_msg, alert_type);
{% endfor %}
// Confirm TFA modal
{% if pending_tfa_method %}
$('#ConfirmTFAModal').modal({
backdrop: 'static',
keyboard: false
});
$('#u2f_status_auth').html('<p><i class="bi bi-arrow-repeat icon-spin"></i> ' + lang_tfa.init_u2f + '</p>');
$('#ConfirmTFAModal').on('shown.bs.modal', function(){
$(this).find('input[name=token]').focus();
// If U2F
if(document.getElementById("u2f_auth_data") !== null) {
$.ajax({
type: "GET",
cache: false,
dataType: 'script',
url: "/api/v1/get/u2f-authentication/{{ pending_mailcow_cc_username|url_encode(true)|default('null') }}",
complete: function(data){
$('#u2f_status_auth').html(lang_tfa.waiting_usb_auth);
data;
setTimeout(function() {
console.log("Ready to authenticate");
u2f.sign(appId, challenge, registeredKeys, function(data) {
var form = document.getElementById('u2f_auth_form');
var auth = document.getElementById('u2f_auth_data');
console.log("Authenticate callback", data);
auth.value = JSON.stringify(data);
form.submit();
});
}, 1000);
}
});
}
});
$('#ConfirmTFAModal').on('hidden.bs.modal', function(){
$.ajax({
type: "GET",
cache: false,
dataType: 'script',
url: '/inc/ajax/destroy_tfa_auth.php',
complete: function(data){
window.location = window.location.href.split("#")[0];
}
});
});
{% endif %}
// Validate FIDO2
$("#fido2-login").click(function(){
$('#fido2-alerts').html();
if (!window.fetch || !navigator.credentials || !navigator.credentials.create) {
window.alert('Browser not supported.');
return;
}
window.fetch("/api/v1/get/fido2-get-args", {method:'GET',cache:'no-cache'}).then(function(response) {
return response.json();
}).then(function(json) {
if (json.success === false) {
throw new Error();
}
recursiveBase64StrToArrayBuffer(json);
return json;
}).then(function(getCredentialArgs) {
return navigator.credentials.get(getCredentialArgs);
}).then(function(cred) {
return {
id: cred.rawId ? arrayBufferToBase64(cred.rawId) : null,
clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
authenticatorData: cred.response.authenticatorData ? arrayBufferToBase64(cred.response.authenticatorData) : null,
signature : cred.response.signature ? arrayBufferToBase64(cred.response.signature) : null
};
}).then(JSON.stringify).then(function(AuthenticatorAttestationResponse) {
return window.fetch("/api/v1/process/fido2-args", {method:'POST', body: AuthenticatorAttestationResponse, cache:'no-cache'});
}).then(function(response) {
return response.json();
}).then(function(json) {
if (json.success) {
window.location = window.location.href.split("#")[0];
} else {
throw new Error();
}
}).catch(function(err) {
if (typeof err.message === 'undefined') {
mailcow_alert_box(lang_fido2.fido2_validation_failed, "danger");
} else {
mailcow_alert_box(lang_fido2.fido2_validation_failed + ":<br><i>" + err.message + "</i>", "danger");
}
});
});
// Set TFA/FIDO2
$("#register-fido2, #register-fido2-touchid").click(function(){
let t = $(this);
$("option:selected").prop("selected", false);
if (!window.fetch || !navigator.credentials || !navigator.credentials.create) {
window.alert('Browser not supported.');
return;
}
window.fetch("/api/v1/get/fido2-registration/{{ mailcow_cc_username|url_encode(true)|default('null') }}", {method:'GET',cache:'no-cache'}).then(function(response) {
return response.json();
}).then(function(json) {
if (json.success === false) {
throw new Error(json.msg);
}
recursiveBase64StrToArrayBuffer(json);
// set attestation to node if we are registering apple touch id
if(t.attr('id') === 'register-fido2-touchid') {
json.publicKey.attestation = 'none';
json.publicKey.authenticatorSelection.authenticatorAttachment = "platform";
}
return json;
}).then(function(createCredentialArgs) {
console.log(createCredentialArgs);
return navigator.credentials.create(createCredentialArgs);
}).then(function(cred) {
return {
clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
attestationObject: cred.response.attestationObject ? arrayBufferToBase64(cred.response.attestationObject) : null
};
}).then(JSON.stringify).then(function(AuthenticatorAttestationResponse) {
return window.fetch("/api/v1/add/fido2-registration", {method:'POST', body: AuthenticatorAttestationResponse, cache:'no-cache'});
}).then(function(response) {
return response.json();
}).then(function(json) {
if (json.success) {
window.location = window.location.href.split("#")[0];
} else {
throw new Error(json.msg);
}
}).catch(function(err) {
$('#fido2-alerts').html('<span class="text-danger"><b>' + err.message + '</b></span>');
});
});
$('#selectTFA').change(function () {
if ($(this).val() == "yubi_otp") {
$('#YubiOTPModal').modal('show');
$("option:selected").prop("selected", false);
}
if ($(this).val() == "totp") {
$('#TOTPModal').modal('show');
request_token = $('#tfa-qr-img').data('totp-secret');
$.ajax({
url: '/inc/ajax/qr_gen.php',
data: {
token: request_token,
},
}).done(function (result) {
$("#tfa-qr-img").attr("src", result);
});
$("option:selected").prop("selected", false);
}
if ($(this).val() == "u2f") {
$('#U2FModal').modal('show');
$("option:selected").prop("selected", false);
$("#start_u2f_register").click(function(){
$('#u2f_return_code').html('');
$('#u2f_return_code').hide();
$('#u2f_status_reg').html('<p><i class="bi bi-arrow-repeat icon-spin"></i> ' + lang_tfa.init_u2f + '</p>');
$.ajax({
type: "GET",
cache: false,
dataType: 'script',
url: "/api/v1/get/u2f-registration/{{ mailcow_cc_username|url_encode(true)|default('null') }}",
complete: function(data){
data;
setTimeout(function() {
console.log("Ready to register");
$('#u2f_status_reg').html(lang_tfa.waiting_usb_register);
u2f.register(appId, registerRequests, registeredKeys, function(deviceResponse) {
var form = document.getElementById('u2f_reg_form');
var reg = document.getElementById('u2f_register_data');
console.log("Register callback: ", data);
if (deviceResponse.errorCode && deviceResponse.errorCode != 0) {
var u2f_return_code = document.getElementById('u2f_return_code');
u2f_return_code.style.display = u2f_return_code.style.display === 'none' ? '' : null;
if (deviceResponse.errorCode == "4") {
deviceResponse.errorCode = "4 - The presented device is not eligible for this request. For a registration request this may mean that the token is already registered, and for a sign request it may mean that the token does not know the presented key handle";
}
else if (deviceResponse.errorCode == "5") {
deviceResponse.errorCode = "5 - Timeout reached before request could be satisfied.";
}
u2f_return_code.innerHTML = lang_tfa.error_code + ': ' + deviceResponse.errorCode + ' ' + lang_tfa.reload_retry;
return;
}
reg.value = JSON.stringify(deviceResponse);
form.submit();
});
}, 1000);
}
});
});
}
if ($(this).val() == "none") {
$('#DisableTFAModal').modal('show');
$("option:selected").prop("selected", false);
}
});
{% if mailcow_cc_username %}
// Reload after session timeout
var session_lifetime = {{ (session_lifetime * 1000) + 15000 }};
setTimeout(function() {
location.reload();
}, session_lifetime);
{% endif %}
// CSRF
$('<input type="hidden" value="{{ csrf_token }}">').attr('name', 'csrf_token').appendTo('form');
if (sessionStorage.scrollTop != "undefined") {
$(window).scrollTop(sessionStorage.scrollTop);
}
});
</script>
<div class="container footer">
{% if ui_texts.ui_footer %}
<hr><span class="rot-enc">{{ ui_texts.ui_footer|rot13|raw }}</span>
{% endif %}
</div>
</body>
</html>

0
data/web/templates/cache/.gitkeep vendored Normal file
View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,84 @@
{% extends 'base.twig' %}
{% block content %}
<h3>{{ lang.user.user_settings }}</h3>
<div class="panel panel-default">
<div class="panel-heading">{{ lang.user.user_settings }}</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-offset-3 col-sm-9">
<p><a href="#pwChangeModal" data-toggle="modal">[{{ lang.user.change_password }}]</a></p>
<div class="last-login"></div>
<span class="clear-last-logins">{{ lang.user.clear_recent_successful_connections }}</span>
</div>
</div>
<hr>
{# TFA #}
<div class="row">
<div class="col-sm-3 col-xs-5 text-right">{{ lang.tfa.tfa }}</div>
<div class="col-sm-9 col-xs-7">
<p id="tfa_pretty">{{ tfa_data.pretty }}</p>
{% include 'tfa_keys.twig' %}
<br>
</div>
</div>
<div class="row">
<div class="col-sm-3 col-xs-5 text-right">{{ lang.tfa.set_tfa }}</div>
<div class="col-sm-9 col-xs-7">
<select id="selectTFA" class="selectpicker" title="{{ lang.tfa.select }}">
<option value="yubi_otp">{{ lang.tfa.yubi_otp }}</option>
<option value="u2f">{{ lang.tfa.u2f }}</option>
<option value="totp">{{ lang.tfa.totp }}</option>
<option value="none">{{ lang.tfa.none }}</option>
</select>
</div>
</div>
<hr>
{# FIDO2 #}
<div class="row">
<div class="col-sm-3 col-xs-5 text-right">
<p><i class="bi bi-shield-fill-check"></i> {{ lang.fido2.fido2_auth }}</p>
</div>
</div>
<div class="row">
<div class="col-sm-3 col-xs-5 text-right">{{ lang.fido2.known_ids }}:</div>
<div class="col-sm-9 col-xs-7">
<div class="table-responsive">
<table class="table table-striped table-hover table-condensed" id="fido2_keys">
<tr>
<th>ID</th>
<th style="min-width:240px;text-align: right">{{ lang.admin.action }}</th>
</tr>
{% include 'fido2.twig' %}
</table>
</div>
<br>
</div>
</div>
<div class="row">
<div class="col-sm-offset-3 col-sm-9">
<div class="btn-group">
<button class="btn btn-sm btn-primary" id="register-fido2">{{ lang.fido2.set_fido2 }}</button>
<button type="button" class="btn btn-sm btn-xs-lg btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" id="register-fido2-touchid" style="line-height:1.4;"><i class="bi bi-shield-fill-check"></i> {{ lang.fido2.set_fido2_touchid }}</a></li>
</ul>
</div>
</div>
</div>
<br>
<div class="row" id="status-fido2">
<div class="col-sm-3 col-xs-5 text-right">{{ lang.fido2.register_status }}:</div>
<div class="col-sm-9 col-xs-7">
<div id="fido2-alerts">-</div>
</div>
<br>
</div>
</div>
</div>
{% include 'user_domainadmin_common.twig' %}
{% endblock %}

View File

@@ -0,0 +1,30 @@
{% extends 'base.twig' %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{ lang.edit.title }}</h3>
</div>
<div class="panel-body">
{% block inner_content %}
{% if access_denied %}
<div class="alert alert-danger" role="alert">{{ lang.danger.access_denied }}</div>
{% else %}
<div class="alert alert-info" role="alert">{{ lang.info.no_action }}</div>
{% endif %}
{% endblock %}
</div>
</div>
</div>
</div>
<a href="{{ return_to }}">&#8592; {{ lang.edit.previous }}</a>
<script type='text/javascript'>
var lang_user = {{ lang_user|raw }};
var csrf_token = '{{ csrf_token }}';
var pagination_size = '{{ pagination_size }}';
var table_for_domain = '{{ domain }}';
</script>
{% endblock %}

View File

@@ -0,0 +1,51 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.admin }}</h4>
<br>
<form class="form-horizontal" data-id="editadmin" role="form" method="post" autocomplete="off">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="username_new">{{ lang.edit.username }}</label>
<div class="col-sm-10">
<input class="form-control" type="text" name="username_new" onkeyup="this.value = this.value.toLowerCase();" required value="{{ admin }}" />
&rdsh; <kbd>a-z - _ .</kbd>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password">{{ lang.edit.password }} (<a href="#" class="generate_password">{{ lang.edit.generate }}</a>)</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="password" placeholder="" autocomplete="new-password">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password2">{{ lang.edit.password_repeat }}</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" class="form-control" name="password2" autocomplete="new-password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="disable_tfa"> {{ lang.tfa.disable_tfa }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-api-reload-location="/admin" data-id="editadmin" data-item="{{ admin }}" data-api-url='edit/admin' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,70 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.alias }}</h4>
<br>
<form class="form-horizontal" data-id="editalias" role="form" method="post">
<input type="hidden" value="0" name="active">
{% if not skip_sogo %}
<input type="hidden" value="0" name="sogo_visible">
{% endif %}
<div class="form-group">
<label class="control-label col-sm-2" for="address">{{ lang.edit.alias }}</label>
<div class="col-sm-10">
<input class="form-control" type="text" name="address" value="{{ result.address }}" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="goto">{{ lang.edit.target_address|raw }}</label>
<div class="col-sm-10">
<textarea id="textarea_alias_goto" class="form-control" autocapitalize="none" autocorrect="off" rows="10" id="goto" name="goto" required>{{ goto|replace({',': ', '}) }}</textarea>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_null"{% if result.goto == 'null@localhost' %} checked{% endif %}> {{ lang.add.goto_null }}</label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_spam"{% if result.goto == 'spam@localhost' %} checked{% endif %}> {{ lang.add.goto_spam|raw }}</label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_ham"{% if result.goto == 'ham@localhost' %} checked{% endif %}> {{ lang.add.goto_ham|raw }}</label>
</div>
{% if not skip_sogo %}
<hr>
<div class="checkbox">
<label><input type="checkbox" value="1" name="sogo_visible"{% if result.sogo_visible == '1' %} checked{% endif %}> {{ lang.edit.sogo_visible }}</label>
</div>
<p class="help-block">{{ lang.edit.sogo_visible_info }}</p>
{% endif %}
</div>
</div>
<hr>
<div class="form-group">
<label class="control-label col-sm-2" for="private_">{{ lang.edit.private_comment }}</label>
<div class="col-sm-10">
<input maxlength="160" class="form-control" type="text" name="private_comment" value="{{ result.private_comment }}" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="public_comment">{{ lang.edit.public_comment }}</label>
<div class="col-sm-10">
<input maxlength="160" class="form-control" type="text" name="public_comment" value="{{ result.public_comment }}" />
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editalias" data-item="{{ alias }}" data-api-url='edit/alias' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,60 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.edit_alias_domain }}</h4>
<form class="form-horizontal" data-id="editaliasdomain" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="target_domain">{{ lang.edit.target_domain }}</label>
<div class="col-sm-10">
<select class="full-width-select" data-live-search="true" id="addSelectDomain" name="target_domain" required>
{% for domain in domains %}
<option{% if result.target_domain == domain %} selected{% endif %}>{{ domain }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editaliasdomain" data-item="{{ alias_domain }}" data-api-url='edit/alias-domain' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
<hr>
<form data-id="domratelimit" class="form-inline well" method="post">
<div class="form-group">
<label class="control-label">{{ lang.acl.ratelimit }}</label>
<input name="rl_value" type="number" value="{{ rl.value }}" autocomplete="off" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
</div>
<div class="form-group">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
<div class="form-group">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="domratelimit" data-item="{{ alias_domain }}" data-api-url='edit/rl-domain' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</form>
{% if dkim %}
<hr>
<div class="row">
<div class="col-xs-12 col-sm-2">
<p>Domain: <strong>{{ result.alias_domain }}</strong> ({{ dkim.dkim_selector }}._domainkey)</p>
</div>
<div class="col-xs-12 col-sm-10">
<pre>{{ dkim.dkim_txt }}</pre>
</div>
</div>
{% endif %}
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,42 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.app_passwd }}</h4>
<form class="form-horizontal" data-pwgen-length="32" data-id="editapp" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="app_name">{{ lang.edit.app_name }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="app_name" id="app_name" value="{{ result.name }}" required maxlength="255">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password">{{ lang.edit.password }} (<a href="#" class="generate_password">{{ lang.edit.generate }}</a>)</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="password" placeholder="" autocomplete="new-password">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password2">{{ lang.edit.password_repeat }}</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" class="form-control" name="password2" autocomplete="new-password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editapp" data-item="{{ result.id }}" data-api-url='edit/app-passwd' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,41 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.mailbox.bcc_map }}</h4>
<br>
<form class="form-horizontal" data-id="editbcc" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="bcc_dest">{{ lang.mailbox.bcc_destination }}</label>
<div class="col-sm-10">
<input value="{{ result.bcc_dest }}" type="text" class="form-control" name="bcc_dest" id="bcc_dest">
<small>{{ lang.edit.bcc_dest_format|raw }}</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="type">{{ lang.mailbox.bcc_map_type }}</label>
<div class="col-sm-10">
<select id="addFilterType" name="type" id="type" required>
<option value="sender"{% if result.type == 'sender'%} selected{% endif %}>{{ lang.mailbox.bcc_sender_map }}</option>
<option value="rcpt"{% if result.type == 'rcpt'%} selected{% endif %}>{{ lang.mailbox.bcc_rcpt_map }}</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editbcc" data-item="{{ bcc }}" data-api-url='edit/bcc' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,221 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<ul class="nav nav-tabs responsive-tabs" role="tablist">
<li class="active"><a data-toggle="tab" href="#dedit">{{ lang.edit.domain }}</a></li>
<li><a data-toggle="tab" href="#dratelimit">{{ lang.edit.ratelimit }}</a></li>
<li><a data-toggle="tab" href="#dspamfilter">{{ lang.edit.spam_filter }}</a></li>
<li><a data-toggle="tab" href="#dqwbcc">{{ lang.edit.quota_warning_bcc }}</a></li>
</ul>
<hr>
<div class="tab-content">
<div id="dedit" class="tab-pane in active">
<form data-id="editdomain" class="form-horizontal" role="form" method="post">
<input type="hidden" value="0" name="active">
<input type="hidden" value="0" name="backupmx">
<input type="hidden" value="0" name="gal">
<input type="hidden" value="0" name="relay_all_recipients">
<input type="hidden" value="0" name="relay_unknown_only">
<div class="form-group" data-acl="{{ acl.domain_desc }}">
<label class="control-label col-sm-2" for="description">{{ lang.edit.description }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="description" value="{{ result.description }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="relayhost">{{ lang.edit.relayhost }}</label>
<div class="col-sm-10">
<select data-acl="{{ acl.domain_relayhost }}" data-live-search="true" id="relayhost" name="relayhost" class="form-control">
{% for rlyhost in rlyhosts %}
<option
style="{% if rlyhost.active != '1' %}background: #ff4136; color: #fff{% endif %}"
{% if result.relayhost == rlyhost.id %} selected{% endif %}
value="{{ rlyhost.id }}">
ID {{ rlyhost.id }}: {{ rlyhost.hostname }} ({{ rlyhost.username }})
</option>
{% endfor %}
<option value=""{% if not result.relayhost %} selected{% endif %}>
{{ lang.edit.none_inherit }}
</option>
</select>
</div>
</div>
{% if mailcow_cc_role == 'admin' %}
<div class="form-group">
<label class="control-label col-sm-2" for="aliases">{{ lang.edit.max_aliases }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="aliases" value="{{ result.max_num_aliases_for_domain }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mailboxes">{{ lang.edit.max_mailboxes }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mailboxes" value="{{ result.max_num_mboxes_for_domain }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="defquota">{{ lang.edit.mailbox_quota_def }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="defquota" value="{{ (result.def_quota_for_mbox / 1048576) }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxquota">{{ lang.edit.max_quota }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxquota" value="{{ (result.max_quota_for_mbox / 1048576) }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="quota">{{ lang.edit.domain_quota }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="quota" value="{{ (result.max_quota_for_domain / 1048576) }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">{{ lang.edit.backup_mx_options }}</label>
<div class="col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="backupmx"{% if result.backupmx == '1' %} checked{% endif %}> {{ lang.edit.relay_domain }}</label>
<br>
<label><input type="checkbox" value="1" name="relay_all_recipients"{% if result.relay_all_recipients == '1' %} checked{% endif %}> {{ lang.edit.relay_all }}</label>
<p>{{ lang.edit.relay_all_info|raw }}</p>
<label><input type="checkbox" value="1" name="relay_unknown_only"{% if result.relay_unknown_only == '1' %} checked{% endif %}> {{ lang.edit.relay_unknown_only }}</label>
<br>
<p>{{ lang.edit.relay_transport_info|raw }}</p>
<hr style="margin:25px 0px 0px 0px">
</div>
</div>
</div>
{% endif %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="gal"{% if result.gal == '1' %} checked{% endif %}> {{ lang.edit.gal }}</label>
<small class="help-block">{{ lang.edit.gal_info|raw }}</small>
</div>
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}{% if mailcow_cc_role != 'admin' %} disabled{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editdomain" data-item="{{ domain }}" data-api-url='edit/domain' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</div>
</form>
{% if dkim %}
<hr>
<div class="row">
<div class="col-xs-12 col-sm-2">
<p>Domain: <strong>{{ result.domain_name }}</strong> ({{ dkim.dkim_selector }}._domainkey)</p>
</div>
<div class="col-xs-12 col-sm-10">
<pre>{{ dkim.dkim_txt }}</pre>
</div>
</div>
{% endif %}
</div>
<div id="dratelimit" class="tab-pane">
<form data-id="domratelimit" class="form-inline well" method="post">
<div class="form-group">
<label class="control-label">{{ lang.edit.ratelimit }}</label>
<input name="rl_value" type="number" value="{{ rl.value }}" autocomplete="off" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
</div>
<div class="form-group">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
<div class="form-group">
<button data-acl="{{ acl.ratelimit }}" class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="domratelimit" data-item="{{ domain }}" data-api-url='edit/rl-domain' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</form>
</div>
<div id="dspamfilter" class="tab-pane">
<div class="row">
<div class="col-sm-6">
<h4>{{ lang.user.spamfilter_wl }}</h4>
<p>{{ lang.user.spamfilter_wl_desc|raw }}</p>
<form class="form-inline space20" data-id="add_wl_policy_domain">
<div class="input-group" data-acl="{{ acl.spam_policy }}">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-default" data-action="add_item" data-id="add_wl_policy_domain" data-api-url='add/domain-policy' data-api-attr='{"domain":"{{ domain }}","object_list":"wl"}' href="#">{{ lang.user.spamfilter_table_add }}</button>
</span>
</div>
</form>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="wl_policy_domain_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.spam_policy }}">
<a class="btn btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_wl_domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-danger" data-action="delete_selected" data-id="policy_wl_domain" data-api-url='delete/domain-policy' href="#">{{ lang.mailbox.remove }}</a>
<div class="clearfix visible-xs"></div>
</div>
</div>
</div>
<div class="col-sm-6">
<h4>{{ lang.user.spamfilter_bl }}</h4>
<p>{{ lang.user.spamfilter_bl_desc|raw }}</p>
<form class="form-inline space20" data-id="add_bl_policy_domain">
<div class="input-group" data-acl="{{ acl.spam_policy }}">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-default" data-action="add_item" data-id="add_bl_policy_domain" data-api-url='add/domain-policy' data-api-attr='{"domain":"{{ domain }}","object_list":"bl"}' href="#">{{ lang.user.spamfilter_table_add }}</button>
</span>
</div>
</form>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="bl_policy_domain_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.spam_policy }}">
<a class="btn btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_bl_domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-danger" data-action="delete_selected" data-id="policy_bl_domain" data-api-url='delete/domain-policy' href="#">{{ lang.mailbox.remove }}</a></li>
</div>
</div>
</div>
</div>
</div>
<div id="dqwbcc" class="tab-pane">
<div class="row">
<div class="col-sm-12">
<h4>{{ lang.edit.quota_warning_bcc }}</h4>
<p>{{ lang.edit.quota_warning_bcc_info|raw }}</p>
<form class="form-horizontal" data-id="quota_bcc">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="script_data">{{ lang.edit.target_address|raw }}:</label>
<div class="col-sm-10">
<textarea spellcheck="false" autocorrect="off" autocapitalize="none" class="form-control" rows="10" id="bcc_rcpt" name="bcc_rcpt">{{ quota_notification_bcc.bcc_rcpts|join("\n") }}</textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if quota_notification_bcc.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="quota_bcc" data-item="quota_bcc" data-api-url='edit/quota_notification_bcc' data-api-attr='{"domain":"{{ domain }}"}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,83 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.domain_admin }}</h4>
<br>
<form class="form-horizontal" data-id="editdomainadmin" role="form" method="post" autocomplete="off">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="username_new">{{ lang.edit.username }}</label>
<div class="col-sm-10">
<input class="form-control" type="text" name="username_new" value="{{ domain_admin }}" required onkeyup="this.value = this.value.toLowerCase();" />
&rdsh; <kbd>a-z - _ .</kbd>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="domains">{{ lang.edit.domains }}</label>
<div class="col-sm-10">
<select data-live-search="true" class="full-width-select" name="domains" multiple required>
{% for domain in result.selected_domains %}
<option selected>{{ domain }}</option>
{% endfor %}
{% for domain in result.unselected_domains %}
<option>{{ domain }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password">{{ lang.edit.password }} (<a href="#" class="generate_password">{{ lang.edit.generate }}</a>)</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="password" placeholder="" autocomplete="new-password">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password2">{{ lang.edit.password_repeat }}</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" class="form-control" name="password2" autocomplete="new-password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="disable_tfa"> {{ lang.tfa.disable_tfa }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-api-reload-location="/admin" data-id="editdomainadmin" data-item="{{ domain_admin }}" data-api-url='edit/domain-admin' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
<form data-id="daacl" class="form-inline well" method="post">
<div class="row">
<div class="col-sm-1">
<p class="help-block">ACL</p>
</div>
<div class="col-sm-10">
<div class="form-group">
<select id="da_acl" name="da_acl" size="10" data-container="body" multiple>
{% for acl, val in da_acls %}
<option value="{{ acl }}"{% if val == 1 %} selected{% endif %}>{{ lang.acl[acl] }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="daacl" data-item="{{ domain_admin }}" data-api-url='edit/da-acl' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,45 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>Filter</h4>
<form class="form-horizontal" data-id="editfilter" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="script_desc">{{ lang.edit.sieve_desc }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="script_desc" id="script_desc" value="{{ result.script_desc }}" required maxlength="255">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="filter_type">{{ lang.edit.sieve_type }}</label>
<div class="col-sm-10">
<select id="addFilterType" name="filter_type" id="filter_type" required>
<option value="prefilter"{% if result.filter_type == 'prefilter' %} selected{% endif %}>Prefilter</option>
<option value="postfilter"{% if result.filter_type == 'postfilter' %} selected{% endif %}>Postfilter</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="script_data">Script:</label>
<div class="col-sm-10">
<textarea spellcheck="false" autocorrect="off" autocapitalize="none" class="form-control textarea-code" rows="20" id="script_data" name="script_data" required>{{ result.script_data|raw }}</textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editfilter" data-item="{{ result.id }}" data-api-url='edit/filter' data-api-attr='{}' href="#">{{ lang.edit.validate_save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,374 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<ul class="nav nav-tabs responsive-tabs" role="tablist">
<li class="active"><a data-toggle="tab" href="#medit">{{ lang.edit.mailbox }}</a></li>
<li><a data-toggle="tab" href="#mpushover">{{ lang.edit.pushover }}</a></li>
<li><a data-toggle="tab" href="#macl">{{ lang.edit.acl }}</a></li>
<li><a data-toggle="tab" href="#mrl">{{ lang.edit.ratelimit }}</a></li>
</ul>
<hr>
<div class="tab-content">
<div id="medit" class="tab-pane in active">
<form class="form-horizontal" data-id="editmailbox" role="form" method="post">
<input type="hidden" value="default" name="sender_acl">
<input type="hidden" value="0" name="force_pw_update">
<input type="hidden" value="0" name="sogo_access">
<input type="hidden" value="0" name="protocol_access">
<div class="form-group">
<label class="control-label col-sm-2" for="name">{{ lang.edit.full_name }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" value="{{ result.name }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="quota">{{ lang.edit.quota_mb }}
<br><span id="quotaBadge" class="badge">max. {{ (result.max_new_quota / 1048576) }} MiB</span>
</label>
<div class="col-sm-10">
<input type="number" name="quota" style="width:100%" min="0" max="{{ (result.max_new_quota / 1048576) }}" value="{{ (result.quota / 1048576) }}" class="form-control">
<small class="help-block">0 = ∞</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="sender_acl">{{ lang.edit.sender_acl }}</label>
<div class="col-sm-10">
<select data-live-search="true" data-width="100%" style="width:100%" id="editSelectSenderACL" name="sender_acl" size="10" multiple>
{% for domain in sender_acl_handles.sender_acl_domains.ro %}
<option data-subtext="Admin" value="{{ domain }}" disabled selected>
{{ lang.edit.dont_check_sender_acl|format(domain) }}
</option>
{% endfor %}
{% for alias in sender_acl_handles.sender_acl_addresses.ro %}
<option data-subtext="Admin" disabled selected>
{{ alias }}
</option>
{% endfor %}
{% for alias in sender_acl_handles.fixed_sender_aliases %}
<option data-subtext="Alias" disabled selected>{{ alias }}</option>
{% endfor %}
{% for domain in sender_acl_handles.sender_acl_domains.rw %}
<option value="{{ domain }}" selected>
{{ lang.edit.dont_check_sender_acl|format(domain) }}
</option>
{% endfor %}
{% for domain in sender_acl_handles.sender_acl_domains.selectable %}
<option value="{{ domain }}">
{{ lang.edit.dont_check_sender_acl|format(domain) }}
</option>
{% endfor %}
{% for address in sender_acl_handles.sender_acl_addresses.rw %}
<option selected>{{ address }}</option>
{% endfor %}
{% for address in sender_acl_handles.sender_acl_addresses.selectable %}
<option>{{ address }}</option>
{% endfor %}
</select>
<div id="sender_acl_disabled"><i class="bi bi-shield-exclamation"></i> {{ lang.edit.sender_acl_disabled }}</div>
<small class="help-block">{{ lang.edit.sender_acl_info|raw }}</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="relayhost">{{ lang.edit.relayhost }}</label>
<div class="col-sm-10">
<select data-acl="{{ acl.mailbox_relayhost }}" data-live-search="true" id="relayhost" name="relayhost" class="form-control space20">
{% for rlyhost in rlyhosts %}
<option
style="{% if rlyhost.active != '1' %}background: #ff4136; color: #fff{% endif %}"
{% if result.attributes.relayhost == rlyhost.id %} selected{% endif %}
value="{{ rlyhost.id }}">
ID {{ rlyhost.id }}: {{ rlyhost.hostname }} ({{ rlyhost.username }})
</option>
{% endfor %}
<option value=""{% if not result.attributes.relayhost %} selected{% endif %}>
{{ lang.edit.none_inherit }}
</option>
</select>
<p class="visible-xs" style="margin: 0;padding: 0">&nbsp;</p>
<small class="help-block">{{ lang.edit.mailbox_relayhost_info }}</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">{{ lang.user.quarantine_notification }}</label>
<div class="col-sm-10">
<div class="btn-group" data-acl="{{ acl.quarantine_notification }}">
<button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_notification == 'never' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"never"}'>{{ lang.user.never }}</button>
<button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_notification == 'hourly' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"hourly"}'>{{ lang.user.hourly }}</button>
<button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_notification == 'daily' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"daily"}'>{{ lang.user.daily }}</button>
<button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_notification == 'weekly' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"weekly"}'>{{ lang.user.weekly }}</button>
<div class="clearfix visible-xs"></div>
</div>
<p class="help-block"><small>{{ lang.user.quarantine_notification_info }}</small></p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">{{ lang.user.quarantine_category }}</label>
<div class="col-sm-10">
<div class="btn-group" data-acl="{{ acl.quarantine_category }}">
<button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_category == 'reject' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"reject"}'>{{ lang.user.q_reject }}</button>
<button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_category == 'add_header' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"add_header"}'>{{ lang.user.q_add_header }}</button>
<button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_category == 'all' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"all"}'>{{ lang.user.q_all }}</button>
<div class="clearfix visible-xs"></div>
</div>
<p class="help-block"><small>{{ lang.user.quarantine_category_info }}</small></p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="sender_acl">{{ lang.user.tls_policy }}</label>
<div class="col-sm-10">
<div class="btn-group" data-acl="{{ acl.tls_policy }}">
<button type="button" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if get_tls_policy.tls_enforce_in == '1' %} active"{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_in": {% if get_tls_policy.tls_enforce_in == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_in }}</button>
<button type="button" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if get_tls_policy.tls_enforce_out == '1' %} active"{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_out": {% if get_tls_policy.tls_enforce_out == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_out }}</button>
<div class="clearfix visible-xs"></div>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password">{{ lang.edit.password }} (<a href="#" class="generate_password">{{ lang.edit.generate }}</a>)</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="password" placeholder="{{ lang.edit.unchanged_if_empty }}" autocomplete="new-password">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password2">{{ lang.edit.password_repeat }}</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" class="form-control" name="password2" autocomplete="new-password">
</div>
</div>
<div data-acl="{{ acl.extend_sender_acl }}" class="form-group">
<label class="control-label col-sm-2" for="extended_sender_acl">{{ lang.edit.extended_sender_acl }}</label>
<div class="col-sm-10">
{% if sender_acl_handles.external_sender_aliases %}
{% set ext_sender_acl = sender_acl_handles.external_sender_aliases|join(', ') %}
{% endif %}
<input type="text" class="form-control" name="extended_sender_acl" value="{{ ext_sender_acl }}" placeholder="user1@example.com, user2@example.org, @example.com, ...">
<small class="help-block">{{ lang.edit.extended_sender_acl_info|raw }}</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="protocol_access">{{ lang.edit.allowed_protocols }}</label>
<div class="col-sm-10">
<select data-acl="{{ acl.protocol_access }}" name="protocol_access" multiple class="form-control">
<option value="imap"{% if result.attributes.imap_access == '1' %} selected{% endif %}>IMAP</option>
<option value="pop3"{% if result.attributes.pop3_access == '1' %} selected{% endif %}>POP3</option>
<option value="smtp"{% if result.attributes.smtp_access == '1' %} selected{% endif %}>SMTP</option>
</select>
</div>
</div>
<div hidden data-acl="{{ acl.smtp_ip_access }}" class="form-group">
<label class="control-label col-sm-2" for="allow_from_smtp">{{ lang.edit.allow_from_smtp }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="allow_from_smtp" value="{{ allow_from_smtp }}" placeholder="1.1.1.1, 10.2.0.0/24, ...">
<small class="help-block">{{ lang.edit.allow_from_smtp_info }}</small>
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<select name="active" class="form-control">
<option value="1"{% if result.active == '1' %} selected{% endif %}>{{ lang.edit.active }}</option>
<option value="2"{% if result.active == '2' %} selected{% endif %}>{{ lang.edit.disable_login }}</option>
<option value="0"{% if result.active == '0' %} selected{% endif %}>{{ lang.edit.inactive }}</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="force_pw_update"{% if result.attributes.force_pw_update == '1' %} checked{% endif %}> {{ lang.edit.force_pw_update }}</label>
<small class="help-block">{{ lang.edit.force_pw_update_info|format(ui_texts.main_name) }}</small>
</div>
</div>
</div>
{% if not skip_sogo %}
<div data-acl="{{ acl.sogo_access }}" class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="sogo_access"{% if result.attributes.sogo_access == '1' %} checked{% endif %}> {{ lang.edit.sogo_access }}</label>
<small class="help-block">{{ lang.edit.sogo_access_info }}</small>
</div>
</div>
</div>
{% endif %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editmailbox" data-item="{{ result.username }}" data-api-url='edit/mailbox' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
</div>
<div id="mpushover" class="tab-pane">
<form data-id="pushover" class="form well" method="post">
<input type="hidden" value="0" name="evaluate_x_prio">
<input type="hidden" value="0" name="only_x_prio">
<input type="hidden" value="0" name="active">
<div class="row">
<div class="col-sm-1">
<p class="help-block"><a href="https://pushover.net" target="_blank"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAACglBMVEUAAAAAAAEAAAAilecFGigAAAAAAAAAAAAAAAANj+c3n+Ypm+oeYI4KWI4MieAtkdQbleoJcLcjmeswmN4Rit4KgdMKUYQJKUAQSnILL0kMNlMSTngimOoNPF0hlOQBBgkNOlkRS3MHIjUhk+IPf8wKLUYsjM0AAAASTngAAAAAAAAPfckbdLIbdrYUWIgegsgce70knfEAAAAknfENOVkGHi8YaaIjnvEdgMUhkuAQSG8aca0hleQUh9YLjOM4nOEMgtMcbaYWa6YemO02ltkKhNktgLodYZEPXJEyi8kKesktfLUzj84cWYMiluckZ5YJXJYeW4Y0k9YKfs4yjs0pc6YHZaUviskLfMkqmugak+cqkNcViNcqeK4Iaq4XRmYGPmYMKDsFJTstgr0LdL0ti84CCQ4BCQ4Qgc8rlt8XjN8shcQsi8wZSGgEP2cRMEUDKkUAAAD///8dmvEamfExo/EXmPEWl/ERlvElnvEsofEjnfETl/Enn/Ezo/E4pvEvovEfm/E1pPEzpPEvofEOlfEpoPEamPEQlfEYmfE6p/EgnPEVlvEroPE3pfE2pfENk/Ern/E3pPEcmfEfmvEnnvBlufT6/P0soPAknPDd7/zs9vzo9PxBqfItofAqoPD9/f3B4/q43/mx2/l/xfZ6w/Vxv/VtvfVgt/RXtPNTsfNEq/L3+/31+v3a7fvR6vvH5fqs2vmc0/jx+P3v9/3h8fzW7PvV7PvL5/q13fmo1/mh1PiY0fiNy/aHyfZ2wfVou/Vdt/RPsPM3oeoQkuowmeAgjdgcgMQbeLrw9/3k8vy74Pm63/mX0PdYtfNNr/Ikm+4wnOchkuAVjOAfdrMVcrOdoJikAAAAcnRSTlMAIQ8IzzweFwf+/fvw8P79+/Xt7e3p6eji4d7U08y8qZyTiIWDgn53bWxqaWBKQ0JBOjUwMCkoJCEfHBkT/vz8/Pv7+vr69/b29PTy7ezm5ubm5N7e29vQ0M/Pv7+4uLW1pqaWloWDg3x7e21mUVFFRUXdPracAAAEbElEQVRIx4WUZbvaQBCFF+ru7u7u7u7u7t4mvVwSoBC0JIUCLRQolLq7u7vr/+nMLkmQyvlwyfPcd86e3ZldUqwyQ/p329J+XfutPQYOLUP+q55rFtQJRvY79+xxlZTUWbKpz7/xrrMr2+3BoNPpdLn2lJQ4HEeqLOr1d7z7XNkesQed4A848G63Oy4Gmg/6Mz542QvZbqe8C/Ig73CLYiYTrtLmT3zfqbIcAR7y4wIqH/B6M9Fo0+Ldb6sM9ph/v4ozPuz12mxRofaAAr7jCNkuoz/jNf9AGHibkBCm51fsGKvxsAGWx4H+jBcEi6V2birDpCL/9Klrd1KHbiSvPWP8V0tTnTfO03iXi57P6WNHOVUf44IFdFDRz6pV5fw8Zy5z3JVH5+R48OwxqDiGvKJIY9R+9JsCuJ5HPg74OVEMpz+nbdEPUHEWeEk6IDUnTC1l5r+f8uffc0cfxc8fS17kLso24SwUPFDA/6DE82xKDOPliJ7n/GGOOyWK9zD9CdjvOfg9Dv6AH+AX04LW9gj2i8W/APx1UbxwCAu+wPmcpgUKL/EHdvtq4uwaZwCuznPJVY5LHhED15G/isd5Hz4eKui/e/du02YoKFeD5mHzHIN/nxEDe25gQQwKorAid04CfyzwL4XutXvl1Pt1guMOwwKPkU8mYIFT8JHK+vv8prpDScUVL+j8s3lOctw1GIhbWHAS+HgKPk7xPM/4UtNAYmzizJkf6NgTb/gM8jePQLsewMdthS3g95tMpT1IhVm6v1s8fYmLeb13Odwp8Fh5KY048y/d14WUrwrb1e/X/rNp73nkD8kWS+wi/MZ4XuetG4mhKubJm3/WNEvi8SHwB56nPKjUam0LBdp9ARwupFemTYudvgN/L1+A/Ko/LGBuS8pPy+YR1fuCTWNKnUyoeUyYx2o2dyEVGmr5xTD42xzvkD16+Pb9WIIH6fmt1r3mbsTY7Bvw+n23naT8BUWh86bz6G/e259UXPUK3gfAxQDlo7Rpx3Geqb2e3wp83SGEdKpB7zvwYbzvT2n65xLwbH6YP+M9C8vA8E1wxLU8gkCbdhXGUyrMgwVrcbzLHonr78lzDvWM3q/C/HtDlXoSUIe3YkblhRPIX4E8Oo/9siLv8dRjV7SBlkdgTXvKS7nzsA/9AfeEuhKq9T8zWIDv1Sd6ETAP4D6/H/1V+1BojvruNa4SZXz4JhY84dV5MOF5agUvu5OsOo+KRpG30KalEnoeDccFlutPZYs38D5n3zcpr1/0fBhfb3DOY1z2tSAgLxWezz6zuoHhfUmOejf6blHQH/sFuJYfcMZX307ytKvRa3ifoV/586P5j+tICtS77BuJxzxYAPZsntX8k3eSIhlajK4p8b7iefCEKs03kD/I2LnxL9ovH+43y4fAv1YrI/mzDBsavAX/UppfzVOrZT/ydxk6lJ047MfLfVbcb6hS9ZEzWxekKQ5WrtPqZg3rV6tWrX6Tle3KQZj/q6KxQnmDoXwFY0VSrN9e8FRXBCTAvwAAAABJRU5ErkJggg==" class="img img-fluid"></a></p>
</div>
<div class="col-sm-10">
<p class="help-block">{{ lang.user.pushover_info|format(mailbox)|raw }}</p>
<p class="help-block">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code></p>
<div class="form-group">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="token">API Token/Key (Application)</label>
<input type="text" class="form-control" name="token" maxlength="30" value="{{ pushover_data.token }}" required>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="key">User/Group Key</label>
<input type="text" class="form-control" name="key" maxlength="30" value="{{ pushover_data.key }}" required>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="title">{{ lang.edit.pushover_title }}</label>
<input type="text" class="form-control" name="title" value="{{ pushover_data.title }}" placeholder="Mail">
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="text">{{ lang.edit.pushover_text }}</label>
<input type="text" class="form-control" name="text" value="{{ pushover_data.text }}" placeholder="You've got mail 📧">
</div>
</div>
<div class="col-sm-12">
<div class="form-group">
<label for="text">{{ lang.edit.pushover_sender_array|raw }}</label>
<input type="text" class="form-control" name="senders" value="{{ pushover_data.senders }}" placeholder="sender1@example.com, sender2@example.com">
</div>
</div>
<div class="col-sm-12">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if pushover_data.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
<div class="col-sm-12">
<legend style="cursor:pointer;margin-top:10px" data-target="#po_advanced" unselectable="on" data-toggle="collapse">
<i class="bi bi-plus"></i> {{ lang.edit.advanced_settings }}
</legend>
</div>
<div class="col-sm-12">
<div id="po_advanced" class="collapse">
<div class="form-group">
<label for="text">{{ lang.edit.pushover_sender_regex }}</label>
<input type="text" class="form-control" name="senders_regex" value="{{ pushover_data.senders_regex }}" placeholder="/(.*@example\.org$|^foo@example\.com$)/i" regex="true">
<div class="checkbox">
<label><input type="checkbox" value="1" name="evaluate_x_prio"{% if pushover_data.attributes.evaluate_x_prio == '1' %} checked{% endif %}> {{ lang.edit.pushover_evaluate_x_prio|raw }}</label>
</div>
<div class="checkbox">
<label><input type="checkbox" value="1" name="only_x_prio"{% if pushover_data.attributes.only_x_prio == '1' %} checked{% endif %}> {{ lang.edit.pushover_only_x_prio|raw }}</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="btn-group" data-acl="{{ acl.pushover }}">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="pushover" data-item="{{ mailbox }}" data-api-url='edit/pushover' data-api-attr='{}' href="#">{{ lang.edit.save }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="pushover-test" data-item="{{ mailbox }}" data-api-url='edit/pushover-test' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.edit.pushover_verify }}</a>
<div class="clearfix visible-xs"></div>
<a id="pushover_delete" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger" data-action="edit_selected" data-id="pushover-delete" data-item="{{ mailbox }}" data-api-url='edit/pushover' data-api-attr='{"delete":"true"}' href="#"><i class="bi bi-trash"></i> {{ lang.edit.remove }}</a>
</div>
</div>
</div>
</form>
</div>
<div id="macl" class="tab-pane">
<form data-id="useracl" class="form-inline well" method="post">
<div class="row">
<div class="col-sm-1">
<p class="help-block">ACL</p>
</div>
<div class="col-sm-10">
<div class="form-group">
<select id="user_acl" name="user_acl" size="10" multiple>
{% for acl, val in user_acls %}
<option value="{{ acl }}"{% if val == 1 %} selected{% endif %}>{{ lang.acl[acl] }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="useracl" data-item="{{ mailbox }}" data-api-url='edit/user-acl' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</div>
</form>
</div>
<div id="mrl" class="tab-pane">
<form data-id="mboxratelimit" class="form-inline well" method="post">
<div class="row">
<div class="col-sm-1">
<p class="help-block">{{ lang.acl.ratelimit }}</p>
</div>
<div class="col-sm-10">
<div class="form-group">
<input name="rl_value" type="number" autocomplete="off" value="{{ rl.value }}" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
</div>
<div class="form-group">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
<div class="form-group">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="mboxratelimit" data-item="{{ mailbox }}" data-api-url='edit/rl-mbox' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
<p class="help-block">{{ lang.edit.mbox_rl_info }}</p>
</div>
</div>
</form>
</div>
</div>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,40 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>OAuth2</h4>
<form data-id="oauth2client" class="form-horizontal" role="form" method="post">
<div class="form-group">
<label class="control-label col-sm-2" for="client_id">{{ lang.edit.client_id }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="client_id" id="client_id" value="{{ result.client_id }}" disabled>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="client_secret">{{ lang.edit.client_secret }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="client_secret" id="client_secret" value="{{ result.client_secret }}" disabled>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="scope">{{ lang.edit.scope }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="scope" id="scope" value="{{ result.scope }}" disabled>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="redirect_uri">{{ lang.edit.redirect_uri }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="redirect_uri" id="redirect_uri" value="{{ result.redirect_uri }}">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="oauth2client" data-item="{{ oauth2client }}" data-api-url='edit/oauth2-client' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,39 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.mailbox.recipient_map }}: {{ result.recipient_map_old }}</h4>
<br>
<form class="form-horizontal" data-id="edit_recipient_map" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="recipient_map_new">{{ lang.mailbox.recipient_map_old }}</label>
<div class="col-sm-10">
<input value="{{ result.recipient_map_old }}" type="text" class="form-control" name="recipient_map_old" id="recipient_map_old">
<small>{{ lang.mailbox.recipient_map_old_info }}</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="recipient_map_new">{{ lang.mailbox.recipient_map_new }}</label>
<div class="col-sm-10">
<input value="{{ result.recipient_map_new }}" type="text" class="form-control" name="recipient_map_new" id="recipient_map_new">
<small>{{ lang.mailbox.recipient_map_new_info }}</small>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="edit_recipient_map" data-item="{{ map }}" data-api-url='edit/recipient_map' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,43 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.resource }}</h4>
<form class="form-horizontal" role="form" method="post" data-id="editrelayhost">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="hostname">{{ lang.add.hostname }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="hostname" value="{{ result.hostname }}" required>
<p class="help-block">{{ lang.add.relayhost_wrapped_tls_info|raw }}</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="username">{{ lang.add.username }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="username" value="{{ result.username }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password">{{ lang.add.password }}</label>
<div class="col-sm-10">
<input type="text" data-hibp="true" class="form-control" name="password" value="{{ result.password }}">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editrelayhost" data-item="{{ result.id }}" data-api-url='edit/relayhost' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,55 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.resource }}</h4>
<form class="form-horizontal" role="form" method="post" data-id="editresource">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="description">{{ lang.add.description }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="description" value="{{ result.description }}" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="domain">{{ lang.edit.kind }}</label>
<div class="col-sm-10">
<select name="kind" title="{{ lang.edit.select }}" required>
<option value="location"{% if result.kind == 'location' %} selected{% endif %}>Location</option>
<option value="group"{% if result.kind == 'group' %} selected{% endif %}>Group</option>
<option value="thing"{% if result.kind == 'thing' %} selected{% endif %}>Thing</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="multiple_bookings_select">{{ lang.add.multiple_bookings }}</label>
<div class="col-sm-10">
<select name="multiple_bookings_select" id="editSelectMultipleBookings" title="{{ lang.add.select }}" required>
<option value="0"{% if result.multiple_bookings == 0 %} selected{% endif %}>{{ lang.mailbox.booking_0 }}</option>
<option value="-1"{% if result.multiple_bookings == -1 %} selected{% endif %}>{{ lang.mailbox.booking_lt0 }}</option>
<option value="custom"{% if result.multiple_bookings >= 1 %} selected{% endif %}>{{ lang.mailbox.booking_custom }}</option>
</select>
<div style="display:none" id="multiple_bookings_custom_div">
<hr>
<input type="number" class="form-control" name="multiple_bookings_custom" id="multiple_bookings_custom"{% if result.multiple_bookings >= 1 %} value="{{ result.multiple_bookings }}"{% endif %}>
</div>
<input type="hidden" name="multiple_bookings" id="multiple_bookings">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editresource" data-item="{{ result.name }}" data-api-url='edit/resource' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,160 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.syncjob }}</h4>
<form class="form-horizontal" data-id="editsyncjob" role="form" method="post">
<input type="hidden" value="0" name="delete2duplicates">
<input type="hidden" value="0" name="delete1">
<input type="hidden" value="0" name="delete2">
<input type="hidden" value="0" name="automap">
<input type="hidden" value="0" name="skipcrossduplicates">
<input type="hidden" value="0" name="active">
<input type="hidden" value="0" name="subscribeall">
<div class="form-group">
<label class="control-label col-sm-2" for="host1">{{ lang.edit.hostname }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="host1" id="host1" value="{{ result.host1 }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="port1">Port</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="port1" id="port1" min="1" max="65535" value="{{ result.port1 }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="user1">{{ lang.edit.username }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="user1" id="user1" value="{{ result.user1 }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password1">{{ lang.edit.password }}</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password1" id="password1" value="{{ result.password1 }}<">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="enc1">{{ lang.edit.encryption }}</label>
<div class="col-sm-10">
<select id="enc1" name="enc1">
<option value="SSL"{% if result.enc1 == 'SSL' %} selected{% endif %}>SSL</option>
<option value="TLS"{% if result.enc1 == 'TLS' %} selected{% endif %}>STARTTLS</option>
<option value="PLAIN"{% if result.enc1 == 'PLAIN' %} selected{% endif %}>PLAIN</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mins_interval">{{ lang.edit.mins_interval }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mins_interval" min="1" max="43800" value="{{ result.mins_interval }}" required>
<small class="help-block">1-43800</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="subfolder2">{{ lang.edit.subfolder2|raw }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="subfolder2" id="subfolder2" value="{{ result.subfolder2 }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxage">{{ lang.edit.maxage|raw }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxage" id="maxage" min="0" max="32000" value="{{ result.maxage }}">
<small class="help-block">0-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxbytespersecond">{{ lang.edit.maxbytespersecond|raw }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxbytespersecond" id="maxbytespersecond" min="0" max="125000000" value="{{ result.maxbytespersecond }}">
<small class="help-block">0-125000000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="timeout1">{{ lang.add.timeout1 }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="timeout1" id="timeout1" min="1" max="32000" value="{{ result.timeout1 }}">
<small class="help-block">1-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="timeout2">{{ lang.add.timeout2 }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="timeout2" id="timeout2" min="1" max="32000" value="{{ result.timeout2 }}">
<small class="help-block">1-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="exclude">{{ lang.edit.exclude }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="exclude" id="exclude" value="{{ result.exclude }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="custom_params">{{ lang.add.custom_params }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="custom_params" id="custom_params" value="{{ result.custom_params }}" placeholder="--dry --some-param=xy --other-param=yx">
<small class="help-block">{{ lang.add.custom_params_hint }}</small>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2duplicates"{% if result.delete2duplicates == '1' %} checked{% endif %}> {{ lang.edit.delete2duplicates }} (--delete2duplicates)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete1"{% if result.delete1 == '1' %} checked{% endif %}> {{ lang.edit.delete1 }} (--delete1)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2"{% if result.delete2 == '1' %} checked{% endif %}> {{ lang.edit.delete2 }} (--delete2)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="automap"{% if result.automap == '1' %} checked{% endif %}> {{ lang.edit.automap }} (--automap)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="skipcrossduplicates"{% if result.skipcrossduplicates == '1' %} checked{% endif %}> {{ lang.edit.skipcrossduplicates }} (--skipcrossduplicates)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="subscribeall"{% if result.subscribeall == '1' %} checked{% endif %}> {{ lang.add.subscribeall }} (--subscribeall)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="editsyncjob" data-item="{{ result.id }}" data-api-url='edit/syncjob' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,49 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.mailbox.tls_policy_maps }}: {{ result.dest }}</h4>
<br>
<form class="form-horizontal" data-id="edit_tls_policy_maps" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="dest">{{ lang.mailbox.tls_map_dest }}</label>
<div class="col-sm-10">
<input value="{{ result.dest }}" type="text" class="form-control" name="dest" id="dest">
<small>{{ lang.mailbox.tls_map_dest_info }}</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="policy">{{ lang.mailbox.tls_map_policy }}</label>
<div class="col-sm-10">
<select class="full-width-select" name="policy" required>
{% for policy in policy_options %}
<option value="{{ policy }}"{% if result.policy == policy %} selected{% endif %}>{{ policy }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="parameters">{{ lang.mailbox.tls_map_parameters }}</label>
<div class="col-sm-10">
<input value="{{ result.parameters }}" type="text" class="form-control" name="parameters" id="parameters">
<small>{{ lang.mailbox.tls_map_parameters_info }}</small>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="edit_tls_policy_maps" data-item="{{ map }}" data-api-url='edit/tls-policy-map' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,56 @@
{% extends 'edit.twig' %}
{% block inner_content %}
{% if result %}
<h4>{{ lang.edit.resource }}</h4>
<form class="form-horizontal" role="form" method="post" data-id="edittransport">
<input type="hidden" value="0" name="active">
<input type="hidden" value="0" name="is_mx_based">
<div class="form-group">
<label class="control-label col-sm-2" for="destination">{{ lang.add.destination }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="destination" value="{{ result.destination }}" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="nexthop">{{ lang.edit.nexthop }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="nexthop" placeholder='[0.0.0.0], [0.0.0.0]:25, host:25, host, [host]:25' value="{{ result.nexthop }}" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="username">{{ lang.add.username }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="username" value="{{ result.username }}">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password">{{ lang.add.password }}</label>
<div class="col-sm-10">
<input type="text" data-hibp="true" class="form-control" name="password" value="{{ result.password }}">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="is_mx_based"{% if result.is_mx_based == '1' %} checked{% endif %}> {{ lang.edit.lookup_mx|raw }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if result.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="edittransport" data-item="{{ result.id }}" data-api-url='edit/transport' data-api-attr='{}' href="#">{{ lang.edit.save }}</button>
</div>
</div>
</form>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,29 @@
{% if fido2_data %}
{% for key_info in fido2_data %}
<tr>
<td>
{% if fido2_cid == key_info.cid %}
<i class="bi bi-unlock-fill"></i>
{% endif %}
{% if key_info.fn %}
{{ key_info.fn }}
{% else %}
{{ key_info.subject }}
{% endif %}
</td>
<td style="min-width:240px;text-align: right">
<form style="display:inline;" method="post">
<input type="hidden" name="unset_fido2_key" value="{{ key_info.cid }}">
<div class="btn-group">
<a href="#" class="btn btn-xs btn-default" data-cid="{{ key_info.cid }}" data-subject="{{ key_info.subject|base64_encode }}" data-toggle="modal" data-target="#fido2ChangeFn">
<i class="bi bi-pencil-fill"></i> {{ lang.fido2.rename }}
</a>
<a href="#" onClick='return confirm("{{ lang.admin.ays }}")?$(this).closest("form").submit():"";' class="btn btn-xs btn-danger">
<i class="bi bi-trash"></i> {{ lang.admin.remove }}
</a>
</div>
</form>
</td>
</tr>
{% endfor %}
{% endif %}

View File

@@ -0,0 +1,111 @@
{% extends 'base.twig' %}
{% block navbar %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-offset-3 col-md-6">
<div class="panel panel-default panel-login">
<div class="panel-heading"><i class="bi bi-person-fill"></i> {{ lang.login.login }}</div>
<div class="panel-body">
<div class="text-center mailcow-logo"><img src="{{ logo|default('/img/cow_mailcow.svg') }}" alt="mailcow"></div>
{% if ui_texts.ui_announcement_text and ui_texts.ui_announcement_active and not is_root_uri %}
<div class="alert alert-{{ ui_texts.ui_announcement_type }} rot-enc ui-announcement-alert">{{ ui_texts.ui_announcement_text|rot13 }}</div>
{% endif %}
<legend>{% if oauth2_request %}{{ lang.oauth2.authorize_app }}{% else %}{{ ui_texts.main_name }}{% endif %}</legend>
{% if is_mobileconfig %}
<div class="alert alert-info">{{ lang.login.mobileconfig_info }}</div>
{% endif %}
<form method="post" autofill="off">
<div class="form-group">
<label class="sr-only" for="login_user">{{ lang.login.username }}</label>
<div class="input-group">
<div class="input-group-addon"><i class="bi bi-person-fill"></i></div>
<input name="login_user" autocorrect="off" autocapitalize="none" type="{% if is_mobileconfig %}email{% else %}text{% endif %}" id="login_user" class="form-control" placeholder="{{ lang.login.username }}" required="" autofocus="" autocomplete="username">
</div>
</div>
<div class="form-group">
<label class="sr-only" for="pass_user">{{ lang.login.password }}</label>
<div class="input-group">
<div class="input-group-addon"><i class="bi bi-lock-fill"></i></div>
<input name="pass_user" type="password" id="pass_user" class="form-control" placeholder="{{ lang.login.password }}" required="" autocomplete="current-password">
</div>
</div>
<div class="form-group" style="position: relative">
<div class="btn-group">
<div class="btn-group">
<button type="submit" class="btn btn-xs-lg btn-success" value="Login">{{ lang.login.login }}</button>
<button type="button" class="btn btn-xs-lg btn-success dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" id="fido2-login" style="line-height:1.4;"><i class="bi bi-shield-fill-check"></i> {{ lang.login.fido2_webauthn }}</a></li>
</ul>
</div>
</div>
{% if not oauth2_request %}
<button type="button" {% if available_languages|length == 1 %}disabled="true"{% endif %} class="btn btn-xs-lg btn-default pull-right dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="flag-icon flag-icon-{{ mailcow_locale }}"></span> <span class="caret"></span>
</button>
<ul class="dropdown-menu pull-right login">
{% for key, val in available_languages %}
<li{% if mailcow_locale == key %} class="active"{% endif %}>
<a href="?{{ query_string({'lang': key}) }}">
<span class="flag-icon flag-icon-{{ key }}"></span>{{ val }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}
<div class="clearfix"></div>
</div>
</form>
{% if login_delay %}
<p><div class="alert alert-info">{{ lang.login.delayed|format(login_delay) }}</b></div></p>
{% endif %}
<div id="fido2-alerts"></div>
{% if not oauth2_request %}
<legend><i class="bi bi-link-45deg"></i> {{ ui_texts.apps_name }}</legend>
<div class="apps">
{% for app in mailcow_apps %}
{% if not skip_sogo or not is_uri('SOGo', app.link) %}
<div class="media-clearfix">
<a href="{{ app.link }}" role="button" {% if app.description %}title="{{ app.description }}"{% endif %} class="btn btn-primary btn-lg btn-block">{{ app.name }}</a>
</div>
{% endif %}
{% endfor %}
{% for row in app_links %}
{% for key, val in row %}
<div class="media-clearfix">
<a href="{{ val }}" role="button" class="btn btn-primary btn-lg btn-block">{{ key }}</a>
</div>
{% endfor %}
{% endfor %}
</div>
{% endif %}
</div>
</div>
</div>
{% if not oauth2_request %}
<div class="col-md-offset-3 col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<a data-toggle="collapse" href="#collapse1"><i class="bi bi-patch-question-fill"></i> {{ lang.start.help }}</a>
</div>
<div id="collapse1" class="panel-collapse collapse">
<div class="panel-body">
{% if ui_texts.help_text %}
<p>{{ ui_texts.help_text|raw }}</p>
{% else %}
<p><span style="border-bottom: 1px dotted #999;">{{ ui_texts.main_name }}</span></p>
<p>{{ lang.start.mailcow_panel_detail|raw }}</p>
<p><span style="border-bottom: 1px dotted #999;">{{ ui_texts.apps_name }}</span></p>
<p>{{ lang.start.mailcow_apps_detail|raw }}</p>
{% endif %}
</div>
</div>
</div>
</div>
{% endif %}
</div>
{% endblock %}

View File

@@ -0,0 +1,58 @@
{% extends 'base.twig' %}
{% block content %}
<ul class="nav nav-tabs responsive-tabs" role="tablist">
<li role="presentation" class="active"><a href="#tab-domains" aria-controls="tab-domains" role="tab" data-toggle="tab">{{ lang.mailbox.domains }}</a></li>
<li role="presentation"><a href="#tab-mailboxes" aria-controls="tab-mailboxes" role="tab" data-toggle="tab">{{ lang.mailbox.mailboxes }}</a></li>
{# <li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.mailboxes }}
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li role="presentation"><a href="#tab-mailboxes" aria-controls="tab-mailboxes" role="tab" data-toggle="tab">{{ lang.mailbox.mailboxes }}</a></li>
<li role="presentation"><a href="#tab-mailbox-defaults" aria-controls="tab-mailbox-defaults" role="tab" data-toggle="tab">{{ lang.mailbox.mailbox_defaults }}</a></li>
</ul>
</li> #}
<li role="presentation"><a href="#tab-resources" aria-controls="tab-resources" role="tab" data-toggle="tab">{{ lang.mailbox.resources }}</a></li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.aliases }}
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li role="presentation"><a href="#tab-mbox-aliases" aria-controls="tab-mbox-aliases" role="tab" data-toggle="tab">{{ lang.mailbox.aliases }}</a></li>
<li role="presentation"><a href="#tab-domain-aliases" aria-controls="tab-domain-aliases" role="tab" data-toggle="tab">{{ lang.mailbox.domain_aliases }}</a></li>
</ul>
</li>
<li role="presentation"><a href="#tab-syncjobs" aria-controls="tab-syncjobs" role="tab" data-toggle="tab">{{ lang.mailbox.sync_jobs }}</a></li>
<li role="presentation"><a href="#tab-filters" aria-controls="tab-filters" role="tab" data-toggle="tab">{{ lang.mailbox.filters }}</a></li>
<li role="presentation"><a href="#tab-bcc" aria-controls="tab-bcc" role="tab" data-toggle="tab">{{ lang.mailbox.address_rewriting }}</a></li>
<li role="presentation"{% if mailcow_cc_role != 'admin' %} class="hidden"{% endif %}><a href="#tab-tls-policy" aria-controls="tab-tls-policy" role="tab" data-toggle="tab">{{ lang.mailbox.tls_policy_maps }}</a></li>
</ul>
<div class="row">
<div class="col-md-12">
<div class="tab-content" style="padding-top:20px">
{% include 'mailbox/tab-domains.twig' %}
{% include 'mailbox/tab-mailbox-defaults.twig' %}
{% include 'mailbox/tab-mailboxes.twig' %}
{% include 'mailbox/tab-resources.twig' %}
{% include 'mailbox/tab-domain-aliases.twig' %}
{% include 'mailbox/tab-mbox-aliases.twig' %}
{% include 'mailbox/tab-syncjobs.twig' %}
{% include 'mailbox/tab-filters.twig' %}
{% include 'mailbox/tab-bcc.twig' %}
{% include 'mailbox/tab-tls-policy.twig' %}
</div> <!-- /tab-content -->
</div> <!-- /col-md-12 -->
</div> <!-- /row -->
{% include 'modals/mailbox.twig' %}
<script type='text/javascript'>
var acl = '{{ acl_json|raw }}';
var lang = {{ lang_mailbox|raw }};
var csrf_token = '{{ csrf_token }}';
var pagination_size = '{{ pagination_size }}';
var role = '{{ role }}';
var is_dual = {{ is_dual }};
var ALLOW_ADMIN_EMAIL_LOGIN = {{ allow_admin_email_login }};
</script>
{% endblock %}

View File

@@ -0,0 +1,6 @@
<li><a href="#" data-page-size="3">{{ lang.mailbox.table_size_show_n|format(3) }}</a></li>
<li><a href="#" data-page-size="10">{{ lang.mailbox.table_size_show_n|format(10) }}</a></li>
<li><a href="#" data-page-size="20">{{ lang.mailbox.table_size_show_n|format(20) }}</a></li>
<li><a href="#" data-page-size="50">{{ lang.mailbox.table_size_show_n|format(50) }}</a></li>
<li><a href="#" data-page-size="100">{{ lang.mailbox.table_size_show_n|format(100) }}</a></li>
<li><a href="#" data-page-size="200">{{ lang.mailbox.table_size_show_n|format(200) }}</a></li>

View File

@@ -0,0 +1,4 @@
<option value="s"{% if rl.frame == 's' %} selected{% endif %}>{{ lang.ratelimit.second }}</option>
<option value="m"{% if rl.frame == 'm' %} selected{% endif %}>{{ lang.ratelimit.minute }}</option>
<option value="h"{% if rl.frame == 'h' %} selected{% endif %}>{{ lang.ratelimit.hour }}</option>
<option value="d"{% if rl.frame == 'd' %} selected{% endif %}>{{ lang.ratelimit.day }}</option>

View File

@@ -0,0 +1,73 @@
<div role="tabpanel" class="tab-pane" id="tab-bcc">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.mailbox.bcc_maps }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right hidden-xs">
<button class="btn btn-xs btn-success" href="#" data-acl="{{ acl.bcc_maps }}" data-toggle="modal" data-target="#addBCCModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_bcc_entry }}</button>
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_bcc_table" data-table="bcc_table">{{ lang.admin.refresh }}</button>
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.mailbox.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="bcc_table" role="menu">
{% include 'mailbox/page-size.twig' %}
</ul>
</div>
</div>
<p style="margin:10px" class="help-block">{{ lang.mailbox.bcc_info|raw }}</p>
{# <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
<div class="table-responsive">
<table class="table table-striped" id="bcc_table"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group" data-acl="{{ acl.bcc_maps }}">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="bcc" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"sender"}' href="#">{{ lang.mailbox.bcc_to_sender }}</a></li>
<li><a data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"rcpt"}' href="#">{{ lang.mailbox.bcc_to_rcpt }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="bcc" data-api-url='delete/bcc' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addBCCModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_bcc_entry }}</a>
</div>
</div>
</div>
<div class="panel panel-default{% if mailcow_cc_role != 'admin' %} hidden{% endif %}">
<div class="panel-heading">
{{ lang.mailbox.recipient_maps }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right hidden-xs">
<button class="btn btn-xs btn-success" href="#" data-toggle="modal" data-target="#addRecipientMapModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_recipient_map_entry }}</button>
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_recipient_map_table" data-table="recipient_map_table">{{ lang.admin.refresh }}</button>
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.mailbox.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="recipient_map_table" role="menu">
{% include 'mailbox/page-size.twig' %}
</ul>
</div>
</div>
<p style="margin:10px" class="help-block">{{ lang.mailbox.recipient_map_info }}</p>
{# <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
<div class="table-responsive">
<table class="table table-striped" id="recipient_map_table"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="recipient_map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="recipient_map" data-api-url='delete/recipient_map' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addRecipientMapModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_recipient_map_entry }}</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,35 @@
<div role="tabpanel" class="tab-pane" id="tab-domain-aliases">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.mailbox.domain_aliases }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right hidden-xs">
<button class="btn btn-xs btn-success" href="#" data-acl="{{ acl.alias_domains }}" data-toggle="modal" data-target="#addAliasDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain_alias }}</button>
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_aliasdomain_table" data-table="aliasdomain_table">{{ lang.admin.refresh }}</button>
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.mailbox.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="aliasdomain_table" role="menu">
{% include 'mailbox/page-size.twig' %}
</ul>
</div>
</div>
{# <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
<div class="table-responsive">
<table id="aliasdomain_table" class="table table-striped"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="alias-domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="alias-domain" data-api-url='delete/alias-domain' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-acl="{{ acl.alias_domains }}" data-toggle="modal" data-target="#addAliasDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain_alias }}</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,41 @@
<div role="tabpanel" class="tab-pane active" id="tab-domains">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.mailbox.domains }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right hidden-xs">
{% if mailcow_cc_role == 'admin' %}
<button class="btn btn-xs btn-success" href="#" data-toggle="modal" data-target="#addDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain }}</button>
{% endif %}
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_domain_table" data-table="domain_table">{{ lang.admin.refresh }}</button>
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.mailbox.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="domain_table" role="menu">
{% include 'mailbox/page-size.twig' %}
</ul>
</div>
</div>
{# <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
<div class="table-responsive">
<table id="domain_table" class="table table-striped"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="domain" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
{% if mailcow_cc_role == 'admin' %}
<li><a data-action="edit_selected" data-id="domain" data-api-url='edit/domain' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="domain" data-api-url='edit/domain' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="domain" data-api-url='delete/domain' href="#">{{ lang.mailbox.remove }}</a></li>
{% endif %}
</ul>
<div class="clearfix visible-xs"></div>
{% if mailcow_cc_role == 'admin' %}
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addDomainModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_domain }}</a>
{% endif %}
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,83 @@
<div role="tabpanel" class="tab-pane" id="tab-filters">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.mailbox.filters }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right hidden-xs">
<button class="btn btn-xs btn-success" href="#" data-acl="{{ acl.filters }}" data-toggle="modal" data-target="#addFilterModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_filter }}</button>
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_filter_table" data-table="filter_table">{{ lang.admin.refresh }}</button>
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.mailbox.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="filter_table" role="menu">
{% include 'mailbox/page-size.twig' %}
</ul>
</div>
</div>
<div class="panel-body">
<p class="help-block">{{ lang.mailbox.sieve_info|raw }}</p><br>
</div>
{# <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
<div class="table-responsive">
<table class="table table-striped" id="filter_table"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group" data-acl="{{ acl.filters }}">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="filter_item" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"filter_type":"prefilter"}' href="#">{{ lang.mailbox.set_prefilter }}</a></li>
<li><a data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"filter_type":"postfilter"}' href="#">{{ lang.mailbox.set_postfilter }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-text="{{ lang.user.eas_reset }}?" data-id="filter_item" data-api-url='delete/filter' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addFilterModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_filter }}</a>
</div>
</div>
<div class="panel-body{% if mailcow_cc_role != 'admin' %} hidden{% endif %}">
<div class="row">
<div class="col-lg-6">
<h5>Global Prefilter</h5>
<form class="form-horizontal" data-cached-form="false" role="form" data-id="add_prefilter">
<div class="form-group">
<div class="col-sm-12">
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code script_data" rows="10" name="script_data" required>{{ global_filters.prefilter }}</textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-10 add_filter_btns">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default validate_sieve" href="#">{{ lang.add.validate }}</button>
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success add_sieve_script" data-action="add_item" data-id="add_prefilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"prefilter"}' href="#" disabled><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<div class="clearfix visible-xs"></div>
</div>
</div>
</div>
</form>
</div>
<div class="col-lg-6">
<h5>Global Postfilter</h5>
<form class="form-horizontal" data-cached-form="false" role="form" data-id="add_postfilter">
<div class="form-group">
<div class="col-sm-12">
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code script_data" rows="10" name="script_data" required>{{ global_filters.postfilter }}</textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-10 add_filter_btns">
<div class="btn-group">
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default validate_sieve" href="#">{{ lang.add.validate }}</button>
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success add_sieve_script" data-action="add_item" data-id="add_postfilter" data-api-url='add/global-filter' data-api-attr='{"filter_type":"postfilter"}' href="#" disabled><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
<div class="clearfix visible-xs"></div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,10 @@
<div role="tabpanel" class="tab-pane" id="tab-mailbox-defaults">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.mailbox.mailbox_defaults }}
</div>
<div class="panel-body help-block">
{{ lang.mailbox.mailbox_defaults_info }}
</div>
</div>
</div>

View File

@@ -0,0 +1,121 @@
<div role="tabpanel" class="tab-pane" id="tab-mailboxes">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.mailbox.mailboxes }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right hidden-xs">
<button class="btn btn-xs btn-success" href="#" data-toggle="modal" data-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</button>
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_mailbox_table" data-table="mailbox_table">{{ lang.admin.refresh }}</button>
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.mailbox.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="mailbox_table" role="menu">
{% include 'mailbox/page-size.twig' %}
</ul>
</div>
</div>
<div class="mass-actions-mailbox hidden-xs" data-actions-header="true"></div>
<div class="table-responsive">
<table id="mailbox_table" class="table table-striped"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group hidden-md hidden-lg hidden-xl">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="dropdown-header">{{ lang.mailbox.mailbox }}</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li><a data-action="delete_selected" data-id="mailbox" data-api-url='delete/mailbox' href="#">{{ lang.mailbox.remove }}</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">{{ lang.mailbox.tls_enforce_in }}</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_in":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_in":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">{{ lang.mailbox.tls_enforce_out }}</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_out":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_out":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">{{ lang.mailbox.quarantine_notification }}</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"hourly"}' href="#">{{ lang.user.hourly }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"daily"}' href="#">{{ lang.user.daily }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"weekly"}' href="#">{{ lang.user.weekly }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"never"}' href="#">{{ lang.user.never }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"reject"}' href="#">{{ lang.user.q_reject }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"add_header"}' href="#">{{ lang.user.q_add_header }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"all"}' href="#">{{ lang.user.q_all }}</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">{{ lang.mailbox.allowed_protocols }}</li>
<li class="dropdown-header">IMAP</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"imap_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"imap_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">POP3</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"pop3_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"pop3_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">SMTP</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</a>
</div>
<div class="btn-group hidden-xs hidden-sm">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<div class="btn-group">
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.mailbox }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"2"}' href="#">{{ lang.mailbox.disable_login }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="mailbox" data-api-url='delete/mailbox' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
</div>
<div class="btn-group">
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#">TLS <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="dropdown-header">{{ lang.mailbox.tls_enforce_in }}</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_in":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_in":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">{{ lang.mailbox.tls_enforce_out }}</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_out":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/tls_policy' data-api-attr='{"tls_enforce_out":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
</ul>
</div>
<div class="btn-group">
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.allowed_protocols }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="dropdown-header">IMAP</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"imap_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"imap_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">POP3</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"pop3_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"pop3_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">SMTP</li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":1}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"smtp_access":0}' href="#">{{ lang.mailbox.deactivate }}</a></li>
</ul>
</div>
<div class="btn-group">
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quarantine_notification }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"hourly"}' href="#">{{ lang.user.hourly }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"daily"}' href="#">{{ lang.user.daily }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"weekly"}' href="#">{{ lang.user.weekly }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_notification' data-api-attr='{"quarantine_notification":"never"}' href="#">{{ lang.user.never }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"reject"}' href="#">{{ lang.user.q_reject }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"add_header"}' href="#">{{ lang.user.q_add_header }}</a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/quarantine_category' data-api-attr='{"quarantine_category":"all"}' href="#">{{ lang.user.q_all }}</a></li>
</ul>
</div>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addMailboxModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_mailbox }}</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,44 @@
<div role="tabpanel" class="tab-pane" id="tab-mbox-aliases">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.mailbox.aliases }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right hidden-xs">
<button class="btn btn-xs btn-success" href="#" data-toggle="modal" data-target="#addAliasModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_alias }}</button>
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_alias_table" data-table="alias_table">{{ lang.admin.refresh }}</button>
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.mailbox.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="alias_table" role="menu">
{% include 'mailbox/page-size.twig' %}
</ul>
</div>
</div>
<div class="panel-body help-block">
{{ lang.mailbox.alias_domain_alias_hint|raw }}
</div>
<!-- <div class="mass-actions-mailbox" data-actions-header="true"></div> -->
<div class="table-responsive">
<table id="alias_table" class="table table-striped"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="alias" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu top33">
<li><a data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="alias" data-api-url='delete/alias' href="#">{{ lang.mailbox.remove }}</a></li>
{% if not skip_sogo %}
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"sogo_visible":"1"}' href="#">{{ lang.mailbox.sogo_visible_y }}</a></li>
<li><a data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"sogo_visible":"0"}' href="#">{{ lang.mailbox.sogo_visible_n }}</a></li>
{% endif %}
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"expand_alias":true}' ><i class="bi bi-arrows-angle-expand"></i> {{ lang.mailbox.add_alias_expand }}</a>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addAliasModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_alias }}</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,40 @@
<div role="tabpanel" class="tab-pane" id="tab-resources">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.mailbox.resources }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right hidden-xs">
<button class="btn btn-xs btn-success" href="#" data-toggle="modal" data-target="#addResourceModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_resource }}</button>
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_resource_table" data-table="resource_table">{{ lang.admin.refresh }}</button>
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.mailbox.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="resource_table" role="menu">
{% include 'mailbox/page-size.twig' %}
</ul>
</div>
</div>
<div class="panel-body help-block">
<p><span class="label label-success">{{ lang.mailbox.booking_0_short }}</span> - {{ lang.mailbox.booking_0 }}</p>
<p><span class="label label-warning">{{ lang.mailbox.booking_lt0_short }}</span> - {{ lang.mailbox.booking_lt0 }}</p>
<p><span class="label label-danger">{{ lang.mailbox.booking_custom_short }}</span> - {{ lang.mailbox.booking_custom }}</p>
</div>
{# <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
<div class="table-responsive">
<table id="resource_table" class="table table-striped"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="resource" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="resource" data-api-url='delete/resource' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addResourceModal"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_resource }}</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,37 @@
<div role="tabpanel" class="tab-pane" id="tab-syncjobs">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.mailbox.sync_jobs }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right hidden-xs">
<button data-acl="{{ acl.syncjobs }}" class="btn btn-xs btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.user.create_syncjob }}</button>
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_sync_job_table" data-table="sync_job_table">{{ lang.admin.refresh }}</button>
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.mailbox.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="sync_job_table" role="menu">
{% include 'mailbox/page-size.twig' %}
</ul>
</div>
</div>
<!-- <div class="mass-actions-mailbox" data-actions-header="true"></div> -->
<div class="table-responsive">
<table class="table table-striped" id="sync_job_table"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group" data-acl="{{ acl.syncjobs }}">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"last_run":"","success":""}' href="#">{{ lang.mailbox.last_run_reset }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="syncjob" data-api-url='delete/syncjob' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModalAdmin"><i class="bi bi-plus-lg"></i> {{ lang.user.create_syncjob }}</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,36 @@
<div role="tabpanel" class="tab-pane{% if mailcow_cc_role != 'admin' %} hidden{% endif %}" id="tab-tls-policy">
<div class="panel panel-default">
<div class="panel-heading">
{{ lang.mailbox.tls_policy_maps_long }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right hidden-xs">
<button class="btn btn-xs btn-success" href="#" data-toggle="modal" data-target="#addTLSPolicyMapAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_tls_policy_map }}</button>
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_tls_policy_table" data-table="tls_policy_table">{{ lang.admin.refresh }}</button>
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.mailbox.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="tls_policy_table" role="menu">
{% include 'mailbox/page-size.twig' %}
</ul>
</div>
</div>
<p style="margin:10px" class="help-block">{{ lang.mailbox.tls_policy_maps_info|raw }}</p>
{# <div class="mass-actions-mailbox" data-actions-header="true"></div>#}
<div class="table-responsive">
<table class="table table-striped" id="tls_policy_table"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="tls-policy-map" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="tls-policy-map" data-api-url='delete/tls-policy-map' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addTLSPolicyMapAdmin"><i class="bi bi-plus-lg"></i> {{ lang.mailbox.add_tls_policy_map }}</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,263 @@
<!-- add settings rule modal -->
<div class="modal fade" id="addRsettingModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.admin.add_settings_rule }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" data-id="rsetting" role="form" method="post">
<div class="form-group">
<label class="control-label col-sm-2" for="desc">{{ lang.admin.rsetting_desc }}:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="adminRspamdSettingsDesc" name="desc" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="content">{{ lang.admin.rsetting_content }}:</label>
<div class="col-sm-10">
<textarea class="form-control" id="adminRspamdSettingsContent" name="content" rows="10"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.admin.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="rsetting" data-api-url='add/rsetting' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.add }}</button>
</div>
</div>
</form>
<hr>
<p>{{ lang.admin.rspamd-com_settings }}</p>
<ul id="rspamd_presets"></ul>
</div>
</div>
</div>
</div><!-- add settings rule modal -->
<!-- add domain admin modal -->
<div class="modal fade" id="addDomainAdminModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.admin.add_domain_admin }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" data-id="add_domain_admin" role="form" method="post" autocomplete="off">
<div class="form-group">
<label class="control-label col-sm-2" for="username">{{ lang.admin.username }}:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="username" onkeyup="this.value = this.value.toLowerCase();" required>
&rdsh; <kbd>a-z - _ .</kbd>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="name">{{ lang.admin.admin_domains }}:</label>
<div class="col-sm-10">
<select title="{{ lang.admin.search_domain_da }}" class="full-width-select" name="domains" size="5" multiple>
{% for domain in domains %}
<option>{{ domain }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password">{{ lang.admin.password }} (<a href="#" class="generate_password">{{ lang.admin.generate }}</a>)</label>
<div class="col-sm-10">
<input type="password" class="form-control" data-pwgen-field="true" data-hibp="true" name="password" placeholder="" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password2">{{ lang.admin.password_repeat }}:</label>
<div class="col-sm-10">
<input type="password" class="form-control" data-pwgen-field="true" name="password2" placeholder="" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.admin.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_domain_admin" data-api-url='add/domain-admin' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add domain admin modal -->
<!-- change fido2 fn -->
<div class="modal fade" id="fido2ChangeFn" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.fido2.set_fn }}</h3>
<p class="help-block" style="word-break:break-all" id="fido2_subject_desc" data-fido2-subject=""></p>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="false" data-id="fido2ChangeFn" role="form" method="post" autocomplete="off">
<input type="hidden" class="form-control" name="fido2_cid" id="fido2_cid">
<div class="form-group">
<label class="control-label col-sm-4" for="fido2_fn">{{ lang.fido2.fn }}:</label>
<div class="col-sm-8">
<input type="text" class="form-control" name="fido2_fn">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="fido2ChangeFn" data-item="null" data-api-url='edit/fido2-fn' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add domain admin modal -->
<!-- add oauth2 client modal -->
<div class="modal fade" id="addOAuth2ClientModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">OAuth2</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" data-id="add_oauth2_client" role="form" method="post">
<div class="form-group">
<label class="control-label col-sm-2" for="redirect_uri">{{ lang.admin.oauth2_redirect_uri }}:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="redirect_uri" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_oauth2_client" data-api-url='add/oauth2-client' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add domain admin modal -->
<!-- add admin modal -->
<div class="modal fade" id="addAdminModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.admin.add_admin }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" data-id="add_admin" role="form" method="post" autocomplete="off">
<div class="form-group">
<label class="control-label col-sm-2" for="username">{{ lang.admin.username }}:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="username" onkeyup="this.value = this.value.toLowerCase();" required>
&rdsh; <kbd>a-z - _ .</kbd>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password">{{ lang.admin.password }} (<a href="#" class="generate_password">{{ lang.admin.generate }}</a>):</label>
<div class="col-sm-10">
<input type="password" class="form-control" data-pwgen-field="true" data-hibp="true" name="password" placeholder="" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password2">{{ lang.admin.password_repeat }}:</label>
<div class="col-sm-10">
<input type="password" class="form-control" data-pwgen-field="true" name="password2" placeholder="" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.admin.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_admin" data-api-url='add/admin' data-api-attr='{}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add admin modal -->
<!-- test transport modal -->
<div class="modal fade" id="testTransportModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><i class="bi bi-info-circle-fill"></i> Transport</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" id="test_transport_form" role="form" method="post">
<input type="hidden" class="form-control" name="transport_id" id="transport_id">
<input type="hidden" class="form-control" name="transport_type" id="transport_type">
<div class="form-group">
<label class="control-label col-sm-2" for="mail_from">{{ lang.admin.relay_from }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="mail_from" placeholder="relay@example.org">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mail_rcpt">{{ lang.admin.relay_rcpt }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="mail_rcpt" placeholder="null@hosted.mailcow.de" value="null@hosted.mailcow.de">
<p class="help-block">{{ lang.admin.transport_test_rcpt_info }}</p>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="test_transport" href="#">{{ lang.admin.relay_run }}</button>
</div>
</div>
</form>
<hr>
<div id="test_transport_result" style="font-size:10pt">-</div>
</div>
</div>
</div>
</div><!-- test transport modal -->
<!-- show queue item modal -->
<div class="modal fade" id="showQueuedMsg" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><i class="bi bi-card-checklist" style="font-size:18px"></i> ID <span id="queue_id"></span></h3>
</div>
<div class="modal-body">
<textarea class="form-control" id="queue_msg_content" name="content" rows="40"></textarea>
</div>
</div>
</div>
</div><!-- show queue item modal -->
<!-- priv key modal -->
<div class="modal fade" id="showDKIMprivKey" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><i class="bi bi-key-fill"></i> Private key</h3>
</div>
<div class="modal-body">
<pre id="priv_key_pre"></pre>
</div>
</div>
</div>
</div><!-- priv key modal -->

View File

@@ -0,0 +1,234 @@
{% if mailcow_cc_role %}
<div class="modal fade" id="YubiOTPModal" tabindex="-1" role="dialog" aria-labelledby="YubiOTPModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.tfa.yubi_otp }}</h3>
</div>
<div class="modal-body">
<form role="form" method="post">
<div class="form-group">
<input type="text" class="form-control" name="key_id" placeholder="{{ lang.tfa.key_id }}" autocomplete="off" required>
</div>
<hr>
<p class="help-block">{{ lang.tfa.api_register|format(ui_texts.main_name) }}</p>
<div class="form-group">
<input type="text" class="form-control" name="yubico_id" placeholder="Yubico API ID" autocomplete="off" required>
</div>
<div class="form-group">
<input type="text" class="form-control" name="yubico_key" placeholder="Yubico API Key" autocomplete="off" required>
</div>
<hr>
<div class="form-group">
<input type="password" class="form-control" name="confirm_password" placeholder="{{ lang.user.password_now }}" autocomplete="off" required>
</div>
<div class="form-group">
<div class="input-group">
<span class="input-group-addon" id="yubi-addon"><img alt="Yubicon Icon" src="/img/yubi.ico"></span>
<input type="text" name="otp_token" class="form-control" placeholder="Touch Yubikey" aria-describedby="yubi-addon">
<input type="hidden" name="tfa_method" value="yubi_otp">
</div>
</div>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" type="submit" name="set_tfa">{{ lang.user.save_changes }}</button>
</form>
</div>
</div>
</div>
</div>
<div class="modal fade" id="U2FModal" tabindex="-1" role="dialog" aria-labelledby="U2FModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.tfa.u2f }}</h3>
</div>
<div class="modal-body">
<form role="form" method="post" id="u2f_reg_form">
<div class="form-group">
<input type="text" class="form-control" name="key_id" placeholder="{{ lang.tfa.key_id }}" autocomplete="off" required>
</div>
<div class="form-group">
<input type="password" class="form-control" name="confirm_password" placeholder="{{ lang.user.password_now }}" autocomplete="off" required>
</div>
<hr>
<center>
<div style="cursor:pointer" id="start_u2f_register">
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24">
<path d="M17.81 4.47c-.08 0-.16-.02-.23-.06C15.66 3.42 14 3 12.01 3c-1.98 0-3.86.47-5.57 1.41-.24.13-.54.04-.68-.2-.13-.24-.04-.55.2-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67-.09.18-.26.28-.44.28zM3.5 9.72c-.1 0-.2-.03-.29-.09-.23-.16-.28-.47-.12-.7.99-1.4 2.25-2.5 3.75-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54-.12.7-.23.16-.54.11-.7-.12-.9-1.26-2.04-2.25-3.39-2.94-2.87-1.47-6.54-1.47-9.4.01-1.36.7-2.5 1.7-3.4 2.96-.08.14-.23.21-.39.21zm6.25 12.07c-.13 0-.26-.05-.35-.15-.87-.87-1.34-1.43-2.01-2.64-.69-1.23-1.05-2.73-1.05-4.34 0-2.97 2.54-5.39 5.66-5.39s5.66 2.42 5.66 5.39c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-2.42-2.09-4.39-4.66-4.39-2.57 0-4.66 1.97-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71-.11.1-.24.15-.37.15zm7.17-1.85c-1.19 0-2.24-.3-3.1-.89-1.49-1.01-2.38-2.65-2.38-4.39 0-.28.22-.5.5-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64-.03 1.04-.1.27-.05.53.13.58.41.05.27-.13.53-.41.58-.57.11-1.07.12-1.21.12zM14.91 22c-.04 0-.09-.01-.13-.02-1.59-.44-2.63-1.03-3.72-2.1-1.4-1.39-2.17-3.24-2.17-5.22 0-1.62 1.38-2.94 3.08-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08-.87 2.08-1.94c0-3.77-3.25-6.83-7.25-6.83-2.84 0-5.44 1.58-6.61 4.03-.39.81-.59 1.76-.59 2.8 0 .78.07 2.01.67 3.61.1.26-.03.55-.29.64-.26.1-.55-.04-.64-.29-.49-1.31-.73-2.61-.73-3.96 0-1.2.23-2.29.68-3.24 1.33-2.79 4.28-4.6 7.51-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62-1.38 2.94-3.08 2.94s-3.08-1.32-3.08-2.94c0-1.07-.93-1.94-2.08-1.94s-2.08.87-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61-.05.23-.26.38-.47.38z"></path>
</svg>
<p>{{ lang.tfa.start_u2f_validation }}</p>
<hr>
</div>
</center>
<p id="u2f_status_reg"></p>
<div class="alert alert-danger" style="display:none" id="u2f_return_code"></div>
<input type="hidden" name="token" id="u2f_register_data"/>
<input type="hidden" name="tfa_method" value="u2f">
<input type="hidden" name="set_tfa"/><br/>
</form>
</div>
</div>
</div>
</div>
<div class="modal fade" id="TOTPModal" tabindex="-1" role="dialog" aria-labelledby="TOTPModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.tfa.totp }}</h3>
</div>
<div class="modal-body">
<form role="form" method="post">
<div class="form-group">
<input type="text" class="form-control" name="key_id" placeholder="{{ lang.tfa.key_id_totp }}" autocomplete="off" required>
</div>
<div class="form-group">
<input type="password" class="form-control" name="confirm_password" placeholder="{{ lang.user.password_now }}" autocomplete="off" required>
</div>
<hr>
<?php
$totp_secret = $tfa->createSecret();
?>
<input type="hidden" value="<?=$totp_secret;?>" name="totp_secret">
<input type="hidden" name="tfa_method" value="totp">
<ol>
<li>
<p>{{ lang.tfa.scan_qr_code }}</p>
<img id="tfa-qr-img" data-totp-secret="<?=$totp_secret;?>" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
<p class="help-block">{{ lang.tfa.enter_qr_code }}:<br />
<code><?=$totp_secret;?></code>
</p>
</li>
<li>
<p>{{ lang.tfa.confirm_totp_token }}:</p>
<p><input type="number" style="width:33%" class="form-control" name="totp_confirm_token" autocomplete="off" required></p>
<p><button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" type="submit" name="set_tfa">{{ lang.tfa.confirm }}</button></p>
</li>
</ol>
</form>
</div>
</div>
</div>
</div>
<div class="modal fade" id="DisableTFAModal" tabindex="-1" role="dialog" aria-labelledby="DisableTFAModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.tfa.delete_tfa }}</h3>
</div>
<div class="modal-body">
<form role="form" method="post">
<div class="input-group">
<input type="password" class="form-control input-xs-lg" name="confirm_password" placeholder="{{ lang.user.password_now }}" autocomplete="off" required>
<span class="input-group-btn">
<input type="hidden" name="tfa_method" value="none">
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger" type="submit" name="set_tfa">{{ lang.tfa.delete_tfa|replace({" ": "&nbsp;"}) }}</button>
</span>
</div>
</form>
</div>
</div>
</div>
</div>
{% endif %}
{% if pending_tfa_method %}
<div class="modal fade" id="ConfirmTFAModal" tabindex="-1" role="dialog" aria-labelledby="ConfirmTFAModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.tfa[pending_tfa_method] }}</h3>
</div>
<div class="modal-body">
{% if pending_tfa_method == 'yubi_otp' %}
<form role="form" method="post">
<div class="form-group">
<div class="input-group">
<span class="input-group-addon" id="yubi-addon"><img alt="Yubicon Icon" src="/img/yubi.ico"></span>
<input type="text" name="token" class="form-control" autocomplete="off" placeholder="Touch Yubikey" aria-describedby="yubi-addon">
<input type="hidden" name="tfa_method" value="yubi_otp">
</div>
</div>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-default" type="submit" name="verify_tfa_login">{{ lang.login.login }}</button>
</form>
{% endif %}
{% if pending_tfa_method == 'u2f' %}
<form role="form" method="post" id="u2f_auth_form">
<center>
<div id="start_u2f_confirmation">
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24">
<path d="M17.81 4.47c-.08 0-.16-.02-.23-.06C15.66 3.42 14 3 12.01 3c-1.98 0-3.86.47-5.57 1.41-.24.13-.54.04-.68-.2-.13-.24-.04-.55.2-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67-.09.18-.26.28-.44.28zM3.5 9.72c-.1 0-.2-.03-.29-.09-.23-.16-.28-.47-.12-.7.99-1.4 2.25-2.5 3.75-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54-.12.7-.23.16-.54.11-.7-.12-.9-1.26-2.04-2.25-3.39-2.94-2.87-1.47-6.54-1.47-9.4.01-1.36.7-2.5 1.7-3.4 2.96-.08.14-.23.21-.39.21zm6.25 12.07c-.13 0-.26-.05-.35-.15-.87-.87-1.34-1.43-2.01-2.64-.69-1.23-1.05-2.73-1.05-4.34 0-2.97 2.54-5.39 5.66-5.39s5.66 2.42 5.66 5.39c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-2.42-2.09-4.39-4.66-4.39-2.57 0-4.66 1.97-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71-.11.1-.24.15-.37.15zm7.17-1.85c-1.19 0-2.24-.3-3.1-.89-1.49-1.01-2.38-2.65-2.38-4.39 0-.28.22-.5.5-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64-.03 1.04-.1.27-.05.53.13.58.41.05.27-.13.53-.41.58-.57.11-1.07.12-1.21.12zM14.91 22c-.04 0-.09-.01-.13-.02-1.59-.44-2.63-1.03-3.72-2.1-1.4-1.39-2.17-3.24-2.17-5.22 0-1.62 1.38-2.94 3.08-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08-.87 2.08-1.94c0-3.77-3.25-6.83-7.25-6.83-2.84 0-5.44 1.58-6.61 4.03-.39.81-.59 1.76-.59 2.8 0 .78.07 2.01.67 3.61.1.26-.03.55-.29.64-.26.1-.55-.04-.64-.29-.49-1.31-.73-2.61-.73-3.96 0-1.2.23-2.29.68-3.24 1.33-2.79 4.28-4.6 7.51-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62-1.38 2.94-3.08 2.94s-3.08-1.32-3.08-2.94c0-1.07-.93-1.94-2.08-1.94s-2.08.87-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61-.05.23-.26.38-.47.38z"></path>
</svg>
<p>{{ lang.tfa.start_u2f_validation }}</p>
<hr>
</div>
</center>
<p id="u2f_status_auth"></p>
<div class="alert alert-danger" style="display:none" id="u2f_return_code"></div>
<input type="hidden" name="token" id="u2f_auth_data"/>
<input type="hidden" name="tfa_method" value="u2f">
<input type="hidden" name="verify_tfa_login"/><br/>
</form>
{% endif %}
{% if pending_tfa_method == 'totp' %}
<form role="form" method="post">
<div class="form-group">
<div class="input-group">
<span class="input-group-addon" id="tfa-addon"><i class="bi bi-shield-lock-fill"></i></span>
<input type="number" min="000000" max="999999" name="token" class="form-control" placeholder="123456" autocomplete="one-time-code" aria-describedby="tfa-addon">
<input type="hidden" name="tfa_method" value="totp">
</div>
</div>
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" type="submit" name="verify_tfa_login">{{ lang.login.login }}</button>
</form>
{% endif %}
{% if pending_tfa_method == 'hotp' %}
<div class="empty"></div>
{% endif %}
</div>
</div>
</div>
</div>
{% endif %}
{% if mailcow_cc_role == 'admin' %}
<div id="RestartContainer" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">{{ lang.footer.restart_container }} (<code id="containerName"></code>)</h4>
</div>
<div class="modal-body">
<p>{{ lang.footer.restart_container_info|raw }}</p>
<hr>
<button class="btn btn-md visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-primary" id="triggerRestartContainer">{{ lang.footer.restart_now }}</button>
<br><br>
<div id="statusTriggerRestartContainer"></div>
</div>
</div>
</div>
</div>
{% endif %}
<div id="ConfirmDeleteModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.footer.confirm_delete }}</h3>
</div>
<div class="modal-body">
<p id="DeleteText">{{ lang.footer.delete_these_items }}</p>
<ul id="ItemsToDelete"></ul>
<hr>
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger" id="IsConfirmed">{{ lang.footer.delete_now }}</button>
<button class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="isCanceled">{{ lang.footer.cancel }}</button>
<div class="clearfix visible-xs"></div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,817 @@
<!-- add mailbox modal -->
<div class="modal fade" id="addMailboxModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.mailbox.add_mailbox }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" data-id="add_mailbox" role="form" autocomplete="off">
<div class="form-group">
<label class="control-label col-sm-2" for="local_part">{{ lang.add.mailbox_username }}</label>
<div class="col-sm-10">
<input type="text" pattern="[A-Za-z0-9\.!#$%&'*+/=?^_`{|}~-]+" autocorrect="off" autocapitalize="none" class="form-control" name="local_part" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="domain">{{ lang.add.domain }}</label>
<div class="col-sm-10">
<select class="full-width-select" data-live-search="true" id="addSelectDomain" name="domain" required>
{% for domain in domains %}
<option>{{ domain }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="name">{{ lang.add.full_name }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="addInputQuota">{{ lang.add.quota_mb }}
<br /><span id="quotaBadge" class="badge">max. - MiB</span>
</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="quota" min="0" max="" id="addInputQuota" disabled value="{{ lang.add.select_domain }}" required>
<small class="help-block">0 = ∞</small>
<div class="label label-warning addInputQuotaExhausted" style="display:none;">{{ lang.warning.quota_exceeded_scope }}</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password">{{ lang.add.password }} (<a href="#" class="generate_password">{{ lang.add.generate }}</a>)</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="password" placeholder="" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password2">{{ lang.add.password_repeat }}</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" class="form-control" name="password2" placeholder="" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<select name="active" class="form-control">
<option value="1" selected>{{ lang.add.active }}</option>
<option value="2">{{ lang.add.disable_login }}</option>
<option value="0">{{ lang.add.inactive }}</option>
</select>
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_mailbox" data-api-url='add/mailbox' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add mailbox modal -->
<!-- add domain modal -->
<div class="modal fade" id="addDomainModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.mailbox.add_domain }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" data-id="add_domain" role="form">
<div class="form-group">
<label class="control-label col-sm-2" for="domain">{{ lang.add.domain }}</label>
<div class="col-sm-10">
<input type="text" autocorrect="off" autocapitalize="none" class="form-control" name="domain" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="description">{{ lang.add.description }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="description">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="aliases">{{ lang.add.max_aliases }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="aliases" value="400" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mailboxes">{{ lang.add.max_mailboxes }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mailboxes" value="10" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="defquota">{{ lang.add.mailbox_quota_def }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="defquota" value="3072" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxquota">{{ lang.add.mailbox_quota_m }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxquota" value="10240" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="quota">{{ lang.add.domain_quota_m }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="quota" value="10240" required>
</div>
</div>
{% if not skip_sogo %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="gal" checked> {{ lang.edit.gal }}</label>
<small class="help-block">{{ lang.edit.gal_info|raw }}</small>
</div>
</div>
</div>
{% endif %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<hr>
<div class="form-group">
<label class="control-label col-sm-2" for="rl_frame">{{ lang.acl.ratelimit }}</label>
<div class="col-sm-7">
<input name="rl_value" type="number" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
</div>
<div class="col-sm-3">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
</div>
<hr>
<div class="form-group">
<label class="control-label col-sm-2" for="dkim_selector">{{ lang.admin.dkim_domains_selector }}</label>
<div class="col-sm-10">
<input class="form-control" id="dkim_selector" name="dkim_selector" value="dkim">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="key_size">{{ lang.admin.dkim_key_length }}</label>
<div class="col-sm-10">
<select data-style="btn btn-default btn-sm" class="form-control" id="key_size" name="key_size">
<option data-subtext="bits">1024</option>
<option data-subtext="bits">2048</option>
</select>
</div>
</div>
<hr>
<div class="form-group">
<label class="control-label col-sm-2">{{ lang.add.backup_mx_options }}</label>
<div class="col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="backupmx"> {{ lang.add.relay_domain }}</label>
<br>
<label><input type="checkbox" value="1" name="relay_all_recipients"> {{ lang.add.relay_all }}</label>
<p>{{ lang.add.relay_all_info|raw }}</p>
<label><input type="checkbox" value="1" name="relay_unknown_only"> {{ lang.add.relay_unknown_only }}</label>
<br>
<p>{{ lang.add.relay_transport_info|raw }}</p>
</div>
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10 btn-group">
{% if not skip_sogo %}
<button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{}' href="#">{{ lang.add.add_domain_only }}</button>
<button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"restart_sogo":"1"}' href="#">{{ lang.add.add_domain_restart }}</button>
<div class="clearfix visible-xs"></div>
{% else %}
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{}' href="#">{{ lang.add.add }}</button>
{% endif %}
</div>
</div>
{# TODO: Separate SOGo-related text #}
{% if not skip_sogo %}
<p><i class="bi bi-shield-fill-exclamation text-danger"></i> {{ lang.add.post_domain_add|raw }}</p>
{% endif %}
</form>
</div>
</div>
</div>
</div><!-- add domain modal -->
<!-- add resource modal -->
<div class="modal fade" id="addResourceModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.mailbox.add_resource }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_resource">
<div class="form-group">
<label class="control-label col-sm-2" for="description">{{ lang.add.description }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="description" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="domain">{{ lang.add.domain }}</label>
<div class="col-sm-10">
<select data-live-search="true" name="domain" title="{{ lang.add.select }}" required>
{% for domain in domains %}
<option>{{ domain }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="domain">{{ lang.add.kind }}</label>
<div class="col-sm-10">
<select name="kind" title="{{ lang.add.select }}" required>
<option value="location">Location</option>
<option value="group">Group</option>
<option value="thing">Thing</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="multiple_bookings_select">{{ lang.add.multiple_bookings }}</label>
<div class="col-sm-10">
<select name="multiple_bookings_select" id="multiple_bookings_select" title="{{ lang.add.select }}" required>
<option value="0">{{ lang.mailbox.booking_0 }}</option>
<option value="-1" selected>{{ lang.mailbox.booking_lt0 }}</option>
<option value="custom">{{ lang.mailbox.booking_custom }}</option>
</select>
<div style="display:none" id="multiple_bookings_custom_div">
<hr>
<input type="number" class="form-control" name="multiple_bookings_custom" id="multiple_bookings_custom">
</div>
<input type="hidden" name="multiple_bookings" id="multiple_bookings">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_resource" data-api-url='add/resource' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add resource modal -->
<!-- add alias modal -->
<div class="modal fade" id="addAliasModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.mailbox.add_alias }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_alias">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="address">{{ lang.add.alias_address }}</label>
<div class="col-sm-10">
<textarea autocorrect="off" autocapitalize="none" class="form-control" rows="5" name="address" id="address" required></textarea>
<p>{{ lang.add.alias_address_info|raw }}</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="goto">{{ lang.add.target_address }}</label>
<div class="col-sm-10">
<textarea id="textarea_alias_goto" autocorrect="off" autocapitalize="none" class="form-control" rows="5" id="goto" name="goto" required></textarea>
<p>{{ lang.add.target_address_info|raw }}</p>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_null"> {{ lang.add.goto_null }}</label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_spam"> {{ lang.add.goto_spam|raw }}</label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_ham"> {{ lang.add.goto_ham|raw }}</label>
</div>
{% if not skip_sogo %}
<hr>
<div class="checkbox">
<label><input type="checkbox" value="1" name="sogo_visible" checked> {{ lang.edit.sogo_visible }}</label>
</div>
<p class="help-block">{{ lang.edit.sogo_visible_info }}</p>
{% endif %}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_alias" data-api-url='add/alias' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add alias modal -->
<!-- add domain alias modal -->
<div class="modal fade" id="addAliasDomainModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.mailbox.add_domain_alias }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_alias_domain">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="alias_domain">{{ lang.add.alias_domain }}</label>
<div class="col-sm-10">
<textarea autocorrect="off" autocapitalize="none" class="form-control" rows="5" name="alias_domain" id="alias_domain" required></textarea>
<p>{{ lang.add.alias_domain_info|raw }}</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="target_domain">{{ lang.add.target_domain }}</label>
<div class="col-sm-10">
<select data-live-search="true" name="target_domain" title="{{ lang.add.select }}" required>
{% for domain in domains %}
<option>{{ domain }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<hr>
<div class="form-group">
<label class="control-label col-sm-2" for="rl_frame">{{ lang.acl.ratelimit }}</label>
<div class="col-sm-7">
<input name="rl_value" type="number" class="form-control" placeholder="{{ lang.ratelimit.disabled }}">
</div>
<div class="col-sm-3">
<select name="rl_frame" class="form-control">
{% include 'mailbox/rl-frame.twig' %}
</select>
</div>
</div>
<hr>
<div class="form-group">
<label class="control-label col-sm-2" for="dkim_selector2">{{ lang.admin.dkim_domains_selector }}</label>
<div class="col-sm-10">
<input class="form-control" id="dkim_selector2" name="dkim_selector" value="dkim">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="key_size2">{{ lang.admin.dkim_key_length }}</label>
<div class="col-sm-10">
<select data-style="btn btn-default btn-sm" class="form-control" id="key_size2" name="key_size">
<option data-subtext="bits">1024</option>
<option data-subtext="bits">2048</option>
</select>
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_alias_domain" data-api-url='add/alias-domain' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add domain alias modal -->
<!-- add sync job modal -->
<div class="modal fade" id="addSyncJobModalAdmin" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.add.syncjob }}</h3>
</div>
<div class="modal-body">
<p class="help-block">{{ lang.add.syncjob_hint }}</p>
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_syncjob">
<div class="form-group">
<label class="control-label col-sm-2" for="username">{{ lang.add.username }}</label>
<div class="col-sm-10">
<select data-live-search="true" name="username" required>
{% for mailbox in mailboxes %}
<option>{{ mailbox }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="host1">{{ lang.add.hostname }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="host1" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="port1">{{ lang.add.port }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="port1" min="1" max="65535" value="143" required>
<small class="help-block">1-65535</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="user1">{{ lang.add.username }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="user1" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password1">{{ lang.add.password }}</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password1" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="enc1">{{ lang.add.enc_method }}</label>
<div class="col-sm-10">
<select name="enc1" title="{{ lang.add.select }}" required>
<option value="SSL" selected>SSL</option>
<option value="TLS">STARTTLS</option>
<option value="PLAIN">PLAIN</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mins_interval">{{ lang.add.mins_interval }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mins_interval" min="1" max="43800" value="20" required>
<small class="help-block">1-43800</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="subfolder2">{{ lang.edit.subfolder2|raw }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="subfolder2" value="">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxage">{{ lang.edit.maxage|raw }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxage" min="0" max="32000" value="0">
<small class="help-block">0-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxbytespersecond">{{ lang.edit.maxbytespersecond|raw }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxbytespersecond" min="0" max="125000000" value="0">
<small class="help-block">0-125000000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="timeout1">{{ lang.edit.timeout1 }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="timeout1" min="1" max="32000" value="600">
<small class="help-block">1-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="timeout2">{{ lang.edit.timeout2 }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="timeout2" min="1" max="32000" value="600">
<small class="help-block">1-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="exclude">{{ lang.add.exclude }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="exclude" value="(?i)spam|(?i)junk">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="custom_params">{{ lang.add.custom_params }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="custom_params" placeholder="--dry --some-param=xy --other-param=yx">
<small class="help-block">{{ lang.add.custom_params_hint }}</small>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2duplicates" checked> {{ lang.add.delete2duplicates }} (--delete2duplicates)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete1"> {{ lang.add.delete1 }} (--delete1)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2"> {{ lang.add.delete2 }} (--delete2)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="automap" checked> {{ lang.add.automap }} (--automap)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="skipcrossduplicates"> {{ lang.add.skipcrossduplicates }} (--skipcrossduplicates)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="subscribeall" checked> {{ lang.add.subscribeall }} (--subscribeall)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_syncjob" data-api-url='add/syncjob' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add sync job modal -->
<!-- add add_filter modal -->
<div class="modal fade" id="addFilterModalAdmin" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">Filter</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_filter">
<div class="form-group">
<label class="control-label col-sm-2" for="username">{{ lang.add.username }}</label>
<div class="col-sm-10">
<select data-live-search="true" name="username" required>
{% for mailbox in mailboxes %}
<option>{{ mailbox }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="filter_type">{{ lang.add.sieve_type }}</label>
<div class="col-sm-10">
<select id="addFilterType" name="filter_type" required>
<option value="prefilter">Prefilter</option>
<option value="postfilter">Postfilter</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="script_desc">{{ lang.add.sieve_desc }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="script_desc" name="script_desc" required maxlength="255">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="script_data">Script:</label>
<div class="col-sm-10">
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control textarea-code script_data" rows="20" name="script_data" required></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<p class="help-block">{{ lang.add.activate_filter_warn }}</p>
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10 add_filter_btns btn-group">
<button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default validate_sieve" href="#">{{ lang.add.validate }}</button>
<button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success add_sieve_script" data-action="add_item" data-id="add_filter" data-api-url='add/filter' data-api-attr='{}' href="#" disabled>{{ lang.admin.add }}</button>
<div class="clearfix visible-xs"></div>
</div>
</div>
</form>
{{ lang.mailbox.sieve_preset_header|raw }}
<ul id="sieve_presets"></ul>
</div>
</div>
</div>
</div><!-- add add_filter modal -->
<!-- add add_bcc modal -->
<div class="modal fade" id="addBCCModalAdmin" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.mailbox.bcc_maps }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_bcc">
<div class="form-group">
<label class="control-label col-sm-2" for="local_dest">{{ lang.mailbox.bcc_local_dest }}</label>
<div class="col-sm-10">
<select id="bcc-local-dest" data-live-search="true" data-size="20" name="local_dest" required>
<option selected>{{ lang.footer.loading }}</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="type">{{ lang.mailbox.bcc_map_type }}</label>
<div class="col-sm-10">
<select name="type" required>
<option value="sender">{{ lang.mailbox.bcc_sender_map }}</option>
<option value="rcpt">{{ lang.mailbox.bcc_rcpt_map }}</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="bcc_dest">{{ lang.mailbox.bcc_destination }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="bcc_dest">
<small>{{ lang.add.bcc_dest_format|raw }}</small>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_bcc" data-api-url='add/bcc' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add add_bcc modal -->
<!-- add add_recipient_map modal -->
<div class="modal fade" id="addRecipientMapModalAdmin" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.mailbox.recipient_maps }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_recipient_map">
<div class="form-group">
<label class="control-label col-sm-2" for="recipient_map_old">{{ lang.mailbox.recipient_map_old }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="recipient_map_old">
<small>{{ lang.mailbox.recipient_map_old_info }}</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="recipient_map_new">{{ lang.mailbox.recipient_map_new }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="recipient_map_new">
<small>{{ lang.mailbox.recipient_map_new_info }}</small>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_recipient_map" data-api-url='add/recipient_map' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add add_recipient_map modal -->
<!-- add add_tls_policy_map modal -->
<div class="modal fade" id="addTLSPolicyMapAdmin" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.mailbox.tls_policy_maps }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_tls_policy_map">
<div class="form-group">
<label class="control-label col-sm-2" for="dest">{{ lang.mailbox.tls_map_dest }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="dest">
<small>{{ lang.mailbox.tls_map_dest_info }}</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="policy">{{ lang.mailbox.tls_map_policy }}</label>
<div class="col-sm-10">
<select class="full-width-select" name="policy" required>
<option value="none">none</option>
<option value="may">may</option>
<option value="encrypt">encrypt</option>
<option value="dane">dane</option>
<option value="dane-only">dane-only</option>
<option value="fingerprint">fingerprint</option>
<option value="verify">verify</option>
<option value="secure">secure</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="parameters">{{ lang.mailbox.tls_map_parameters }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="parameters">
<small>{{ lang.mailbox.tls_map_parameters_info }}</small>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_tls_policy_map" data-api-url='add/tls-policy-map' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add add_tls_policy_map modal -->
<!-- log modal -->
<div class="modal fade" id="syncjobLogModal" tabindex="-1" role="dialog" aria-labelledby="syncjobLogModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">Log</h3>
</div>
<div class="modal-body">
<textarea class="form-control" rows="20" id="logText" spellcheck="false"></textarea>
</div>
</div>
</div>
</div><!-- log modal -->
<!-- DNS info modal -->
<div class="modal fade" id="dnsInfoModal" tabindex="-1" role="dialog" aria-labelledby="dnsInfoModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.diagnostics.dns_records }}</h3>
</div>
<div class="modal-body">
<p>{{ lang.diagnostics.dns_records_24hours }}</p>
<div class="dns-modal-body"></div>
<p>{{ lang.diagnostics.dns_records_docs }}</p>
</div>
</div>
</div>
</div><!-- DNS info modal -->

View File

@@ -0,0 +1,68 @@
<div class="modal fade" id="qidDetailModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><i class="bi bi-info-circle-fill"></i> {{ lang.quarantine.qitem }}</h3>
</div>
<div class="modal-body">
<div id="qid_error" style="display:none" class="alert alert-danger"></div>
<div class="form-group">
<label for="qid_detail_symbols"><h4>{{ lang.quarantine.rspamd_result }}:</h4></label>
<p>{{ lang.quarantine.spam_score }}: <span id="qid_detail_score"></span></p>
<hr>
<p id="qid_detail_symbols"></p>
</div>
<div class="form-group">
<label for="qid_detail_subj"><h4>{{ lang.quarantine.subj }}:</h4></label>
<p id="qid_detail_subj"></p>
</div>
<div class="form-group">
<label for="qid_detail_recipients"><h4>{{ lang.quarantine.recipients }}:</h4></label>
<p id="qid_detail_recipients"></p>
</div>
<div class="form-group">
<label for="qid_detail_hfrom"><h4>{{ lang.quarantine.sender_header }}:</h4></label>
<p><span class="mail-address-item" id="qid_detail_hfrom"></span></p>
</div>
<div class="form-group">
<label for="qid_detail_efrom"><h4>{{ lang.quarantine.sender }}:</h4></label>
<p><span class="mail-address-item" id="qid_detail_efrom"></span></p>
</div>
<div class="form-group">
<label for="qid_detail_fuzzy"><h4>Fuzzy Hashes:</h4></label>
<p id="qid_detail_fuzzy"></p>
</div>
<div class="form-group" id="qTextPlain">
<label for="qid_detail_text"><h4>{{ lang.quarantine.text_plain_content }}:</h4></label>
<pre id="qid_detail_text"></pre>
</div>
<div class="form-group" id="qTextHtml">
<label for="qid_detail_text_from_html"><h4>{{ lang.quarantine.text_from_html_content }}:</h4></label>
<pre id="qid_detail_text_from_html"></pre>
</div>
{% if acl.quarantine_attachments == 1 %}
<div class="form-group">
<label for="qid_detail_atts"><h4>{{ lang.quarantine.atts }}:</h4></label>
<div id="qid_detail_atts">-</div>
</div>
{% endif %}
<div class="btn-group dropup" data-acl="{{ acl.quarantine }}">
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.quarantine.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="qitems_single" data-item="" data-api-url='edit/qitem' data-api-attr='{"action":"release"}' href="#">{{ lang.quarantine.deliver_inbox }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="qitems_single" data-item="" data-api-url='edit/qitem' data-api-attr='{"action":"learnspam"}' href="#">{{ lang.quarantine.learn_spam_delete }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-id="qitems_single" data-item="" id="quick_download_link" href="#">{{ lang.quarantine.download_eml }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-id="qitems_single" data-item="" id="quick_release_link" href="#">{{ lang.quarantine.quick_release_link }}</a></li>
<li><a data-id="qitems_single" data-item="" id="quick_delete_link" href="#">{{ lang.quarantine.quick_delete_link }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="qitems_single" data-item="" data-api-url='delete/qitem' href="#">{{ lang.quarantine.remove }}</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,336 @@
<!-- change fido2 fn -->
<div class="modal fade" id="fido2ChangeFn" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.fido2.set_fn }}</h3>
<p class="help-block" style="word-break:break-all" id="fido2_subject_desc" data-fido2-subject=""></p>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="false" data-id="fido2ChangeFn" role="form" method="post" autocomplete="off">
<input type="hidden" class="form-control" name="fido2_cid" id="fido2_cid">
<div class="form-group">
<label class="control-label col-sm-4" for="fido2_fn">{{ lang.fido2.fn }}:</label>
<div class="col-sm-8">
<input type="text" class="form-control" name="fido2_fn">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="fido2ChangeFn" data-item="null" data-api-url='edit/fido2-fn' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add domain admin modal -->
<!-- add sync job modal -->
<div class="modal fade" id="addSyncJobModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.add.syncjob }}</h3>
</div>
<div class="modal-body">
<p>{{ lang.add.syncjob_hint }}</p>
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_syncjob">
<div class="form-group">
<label class="control-label col-sm-2" for="host1">{{ lang.add.hostname }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="host1" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="port1">{{ lang.add.port }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="port1" min="1" max="65535" value="143" required>
<small class="help-block">1-65535</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="user1">{{ lang.add.username }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="user1" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password1">{{ lang.add.password }}</label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password1" data-hibp="true" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="enc1">{{ lang.add.enc_method }}</label>
<div class="col-sm-10">
<select name="enc1" title="{{ lang.add.select }}" required>
<option value="SSL" selected>SSL</option>
<option value="TLS">STARTTLS</option>
<option value="PLAIN">PLAIN</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mins_interval">{{ lang.add.mins_interval }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mins_interval" min="1" max="43800" value="20" required>
<small class="help-block">1-43800</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="subfolder2">{{ lang.edit.subfolder2|raw }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="subfolder2" value="">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxage">{{ lang.edit.maxage|raw }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxage" min="0" max="32000" value="0">
<small class="help-block">0-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxbytespersecond">{{ lang.edit.maxbytespersecond|raw }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxbytespersecond" min="0" max="125000000" value="0">
<small class="help-block">0-125000000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="timeout1">{{ lang.edit.timeout1 }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="timeout1" min="1" max="32000" value="600">
<small class="help-block">1-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="timeout2">{{ lang.edit.timeout2 }}</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="timeout2" min="1" max="32000" value="600">
<small class="help-block">1-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="exclude">{{ lang.add.exclude }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="exclude" value="(?i)spam|(?i)junk">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="custom_params">{{ lang.add.custom_params }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="custom_params" placeholder="--delete2folders --otheroption">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2duplicates" checked> {{ lang.add.delete2duplicates }} (--delete2duplicates)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete1"> {{ lang.add.delete1 }} (--delete1)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2"> {{ lang.add.delete2 }} (--delete2)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="automap" checked> {{ lang.add.automap }} (--automap)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="skipcrossduplicates"> {{ lang.add.skipcrossduplicates }} (--skipcrossduplicates)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="subscribeall" checked> {{ lang.add.subscribeall }} (--subscribeall)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_syncjob" data-api-url='add/syncjob' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add sync job modal -->
<!-- app passwd modal -->
<div class="modal fade" id="addAppPasswdModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.add.app_password }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-pwgen-length="32" data-id="add_apppasswd">
<div class="form-group">
<label class="control-label col-sm-2" for="app_name">{{ lang.add.app_name }}</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="app_name" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="app_passwd">{{ lang.user.password }} (<a href="#" class="generate_password">{{ lang.user.generate }}</a>)</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="app_passwd" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="app_passwd2">{{ lang.user.password_repeat }}</label>
<div class="col-sm-10">
<input type="password" data-pwgen-field="true" class="form-control" name="app_passwd2" autocomplete="new-password" required>
<p class="help-block">{{ lang.user.new_password_description }}</p>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> {{ lang.add.active }}</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_apppasswd" data-api-url='add/app-passwd' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add app passwd modal -->
<!-- log modal -->
<div class="modal fade" id="syncjobLogModal" tabindex="-1" role="dialog" aria-labelledby="syncjobLogModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">Log</h3>
</div>
<div class="modal-body">
<textarea class="form-control textarea-code" rows="20" id="logText" spellcheck="false"></textarea>
</div>
</div>
</div>
</div><!-- log modal -->
<!-- pw change modal -->
<div class="modal fade" id="pwChangeModal" tabindex="-1" role="dialog" aria-labelledby="pwChangeModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.user.change_password }}</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="false" data-id="pwchange" role="form" method="post" autocomplete="off">
<div class="form-group">
<label class="control-label col-sm-3" for="user_new_pass">{{ lang.user.new_password }} (<a href="#" class="generate_password">{{ lang.user.generate }}</a>)</label>
<div class="col-sm-5">
<input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="user_new_pass" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="user_new_pass2">{{ lang.user.new_password_repeat }}</label>
<div class="col-sm-5">
<input type="password" data-pwgen-field="true" class="form-control" name="user_new_pass2" autocomplete="new-password" required>
<p class="help-block">{{ lang.user.new_password_description }}</p>
</div>
</div>
<hr>
<div class="form-group">
<label class="control-label col-sm-3" for="user_old_pass">{{ lang.user.password_now }}</label>
<div class="col-sm-5">
<input type="password" class="form-control" name="user_old_pass" autocomplete="off" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="pwchange" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#">{{ lang.user.change_password }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- pw change modal -->
<!-- pw change modal -->
<div class="modal fade" id="tempAliasModal" tabindex="-1" role="dialog" aria-labelledby="tempAliasModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<form class="form-horizontal" data-cached-form="false" data-id="pwchange" role="form" method="post" autocomplete="off">
<div class="form-group">
<label class="control-label col-sm-3" for="user_new_pass">{{ lang.user.new_password }} (<a href="#" class="generate_password">{{ lang.user.generate }}</a>)</label>
<div class="col-sm-5">
<input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="user_new_pass" autocomplete="new-password" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3" for="user_new_pass2">{{ lang.user.new_password_repeat }}</label>
<div class="col-sm-5">
<input type="password" data-pwgen-field="true" class="form-control" name="user_new_pass2" autocomplete="new-password" required>
<p class="help-block">{{ lang.user.new_password_description }}</p>
</div>
</div>
<hr>
<div class="form-group">
<label class="control-label col-sm-3" for="user_old_pass">{{ lang.user.password_now }}</label>
<div class="col-sm-5">
<input type="password" class="form-control" name="user_old_pass" autocomplete="off" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="pwchange" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#">{{ lang.user.change_password }}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- pw change modal -->
<!-- sieve filter modal -->
<div class="modal fade" id="userFilterModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">{{ lang.user.active_sieve }}</h3>
</div>
<div class="modal-body">
<pre id="user_sieve_filter"></pre>
</div>
</div>
</div>
</div><!-- sieve filter modal -->

View File

@@ -0,0 +1,64 @@
{% extends 'base.twig' %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default panel-xs-lg">
<div class="panel-heading">
{{ lang.quarantine.quarantine }} <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-xs-lg btn-default refresh_table" data-draw="draw_quarantine_table" data-table="quarantinetable">{{ lang.quarantine.refresh }}</button>
<button type="button" class="btn btn-xs btn-xs-lg btn-default dropdown-toggle" data-toggle="dropdown">{{ lang.quarantine.table_size }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" data-table-id="quarantinetable" role="menu">
<li><a href="#" data-page-size="10">{{ lang.quarantine.table_size_show_n|format(10) }}</a></li>
<li><a href="#" data-page-size="20">{{ lang.quarantine.table_size_show_n|format(20) }}</a></li>
<li><a href="#" data-page-size="50">{{ lang.quarantine.table_size_show_n|format(50) }}</a></li>
<li><a href="#" data-page-size="100">{{ lang.quarantine.table_size_show_n|format(100) }}</a></li>
<li><a href="#" data-page-size="200">{{ lang.quarantine.table_size_show_n|format(200) }}</a></li>
<li><a href="#" data-page-size="500">{{ lang.quarantine.table_size_show_n|format(500) }}</a></li>
</ul>
</div>
</div>
<p style="margin:10px" class="help-block">{{ lang.quarantine.qinfo|raw }}</p>
<p style="margin:10px">
{% if not quarantine_settings.retention_size or not quarantine_settings.max_size %}
<div class="panel-body"><div class="alert alert-info">{{ lang.quarantine.disabled_by_config }}</div></div>
{% else %}
<p style="margin:10px" class="help-block">
{{ lang.quarantine.settings_info|format(quarantine_settings.retention_size, quarantine_settings.max_size)|raw }}
</p>
{% endif %}
</p>
<div class="table-responsive">
<table id="quarantinetable" class="table table-striped"></table>
</div>
<div class="mass-actions-quarantine">
<div class="btn-group" data-acl="{{ acl.quarantine }}">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="qitems" href="#"><i class="bi bi-check-all"></i> {{ lang.quarantine.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.quarantine.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="qitems" data-api-url='edit/qitem' data-api-attr='{"action":"release"}' href="#">{{ lang.quarantine.deliver_inbox }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="qitems" data-api-url='edit/qitem' data-api-attr='{"action":"learnspam"}' href="#">{{ lang.quarantine.learn_spam_delete }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="qitems" data-api-url='delete/qitem' href="#">{{ lang.quarantine.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
</div>
</div>
</div>
</div> <!-- /col-md-12 -->
</div> <!-- /row -->
{% include 'modals/quarantine.twig' %}
<script type='text/javascript'>
var acl = '{{ acl_json|raw }}';
var lang = {{ lang_quarantine|raw }};
var csrf_token = '{{ csrf_token }}';
var pagination_size = '{{ pagination_size }}';
var role = '{{ role }}';
</script>
{% endblock %}

View File

@@ -0,0 +1,13 @@
<div id="tfa_keys">
{% if tfa_data.additional %}
{% for key_info in tfa_data.additional %}
<form style="display:inline;" method="post">
<input type="hidden" name="unset_tfa_key" value="{{ key_info.id }}">
<div style="padding:4px;margin:4px" class="label label-keys label-{% if tfa_id == key_info.id %}success{% else %}default{% endif %}">
{{ key_info.key_id }}
<a href="#" style="font-weight:bold;color:white" onClick="$(this).closest('form').submit()">[{{ lang.admin.remove }}]</a>
</div>
</form>
{% endfor %}
{% endif %}
</div>

View File

@@ -0,0 +1,34 @@
{% extends 'base.twig' %}
{% block content %}
<!-- Nav tabs -->
<ul class="nav nav-tabs responsive-tabs" role="tablist">
<li class="dropdown active">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.user.mailbox }}<span class="caret"></span></a>
<ul class="dropdown-menu">
<li role="presentation" class="active" data-dont-remember="1"><a href="#tab-user-auth" aria-controls="tab-user-auth" role="tab" data-toggle="tab">{{ lang.user.mailbox_general }}</a></li>
<li role="presentation"><a href="#tab-user-details" aria-controls="tab-config-fwdhosts" role="tab" data-toggle="tab">{{ lang.user.mailbox_details }}</a></li>
<li role="presentation"><a href="#tab-user-settings" aria-controls="tab-config-f2b" role="tab" data-toggle="tab">{{ lang.user.mailbox_settings }}</a></li>
</ul>
</li>
<li role="presentation"><a href="#SpamAliases" aria-controls="SpamAliases" role="tab" data-toggle="tab">{{ lang.user.spam_aliases }}</a></li>
<li role="presentation"><a href="#Spamfilter" aria-controls="Spamfilter" role="tab" data-toggle="tab">{{ lang.user.spamfilter }}</a></li>
<li role="presentation"><a href="#Syncjobs" aria-controls="Syncjobs" role="tab" data-toggle="tab">{{ lang.user.sync_jobs }}</a></li>
<li role="presentation"><a href="#AppPasswds" aria-controls="AppPasswds" role="tab" data-toggle="tab">{{ lang.user.app_passwds }}</a></li>
<li role="presentation"><a href="#Pushover" aria-controls="Pushover" role="tab" data-toggle="tab">Pushover API</a></li>
</ul>
<hr>
<div class="tab-content">
{% include 'user/tab-user-auth.twig' %}
{% include 'user/tab-user-details.twig' %}
{% include 'user/tab-user-settings.twig' %}
{% include 'user/SpamAliases.twig' %}
{% include 'user/Spamfilter.twig' %}
{% include 'user/Syncjobs.twig' %}
{% include 'user/AppPasswds.twig' %}
{% include 'user/Pushover.twig' %}
</div>
<div style="margin-bottom:200px;"></div>
{% include 'user_domainadmin_common.twig' %}
{% endblock %}

View File

@@ -0,0 +1,24 @@
<div role="tabpanel" class="tab-pane" id="AppPasswds">
<p>{{ lang.user.app_hint|raw }}</p>
<div class="table-responsive">
<table class="table table-striped" id="app_passwd_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.app_passwds }}">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="apppasswd" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="apppasswd" data-api-url='edit/app-passwd' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="apppasswd" data-api-url='edit/app-passwd' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="apppasswd" data-api-url='delete/app-passwd' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
</div>
<div class="btn-group">
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addAppPasswdModal"><i class="bi bi-plus-lg"></i> {{ lang.user.create_app_passwd }}</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,80 @@
<div role="tabpanel" class="tab-pane" id="Pushover">
<form data-id="pushover" class="form well" method="post">
<input type="hidden" value="0" name="evaluate_x_prio">
<input type="hidden" value="0" name="only_x_prio">
<input type="hidden" value="0" name="active">
<div class="row">
<div class="col-sm-1">
<p class="help-block"><a href="https://pushover.net" target="_blank"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAACglBMVEUAAAAAAAEAAAAilecFGigAAAAAAAAAAAAAAAANj+c3n+Ypm+oeYI4KWI4MieAtkdQbleoJcLcjmeswmN4Rit4KgdMKUYQJKUAQSnILL0kMNlMSTngimOoNPF0hlOQBBgkNOlkRS3MHIjUhk+IPf8wKLUYsjM0AAAASTngAAAAAAAAPfckbdLIbdrYUWIgegsgce70knfEAAAAknfENOVkGHi8YaaIjnvEdgMUhkuAQSG8aca0hleQUh9YLjOM4nOEMgtMcbaYWa6YemO02ltkKhNktgLodYZEPXJEyi8kKesktfLUzj84cWYMiluckZ5YJXJYeW4Y0k9YKfs4yjs0pc6YHZaUviskLfMkqmugak+cqkNcViNcqeK4Iaq4XRmYGPmYMKDsFJTstgr0LdL0ti84CCQ4BCQ4Qgc8rlt8XjN8shcQsi8wZSGgEP2cRMEUDKkUAAAD///8dmvEamfExo/EXmPEWl/ERlvElnvEsofEjnfETl/Enn/Ezo/E4pvEvovEfm/E1pPEzpPEvofEOlfEpoPEamPEQlfEYmfE6p/EgnPEVlvEroPE3pfE2pfENk/Ern/E3pPEcmfEfmvEnnvBlufT6/P0soPAknPDd7/zs9vzo9PxBqfItofAqoPD9/f3B4/q43/mx2/l/xfZ6w/Vxv/VtvfVgt/RXtPNTsfNEq/L3+/31+v3a7fvR6vvH5fqs2vmc0/jx+P3v9/3h8fzW7PvV7PvL5/q13fmo1/mh1PiY0fiNy/aHyfZ2wfVou/Vdt/RPsPM3oeoQkuowmeAgjdgcgMQbeLrw9/3k8vy74Pm63/mX0PdYtfNNr/Ikm+4wnOchkuAVjOAfdrMVcrOdoJikAAAAcnRSTlMAIQ8IzzweFwf+/fvw8P79+/Xt7e3p6eji4d7U08y8qZyTiIWDgn53bWxqaWBKQ0JBOjUwMCkoJCEfHBkT/vz8/Pv7+vr69/b29PTy7ezm5ubm5N7e29vQ0M/Pv7+4uLW1pqaWloWDg3x7e21mUVFFRUXdPracAAAEbElEQVRIx4WUZbvaQBCFF+ru7u7u7u7u7t4mvVwSoBC0JIUCLRQolLq7u7vr/+nMLkmQyvlwyfPcd86e3ZldUqwyQ/p329J+XfutPQYOLUP+q55rFtQJRvY79+xxlZTUWbKpz7/xrrMr2+3BoNPpdLn2lJQ4HEeqLOr1d7z7XNkesQed4A848G63Oy4Gmg/6Mz542QvZbqe8C/Ig73CLYiYTrtLmT3zfqbIcAR7y4wIqH/B6M9Fo0+Ldb6sM9ph/v4ozPuz12mxRofaAAr7jCNkuoz/jNf9AGHibkBCm51fsGKvxsAGWx4H+jBcEi6V2birDpCL/9Klrd1KHbiSvPWP8V0tTnTfO03iXi57P6WNHOVUf44IFdFDRz6pV5fw8Zy5z3JVH5+R48OwxqDiGvKJIY9R+9JsCuJ5HPg74OVEMpz+nbdEPUHEWeEk6IDUnTC1l5r+f8uffc0cfxc8fS17kLso24SwUPFDA/6DE82xKDOPliJ7n/GGOOyWK9zD9CdjvOfg9Dv6AH+AX04LW9gj2i8W/APx1UbxwCAu+wPmcpgUKL/EHdvtq4uwaZwCuznPJVY5LHhED15G/isd5Hz4eKui/e/du02YoKFeD5mHzHIN/nxEDe25gQQwKorAid04CfyzwL4XutXvl1Pt1guMOwwKPkU8mYIFT8JHK+vv8prpDScUVL+j8s3lOctw1GIhbWHAS+HgKPk7xPM/4UtNAYmzizJkf6NgTb/gM8jePQLsewMdthS3g95tMpT1IhVm6v1s8fYmLeb13Odwp8Fh5KY048y/d14WUrwrb1e/X/rNp73nkD8kWS+wi/MZ4XuetG4mhKubJm3/WNEvi8SHwB56nPKjUam0LBdp9ARwupFemTYudvgN/L1+A/Ko/LGBuS8pPy+YR1fuCTWNKnUyoeUyYx2o2dyEVGmr5xTD42xzvkD16+Pb9WIIH6fmt1r3mbsTY7Bvw+n23naT8BUWh86bz6G/e259UXPUK3gfAxQDlo7Rpx3Geqb2e3wp83SGEdKpB7zvwYbzvT2n65xLwbH6YP+M9C8vA8E1wxLU8gkCbdhXGUyrMgwVrcbzLHonr78lzDvWM3q/C/HtDlXoSUIe3YkblhRPIX4E8Oo/9siLv8dRjV7SBlkdgTXvKS7nzsA/9AfeEuhKq9T8zWIDv1Sd6ETAP4D6/H/1V+1BojvruNa4SZXz4JhY84dV5MOF5agUvu5OsOo+KRpG30KalEnoeDccFlutPZYs38D5n3zcpr1/0fBhfb3DOY1z2tSAgLxWezz6zuoHhfUmOejf6blHQH/sFuJYfcMZX307ytKvRa3ifoV/586P5j+tICtS77BuJxzxYAPZsntX8k3eSIhlajK4p8b7iefCEKs03kD/I2LnxL9ovH+43y4fAv1YrI/mzDBsavAX/UppfzVOrZT/ydxk6lJ047MfLfVbcb6hS9ZEzWxekKQ5WrtPqZg3rV6tWrX6Tle3KQZj/q6KxQnmDoXwFY0VSrN9e8FRXBCTAvwAAAABJRU5ErkJggg==" class="img img-fluid"></a></p>
</div>
<div class="col-sm-10">
<p class="help-block">{{ lang.user.pushover_info|format(mailcow_cc_username)|raw }}</p>
<p class="help-block">{{ lang.user.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code></p>
<div class="form-group">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="token">API Token/Key (Application)</label>
<input type="text" class="form-control" name="token" maxlength="30" value="{{ pushover_data.token }}" required>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="key">User/Group Key</label>
<input type="text" class="form-control" name="key" maxlength="30" value="{{ pushover_data.key }}" required>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="title">{{ lang.user.pushover_title }}</label>
<input type="text" class="form-control" name="title" value="{{ pushover_data.title }}" placeholder="Mail">
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="text">{{ lang.user.pushover_text }}</label>
<input type="text" class="form-control" name="text" value="{{ pushover_data.text }}" placeholder="You've got mail 📧">
</div>
</div>
<div class="col-sm-12">
<div class="form-group">
<label for="text">{{ lang.user.pushover_sender_array|raw }}</label>
<input type="text" class="form-control" name="senders" value="{{ pushover_data.token }}" placeholder="sender1@example.com, sender2@example.com">
</div>
</div>
<div class="col-sm-12">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active"{% if pushover_data.active == '1' %} checked{% endif %}> {{ lang.user.active }}</label>
</div>
</div>
<div class="col-sm-12">
<legend style="cursor:pointer;margin-top:10px" data-target="#po_advanced" unselectable="on" data-toggle="collapse">
<i style="font-size:10pt;" class="bi bi-plus-square"></i> {{ lang.user.advanced_settings }}
</legend>
</div>
<div class="col-sm-12">
<div id="po_advanced" class="collapse">
<div class="form-group">
<label for="text">{{ lang.user.pushover_sender_regex }}</label>
<input type="text" class="form-control" name="senders_regex" value="{{ pushover_data.senders_regex }}" placeholder="/(.*@example\.org$|^foo@example\.com$)/i" regex="true">
<div class="checkbox">
<label><input type="checkbox" value="1" name="evaluate_x_prio"{% if pushover_data.attributes.evaluate_x_prio == '1' %} checked{% endif %}> {{ lang.user.pushover_evaluate_x_prio|raw }}</label>
</div>
<div class="checkbox">
<label><input type="checkbox" value="1" name="only_x_prio"{% if pushover_data.attributes.only_x_prio == '1' %} checked{% endif %}> {{ lang.user.pushover_only_x_prio|raw }}</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="btn-group mass-actions-user" data-acl="{{ acl.pushover }}">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected" data-id="pushover" data-item="{{ mailcow_cc_username }}" data-api-url='edit/pushover' data-api-attr='{}' href="#">{{ lang.user.save }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected" data-id="pushover-test" data-item="{{ mailcow_cc_username }}" data-api-url='edit/pushover-test' data-api-attr='{}' href="#"><i class="bi bi-check-all"></i> {{ lang.user.pushover_verify }}</a>
<div class="clearfix visible-xs"></div>
<a id="pushover_delete" class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger" data-action="edit_selected" data-id="pushover-delete" data-item="{{ mailcow_cc_username }}" data-api-url='edit/pushover' data-api-attr='{"delete":"true"}' href="#"><i class="bi bi-trash"></i> {{ lang.user.remove }}</a>
</div>
</div>
</div>
</form>
</div>

View File

@@ -0,0 +1,40 @@
<div role="tabpanel" class="tab-pane" id="SpamAliases">
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="table-responsive">
<table class="table table-striped" id="tla_table"></table>
</div>
</div>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.spam_alias }}">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="tla" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"1"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.hour }}</a></li>
<li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"24"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.day }}</a></li>
<li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"168"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.week }}</a></li>
<li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"744"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.month }}</a></li>
<li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"8760"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.year }}</a></li>
<li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"87600"}' href="#">{{ lang.user.expire_in }} 10 {{ lang.user.years }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="tla" data-api-url='delete/time_limited_alias' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs-block"></div>
</div>
<div class="btn-group">
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success dropdown-toggle" data-toggle="dropdown" href="#"><i class="bi bi-plus-lg"></i> {{ lang.user.alias_create_random }}, 1 {{ lang.user.year }} <span class="caret"></span></a>
<ul class="dropdown-menu">
{% for domain in user_domains %}
<li>
<a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"domain":"{{ domain }}"}' href="#">
@ {{ domain }}
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,79 @@
<div role="tabpanel" class="tab-pane" id="Spamfilter">
<h4>{{ lang.user.spamfilter_behavior }}</h4>
<div class="row">
<div class="col-sm-12">
<form class="form-horizontal" role="form" data-id="spam_score" method="post">
<div class="form-group">
<div class="col-lg-8 col-sm-12">
<div id="spam_score" data-provide="slider" data-acl="{{ acl.spam_score }}"></div>
<input id="spam_score_value" name="spam_score" type="hidden" value="{{ user_spam_score }}">
<ul class="list-group list-group-flush">
<li class="list-group-item"><span class="label label-ham spam-ham-score"></span> {{ lang.user.spamfilter_green }}</li>
<li class="list-group-item"><span class="label label-spam spam-spam-score"></span> {{ lang.user.spamfilter_yellow }}</li>
<li class="list-group-item"><span class="label label-reject spam-reject-score"></span> {{ lang.user.spamfilter_red }}</li>
</ul>
</div>
</div>
<div class="btn-group" data-acl="{{ acl.spam_score }}">
<a type="button" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="spam_score"
data-api-url='edit/spam-score'
data-api-attr='{}'><i class="bi bi-save"></i> {{ lang.user.save_changes }}</a>
<a type="button" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="spam_score_reset"
data-api-url='edit/spam-score'
data-api-attr='{"spam_score":"default"}'>{{ lang.user.spam_score_reset }}</a>
</div>
</form>
</div>
</div>
<hr>
<div class="row">
<div class="col-sm-6">
<h4>{{ lang.user.spamfilter_wl }}</h4>
<p>{{ lang.user.spamfilter_wl_desc|raw }}</p>
<form class="form-inline space20" data-id="add_wl_policy_mailbox">
<div class="input-group" data-acl="{{ acl.spam_policy }}">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-default" data-action="add_item" data-id="add_wl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username": {{ mailcow_cc_username|json_encode|raw }},"object_list":"wl"}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.user.spamfilter_table_add }}</button>
</span>
</div>
</form>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="wl_policy_mailbox_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.spam_policy }}">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="policy_wl_mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger" data-action="delete_selected" data-id="policy_wl_mailbox" data-api-url='delete/mailbox-policy' href="#">{{ lang.mailbox.remove }}</a>
<div class="clearfix visible-xs-block"></div>
</div>
</div>
</div>
<div class="col-sm-6">
<h4>{{ lang.user.spamfilter_bl }}</h4>
<p>{{ lang.user.spamfilter_bl_desc|raw }}</p>
<form class="form-inline space20" data-id="add_bl_policy_mailbox">
<div class="input-group" data-acl="{{ acl.spam_policy }}">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-default" data-action="add_item" data-id="add_bl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username": {{ mailcow_cc_username|json_encode|raw }},"object_list":"bl"}' href="#"><i class="bi bi-plus-lg"></i> {{ lang.user.spamfilter_table_add }}</button>
</span>
</div>
</form>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="bl_policy_mailbox_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.spam_policy }}">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="policy_bl_mailbox" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-danger" data-action="delete_selected" data-id="policy_bl_mailbox" data-api-url='delete/mailbox-policy' href="#">{{ lang.mailbox.remove }}</a>
<div class="clearfix visible-xs-block"></div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,23 @@
<div role="tabpanel" class="tab-pane" id="Syncjobs">
<div class="table-responsive">
<table class="table table-striped" id="sync_job_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="{{ acl.syncjobs }}">
<div class="btn-group">
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
<a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
<li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="syncjob" data-api-url='delete/syncjob' href="#">{{ lang.mailbox.remove }}</a></li>
</ul>
<div class="clearfix visible-xs"></div>
</div>
<div class="btn-group">
<a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModal"><i class="bi bi-plus-lg"></i> {{ lang.user.create_syncjob }}</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,114 @@
<div role="tabpanel" class="tab-pane active" id="tab-user-auth">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.user.mailbox_general }}</div>
<div class="panel-body">
{% if not skip_sogo %}
<div class="row">
<div class="hidden-xs col-md-3 col-xs-5 text-right"></div>
<div class="col-md-3 col-xs-12">
<a target="_blank" href="/sogo-auth.php?login={{ mailcow_cc_username }}" role="button" class="btn btn-default btn-block btn-xs-lg">
<i class="bi bi-inbox-fill"></i> {{ lang.user.open_webmail_sso }}
</a>
</div>
</div>
<hr>
{% endif %}
<div class="row">
<div class="col-md-3 col-xs-12 text-right text-xs-left space20">{{ lang.user.in_use }}:</div>
<div class="col-md-5 col-xs-12">
<div class="progress">
<div class="progress-bar progress-bar-{{ mailboxdata.percent_class }}" role="progressbar" aria-valuenow="{{ mailboxdata.percent_in_use }}" aria-valuemin="0" aria-valuemax="100" style="min-width:2em;width: {{ mailboxdata.percent_in_use }}%;">
{{ mailboxdata.percent_in_use }}%
</div>
</div>
<p>{{ mailboxdata.quota_used|formatBytes(2) }} / {% if mailboxdata.quota == 0 %}{% else %}{{ mailboxdata.quota|formatBytes(2) }}{% endif %}<br>{{ mailboxdata.messages }} {{ lang.user.messages }}</p>
<hr>
<p><a href="#pwChangeModal" data-toggle="modal"><i class="bi bi-pencil-fill"></i> {{ lang.user.change_password }}</a></p>
</div>
</div>
<hr>
{# FIDO2 #}
<div class="row">
<div class="col-sm-3 col-xs-12 text-right text-xs-left">
<p><i class="bi bi-shield-fill-check"></i> {{ lang.fido2.fido2_auth }}</p>
</div>
</div>
<div class="row">
<div class="col-sm-3 col-xs-12 text-right text-xs-left space20">
{{ lang.fido2.known_ids }}:
</div>
<div class="col-sm-9 col-xs-12">
<div class="table-responsive">
<table class="table table-striped table-hover table-condensed" id="fido2_keys">
<tr>
<th>ID</th>
<th style="min-width:240px;text-align: right">{{ lang.admin.action }}</th>
</tr>
{% include 'fido2.twig' %}
</table>
</div>
<br>
</div>
</div>
<div class="row">
<div class="col-sm-offset-3 col-sm-9">
<div class="btn-group">
<button class="btn btn-sm btn-primary visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline" id="register-fido2">{{ lang.fido2.set_fido2 }}</button>
<button type="button" class="btn btn-sm btn-xs-lg btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" id="register-fido2-touchid" style="line-height:1.4;"><i class="bi bi-shield-fill-check"></i> {{ lang.fido2.set_fido2_touchid }}</a></li>
</ul>
</div>
</div>
</div>
<br>
<div class="row" id="status-fido2">
<div class="col-sm-3 col-xs-5 text-right">{{ lang.fido2.register_status }}:</div>
<div class="col-sm-9 col-xs-7">
<div id="fido2-alerts">-</div>
</div>
<br>
</div>
<hr>
<div class="row">
<div class="col-md-3 col-xs-12 text-right text-xs-left space20"><i class="bi bi-file-earmark-text"></i> {{ lang.user.apple_connection_profile }}:</div>
<div class="col-md-9 col-xs-12">
<p><i class="bi bi-file-earmark-post"></i> <a href="/mobileconfig.php?only_email">{{ lang.user.email }}</a> <small>IMAP, SMTP</small></p>
<p class="help-block">{{ lang.user.apple_connection_profile_mailonly }}</p>
{% if not skip_sogo %}
<p><i class="bi bi-file-earmark-post"></i> <a href="/mobileconfig.php">{{ lang.user.email_and_dav }}</a> <small>IMAP, SMTP, Cal/CardDAV</small></p>
<p class="help-block">{{ lang.user.apple_connection_profile_complete }}</p>
{% endif %}
</div>
</div>
<hr>
<div class="row">
<div class="col-sm-offset-3 col-sm-9">
{% if mailboxdata.attributes.force_pw_update == '1' %}
<div class="alert alert-danger">{{ lang.user.force_pw_update }}</div>
{% endif %}
<p><a target="_blank" href="https://mailcow.github.io/mailcow-dockerized-docs/client/#{{ clientconfigstr }}">[{{ lang.user.client_configuration }}]</a></p>
<p><a href="#userFilterModal" data-toggle="modal">[{{ lang.user.show_sieve_filters }}]</a></p>
<hr>
<h4 class="recent-login-success pull-left">{{ lang.user.recent_successful_connections }}</h4>
<div class="dropdown pull-left pull-xs-right">
<button class="btn btn-default btn-xs btn-xs-lg dropdown-toggle" type="button" id="history_sasl_days" data-toggle="dropdown">{{ lang.user.login_history }} <span class="caret"></span></button>
<ul class="dropdown-menu">
<li class="login-history active" data-days="1"><a href="#">1 {{ lang.user.day }}</a></li>
<li class="login-history" data-days="7"><a href="#">1 {{ lang.user.week }}</a></li>
<li class="login-history" data-days="14"><a href="#">2 {{ lang.user.weeks }}</a></li>
<li class="login-history" data-days="31"><a href="#">1 {{ lang.user.month }}</a></li>
</ul>
</div>
<div class="clearfix"></div>
<div class="last-login"></div>
<span class="clear-last-logins">
{{ lang.user.clear_recent_successful_connections }}
</span>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,67 @@
<div role="tabpanel" class="tab-pane" id="tab-user-details">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.user.mailbox_details }}</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-4 col-md-3 col-xs-12 text-right text-xs-left"><i class="bi bi-pin-angle"></i> {{ lang.user.direct_aliases }}:
<p class="small">{{ lang.user.direct_aliases_desc }}</p>
</div>
<div class="col-sm-8 col-md-9 col-xs-12">
{% for direct_alias, direct_alias_meta in user_get_alias_details.direct_aliases %}
{% if direct_alias_meta.public_comment %}
{{ direct_alias }} &mdash; <i class="bi bi-chat-left"></i> {{ direct_alias_meta.public_comment }}<br>
{% else %}
{{ direct_alias }}<br>
{% endif %}
{% else %}
<i class="bi bi-x-lg"></i>
{% endfor %}
</div>
</div>
<br>
<div class="row">
<div class="col-sm-4 col-md-3 col-xs-12 text-right text-xs-left"><i class="bi bi-share"></i> {{ lang.user.shared_aliases }}:
<p class="small">{{ lang.user.shared_aliases_desc }}</p>
</div>
<div class="col-sm-8 col-md-9 col-xs-12">
{% for shared_alias, shared_alias_meta in user_get_alias_details.shared_aliases %}
{% if shared_alias_meta.public_comment %}
{{ shared_alias }} &mdash; <i class="bi bi-chat-left"></i> {{ shared_alias_meta.public_comment }}<br>
{% else %}
{{ shared_alias }}<br>
{% endif %}
{% else %}
<i class="bi bi-x-lg"></i>
{% endfor %}
</div>
</div>
<hr>
<div class="row">
<div class="col-sm-4 col-md-3 col-xs-12 text-right text-xs-left space20">{{ lang.user.aliases_also_send_as }}:</div>
<div class="col-sm-8 col-md-9 col-xs-12">
<p>
{% if user_get_alias_details.aliases_also_send_as == '*' %}
{{ lang.user.sender_acl_disabled }}
{% elseif user_get_alias_details.aliases_also_send_as %}
{{ user_get_alias_details.aliases_also_send_as }}
{% else %}
<i class="bi bi-x-lg"></i>
{% endif %}
</p>
</div>
</div>
<div class="row">
<div class="col-sm-4 col-md-3 col-xs-12 text-right text-xs-left space20">{{ lang.user.aliases_send_as_all }}:</div>
<div class="col-sm-8 col-md-9 col-xs-12">
<p>{% if not user_get_alias_details.aliases_send_as_all %}<i class="bi bi-x-lg"></i>{% endif %}</p>
</div>
</div>
<div class="row">
<div class="col-sm-4 col-md-3 col-xs-12 text-right text-xs-left space20">{{ lang.user.is_catch_all }}:</div>
<div class="col-sm-8 col-md-9 col-xs-12">
<p>{% if not user_get_alias_details.is_catch_all %}<i class="bi bi-x-lg"></i>{% endif %}</p>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,136 @@
<div role="tabpanel" class="tab-pane" id="tab-user-settings">
<div class="panel panel-default">
<div class="panel-heading">{{ lang.user.mailbox_settings }}</div>
<div class="panel-body">
{# Show tagging options #}
<div class="row">
<div class="col-sm-3 col-xs-12 text-right text-xs-left text-xs-bold space20">{{ lang.user.tag_handling }}:</div>
<div class="col-sm-9 col-xs-12">
<div class="btn-group" data-acl="{{ acl.delimiter_action }}">
<button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if get_tagging_options == 'subfolder' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"subfolder"}'>{{ lang.user.tag_in_subfolder }}</button>
<button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if get_tagging_options == 'subject' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"subject"}'>{{ lang.user.tag_in_subject }}</button>
<button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if get_tagging_options == 'none' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"none"}'>{{ lang.user.tag_in_none }}</button>
<div class="clearfix visible-xs"></div>
</div>
<p class="help-block">{{ lang.user.tag_help_explain|raw }}</p>
<p class="help-block">{{ lang.user.tag_help_example|raw }}</p>
</div>
</div>
{# Show TLS policy options #}
<div class="row">
<div class="col-sm-3 col-xs-12 text-right text-xs-left text-xs-bold space20">{{ lang.user.tls_policy }}:</div>
<div class="col-sm-9 col-xs-12">
<div class="btn-group" data-acl="{{ acl.tls_policy }}">
<button type="button" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if get_tls_policy.tls_enforce_in == '1' %} active"{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_in": {% if get_tls_policy.tls_enforce_in == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_in }}</button>
<button type="button" class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if get_tls_policy.tls_enforce_out == '1' %} active"{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_out": {% if get_tls_policy.tls_enforce_out == '1' %}0{% else %}1{% endif %} }'>{{ lang.user.tls_enforce_out }}</button>
<div class="clearfix visible-xs"></div>
</div>
<p class="help-block">{{ lang.user.tls_policy_warning|raw }}</p>
</div>
</div>
{# Show quarantine_notification options #}
<div class="row">
<div class="col-sm-3 col-xs-12 text-right text-xs-left text-xs-bold space20">{{ lang.user.quarantine_notification }}:</div>
<div class="col-sm-9 col-xs-12">
<div class="btn-group" data-acl="{{ acl.quarantine_notification }}">
<button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_notification == 'never' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"never"}'>{{ lang.user.never }}</button>
<button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_notification == 'hourly' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"hourly"}'>{{ lang.user.hourly }}</button>
<button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_notification == 'daily' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"daily"}'>{{ lang.user.daily }}</button>
<button type="button" class="btn btn-sm btn-xs-quart visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_notification == 'weekly' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_notification"
data-api-url='edit/quarantine_notification'
data-api-attr='{"quarantine_notification":"weekly"}'>{{ lang.user.weekly }}</button>
<div class="clearfix visible-xs"></div>
</div>
<p class="help-block">{{ lang.user.quarantine_notification_info }}</p>
</div>
</div>
<div class="row">
<div class="col-sm-3 col-xs-12 text-right text-xs-left text-xs-bold space20">{{ lang.user.quarantine_category }}:</div>
<div class="col-sm-9 col-xs-12">
<div class="btn-group" data-acl="{{ acl.quarantine_category }}">
<button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_category == 'reject' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"reject"}'>{{ lang.user.q_reject }}</button>
<button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_category == 'add_header' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"add_header"}'>{{ lang.user.q_add_header }}</button>
<button type="button" class="btn btn-sm btn-xs-third visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default{% if quarantine_category == 'all' %} active{% endif %}"
data-action="edit_selected"
data-item="{{ mailcow_cc_username }}"
data-id="quarantine_category"
data-api-url='edit/quarantine_category'
data-api-attr='{"quarantine_category":"all"}'>{{ lang.user.q_all }}</button>
<div class="clearfix visible-xs"></div>
</div>
<p class="help-block">{{ lang.user.quarantine_category_info }}</p>
</div>
</div>
{% if not skip_sogo %}
<hr>
<div class="row">
<div class="col-sm-3 col-xs-12 text-right text-xs-left text-xs-bold space20">{{ lang.user.eas_reset }}:</div>
<div class="col-sm-9 col-xs-12">
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-acl="{{ acl.eas_reset }}" data-action="delete_selected" data-text="{{ lang.user.eas_reset }}?" data-item="{{ mailcow_cc_username }}" data-id="eas_cache" data-api-url='delete/eas_cache' href="#">{{ lang.user.eas_reset_now }}</button>
<p class="help-block">{{ lang.user.eas_reset_help|raw }}</p>
</div>
</div>
<div class="row">
<div class="col-sm-3 col-xs-12 text-right text-xs-left text-xs-bold space20">{{ lang.user.sogo_profile_reset }}:</div>
<div class="col-sm-9 col-xs-12">
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-acl="{{ acl.sogo_profile_reset }}" data-action="delete_selected" data-text="{{ lang.user.sogo_profile_reset }}?" data-item="{{ mailcow_cc_username }}" data-id="sogo_profile" data-api-url='delete/sogo_profile' href="#">{{ lang.user.sogo_profile_reset_now }}</button>
<p class="help-block">{{ lang.user.sogo_profile_reset_help|raw }}</p>
</div>
</div>
{% endif %}
</div>
</div>
</div>

View File

@@ -0,0 +1,10 @@
{% include 'modals/user.twig' %}
<script type='text/javascript'>
var acl = '{{ acl_json|raw }}';
var lang = {{ lang_user|raw }};
var csrf_token = '{{ csrf_token }}';
var pagination_size = '{{ pagination_size }}';
var mailcow_cc_username = '{{ mailcow_cc_username }}';
var user_spam_score = [{{ user_spam_score }}];
</script>