mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-10-28 20:23:26 +00:00
[Web][Dovecot][SOGo][DockerApi] Add mailbox groups, shared mailboxes and identity provider sync
This commit is contained in:
82 files changed
+6488
-1027
No files matched your search
@@ -0,0 +1,41 @@
|
||||
{# Redirect URLs of the OIDC forms (iam_form = keycloak|generic); row markup is used by addRedirectUrlRow() in admin.js #}
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_redirect_url }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<div class="row mx-0 align-items-center">
|
||||
<span class="col-10 p-0 pe-2">
|
||||
<input type="text" class="form-control" name="redirect_url" value="{{ iam_settings.redirect_url }}" required>
|
||||
</span>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary ms-auto iam_redirect_add_{{ iam_form }}" title="{{ lang.admin.iam_redirect_url_add }}"><i class="bi bi-plus-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2" id="iam_{{ iam_form }}_redirect_list">
|
||||
<input type="hidden" name="redirect_url_extra" value="">
|
||||
{% for key, url in iam_settings.redirect_url_extra %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row mx-0">
|
||||
<div class="col-10 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="redirect_url_extra" value="{{ iam_settings.redirect_url_extra[key] }}">
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_{{ iam_form }}_redirect_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row mx-0">
|
||||
<div class="col-10 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="redirect_url_extra" value="">
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_{{ iam_form }}_redirect_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,153 @@
|
||||
{# Sync and group settings of the Keycloak and LDAP forms (iam_form = keycloak|ldap) #}
|
||||
<legend class="fs-5 mt-4"><i class="bi bi-arrow-repeat"></i> {{ lang.admin.iam_section_sync }}</legend><hr>
|
||||
{% if iam_form == 'keycloak' %}
|
||||
<div class="row mb-2">
|
||||
<div class="offset-md-3 col-12 col-md-9">
|
||||
<small class="text-muted">{{ lang.admin.iam_extra_permission|raw }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_import_users_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_import_users }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="import_users" value="1" {% if iam_settings.import_users == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_periodic_full_sync_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_periodic_full_sync }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="periodic_sync" value="1" {% if iam_settings.periodic_sync == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_offboarding_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_offboarding }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="offboarding" value="1" {% if iam_settings.offboarding == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_sync_interval }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input class="form-control" type="number" min="1" name="sync_interval" style="width: 80px;" value="{{ iam_settings.sync_interval ?: 15 }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_offboarding_limit_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_offboarding_limit }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input class="form-control" type="number" min="0" max="100" name="offboarding_limit" style="width: 80px;" value="{{ iam_settings.offboarding_limit ?? 10 }}">
|
||||
</div>
|
||||
</div>
|
||||
<legend class="fs-5 mt-4"><i class="bi bi-people"></i> {{ lang.admin.iam_section_groups }}</legend><hr>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_group_sync_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_group_sync }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="group_sync" value="1" {% if iam_settings.group_sync == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if iam_form == 'keycloak' %}
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_group_paths_info }}"></i>
|
||||
<label class="control-label" for="iam_{{ iam_form }}_group_paths">{{ lang.admin.iam_group_paths }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="/mailcow/*" id="iam_{{ iam_form }}_group_paths" name="group_paths" value="{{ iam_settings.group_paths }}">
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_{{ iam_form }}_group_basedn">{{ lang.admin.iam_group_basedn }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="{{ lang.admin.iam_basedn }}" id="iam_{{ iam_form }}_group_basedn" name="group_basedn" value="{{ iam_settings.group_basedn }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_{{ iam_form }}_group_filter">{{ lang.admin.iam_group_filter }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="(&(objectClass=group)(cn=mailcow-*))" id="iam_{{ iam_form }}_group_filter" name="group_filter" value="{{ iam_settings.group_filter }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_{{ iam_form }}_group_name_attribute">{{ lang.admin.iam_group_name_attribute }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="cn" id="iam_{{ iam_form }}_group_name_attribute" name="group_name_attribute" value="{{ iam_settings.group_name_attribute }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_ldap_group_member_mode">{{ lang.admin.iam_group_member_mode }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<select id="iam_ldap_group_member_mode" name="group_member_mode" class="form-control">
|
||||
{% for mode in ['memberof', 'member', 'ad_chain'] %}
|
||||
<option value="{{ mode }}" {% if (iam_settings.group_member_mode ?: 'memberof') == mode %}selected{% endif %}>{{ attribute(lang.admin, 'iam_group_member_mode_' ~ mode) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_group_member_attribute_info }}"></i>
|
||||
<label class="control-label" for="iam_{{ iam_form }}_group_member_attribute">{{ lang.admin.iam_group_member_attribute }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="member" id="iam_{{ iam_form }}_group_member_attribute" name="group_member_attribute" value="{{ iam_settings.group_member_attribute }}">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_group_autocreate_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_group_autocreate }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="group_autocreate" value="1" {% if iam_settings.group_autocreate is not defined or iam_settings.group_autocreate == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_group_default_domain_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_group_default_domain }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<select data-live-search="true" name="group_default_domain" class="form-control" title="-- {{ lang.admin.iam_group_default_domain }} --">
|
||||
<option value="" {% if not iam_settings.group_default_domain %}selected{% endif %}>-- {{ lang.admin.iam_group_default_domain }} --</option>
|
||||
{% for domain in domains %}
|
||||
<option {% if domain == iam_settings.group_default_domain %}selected{% endif %}>{{ domain }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,30 @@
|
||||
{# Status of the identity sync (Keycloak and LDAP), filled by js/site/identity.js #}
|
||||
<div class="card mt-4" id="iam_sync_status">
|
||||
<div class="card-header d-flex flex-wrap align-items-center">
|
||||
<span class="me-2">{{ lang.admin.iam_sync_status }}</span>
|
||||
<div class="btn-group ms-auto">
|
||||
<button class="btn btn-sm btn-secondary iam_sync_request" data-mode="preview"><i class="bi bi-eye"></i> {{ lang.admin.iam_sync_preview }}</button>
|
||||
<button class="btn btn-sm btn-primary iam_sync_request" data-mode="run"><i class="bi bi-play"></i> {{ lang.admin.iam_sync_run }}</button>
|
||||
<button class="btn btn-sm btn-danger iam_sync_request" data-mode="force"><i class="bi bi-exclamation-triangle"></i> {{ lang.admin.iam_sync_force }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted"><small>{{ lang.admin.iam_sync_status_info }}</small></p>
|
||||
<div id="iam_sync_counts" class="mb-3"></div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-striped mb-0" id="iam_sync_runs">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ lang.admin.iam_sync_started }}</th>
|
||||
<th>{{ lang.admin.iam_sync_mode }}</th>
|
||||
<th>{{ lang.admin.iam_sync_result }}</th>
|
||||
<th>{{ lang.admin.iam_sync_changes }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td colspan="4" class="text-muted">{{ lang.admin.iam_sync_none }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,72 @@
|
||||
{# Default template and attribute mapping of all IdP forms (iam_form = keycloak|generic|ldap); row markup is used by
|
||||
addAttributeMappingRow() in admin.js #}
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_default_template_description }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_default_template }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<select data-live-search="true" name="default_template" class="form-control" title="-- {{ lang.mailbox.template }} --">
|
||||
<option value="" {% if not iam_settings.default_template %}selected{% endif %}>-- {{ lang.mailbox.template }} --</option>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option {% if mbox_template.template == iam_settings.default_template %}selected{% endif %}>{{ mbox_template.template }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_mapping_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_mapping }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<div class="row mx-0 align-items-center">
|
||||
<span class="col-5 p-0 pe-2 text-muted">{{ lang.user.attribute }}</span>
|
||||
<span class="col-5 p-0 pe-2 text-muted">{{ lang.mailbox.template }}</span>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary ms-auto iam_rolemap_add_{{ iam_form }}" title="{{ lang.admin.iam_mapping_add }}"><i class="bi bi-plus-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2" id="iam_{{ iam_form }}_mapping_list">
|
||||
<input type="hidden" name="mappers" value="">
|
||||
<input type="hidden" name="templates" value="">
|
||||
{% for key, role in iam_settings.mappers %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row mx-0">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="mappers" value="{{ iam_settings.mappers[key] }}" required>
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<select data-live-search="true" name="templates" class="form-control" title="-- {{ lang.mailbox.template }} --" required>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option{% if mbox_template.template == iam_settings.templates[key] %} selected{% endif %}>{{ mbox_template.template }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_{{ iam_form }}_rolemap_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row mx-0">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="mappers" value="">
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<select data-live-search="true" name="templates" class="form-control" title="-- {{ lang.mailbox.template }} --">
|
||||
<option value="" selected>-- {{ lang.mailbox.template }} --</option>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option>{{ mbox_template.template }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_{{ iam_form }}_rolemap_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -10,7 +10,7 @@
|
||||
<p class="offset-sm-3 mb-4">{{ lang.admin.iam_description|raw }}</p>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_realm">{{ lang.admin.iam }}:</label>
|
||||
<label class="control-label" for="iam_provider">{{ lang.admin.iam }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<select
|
||||
@@ -24,15 +24,17 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{# Keycloak #}
|
||||
<div id="keycloak_settings" class="{% if iam_settings.authsource and iam_settings.authsource != 'keycloak' %}d-none{% endif %}">
|
||||
<form class="form-horizontal" autocapitalize="none" data-id="iam_keycloak" autocorrect="off" role="form" method="post">
|
||||
<input type="hidden" name="authsource" value="keycloak">
|
||||
<legend class="fs-5 mt-2"><i class="bi bi-plug"></i> {{ lang.admin.iam_section_connection }}</legend><hr>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_keycloak_url">{{ lang.admin.iam_server_url }}:</label>
|
||||
<label class="control-label" for="iam_keycloak_url">{{ lang.admin.iam_server_url }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" id="iam_keycloak_url" name="server_url" value="{{ iam_settings.server_url }}" required>
|
||||
<input type="text" class="form-control" id="iam_keycloak_url" name="server_url" value="{{ iam_settings.server_url }}" placeholder="https://auth.example.org" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
@@ -43,6 +45,14 @@
|
||||
<input type="text" class="form-control" id="iam_keycloak_realm" name="realm" value="{{ iam_settings.realm }}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_keycloak_version">{{ lang.admin.iam_version }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" id="iam_keycloak_version" name="version" value="{{ iam_settings.version }}" placeholder="26.0.0" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_keycloak_clientid">{{ lang.admin.iam_client_id }}:</label>
|
||||
@@ -62,215 +72,62 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_redirect_url }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<div class="row px-2 align-items-center">
|
||||
<span class="col-10 p-0 pe-2">
|
||||
<input type="text" class="form-control" name="redirect_url" value="{{ iam_settings.redirect_url }}" required>
|
||||
</span>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary ms-auto iam_redirect_add_keycloak"><i class="bi bi-plus-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2" id="iam_keycloak_redirect_list">
|
||||
<input type="hidden" name="redirect_url_extra" value="">
|
||||
{% for key, url in iam_settings.redirect_url_extra %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-10 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="redirect_url_extra" value="{{ iam_settings.redirect_url_extra[key] }}">
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_keycloak_redirect_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-10 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="redirect_url_extra" value="">
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_keycloak_redirect_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_keycloak_version">{{ lang.admin.iam_version }}:</label>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" id="iam_keycloak_version" name="version" value="{{ iam_settings.version }}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_mapping }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<div class="row px-2 align-items-center">
|
||||
<span class="col-5 p-0 pe-2">{{ lang.user.attribute }}</span>
|
||||
<span class="col-5 p-0 pe-2">{{ lang.mailbox.template }}</span>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary ms-auto iam_rolemap_add_keycloak"><i class="bi bi-plus-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2" id="iam_keycloak_mapping_list">
|
||||
<input type="hidden" name="mappers" value="">
|
||||
<input type="hidden" name="templates" value="">
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_default_template_description }}"></i>
|
||||
<span>{{ lang.admin.iam_default_template}}</span>
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2 align-content-end">
|
||||
<select data-live-search="true" name="default_template" class="form-control" title="-- {{ lang.mailbox.template }} --">
|
||||
<option value="" {% if not iam_settings.default_template %}selected{% endif %}>-- {{ lang.mailbox.template }} --</option>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option {% if mbox_template.template == iam_settings.default_template %}selected{% endif %}>
|
||||
{{ mbox_template.template }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% for key, role in iam_settings.mappers %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="mappers" value="{{ iam_settings.mappers[key] }}" required>
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<select data-live-search="true" name="templates" class="form-control" title="-- {{ lang.mailbox.template }} --" required>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option{% if mbox_template.template == iam_settings.templates[key] %} selected{% endif %}>
|
||||
{{ mbox_template.template }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_keycloak_rolemap_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="mappers" value="">
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<select data-live-search="true" name="templates" class="form-control" title="-- {{ lang.mailbox.template }} --">
|
||||
<option value="" selected>-- {{ lang.mailbox.template }} --</option>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option>
|
||||
{{ mbox_template.template }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_keycloak_rolemap_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2 mt-4">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end"></div>
|
||||
<div class="col-12 col-md-9">
|
||||
<span>{{ lang.admin.iam_extra_permission|raw }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-start justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_rest_flow }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="mailpassword_flow" value="1" {% if iam_settings.mailpassword_flow == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
<p class="text-muted">
|
||||
<small>
|
||||
{{ lang.admin.iam_auth_flow_info|raw }}
|
||||
</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.ignore_ssl_error }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="ignore_ssl_error" value="1" {% if iam_settings.ignore_ssl_error == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="offset-md-3 col-12 col-md-9">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary iam_test_connection" data-id="iam_keycloak"><i class="bi bi-play"></i> {{ lang.admin.iam_test_connection }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<legend class="fs-5 mt-4"><i class="bi bi-box-arrow-in-right"></i> {{ lang.admin.iam_section_login }}</legend><hr>
|
||||
{% include 'admin/iam-redirect-urls.twig' with {'iam_form': 'keycloak'} %}
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_auth_flow_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_rest_flow }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="mailpassword_flow" value="1" {% if iam_settings.mailpassword_flow == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_login_provisioning_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_login_provisioning }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="login_provisioning" value="1" {% if iam_settings.login_provisioning == 1 %}checked{% endif %}>
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="login_provisioning" value="1" {% if iam_settings.login_provisioning == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<legend class="fs-5 mt-4"><i class="bi bi-file-earmark-text"></i> {{ lang.admin.iam_section_templates }}</legend><hr>
|
||||
{% include 'admin/iam-template-mapping.twig' with {'iam_form': 'keycloak'} %}
|
||||
{% include 'admin/iam-sync-settings.twig' with {'iam_form': 'keycloak'} %}
|
||||
<hr class="mt-4">
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_periodic_full_sync }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="periodic_sync" value="1" {% if iam_settings.periodic_sync == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_import_users }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="import_users" value="1" {% if iam_settings.import_users == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_sync_interval }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input class="form-control" type="number" min="1" name="sync_interval" style="width: 80px;" {% if iam_settings.sync_interval %}value="{{ iam_settings.sync_interval }}"{% else %}value="15"{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4 mb-2">
|
||||
<div class="offset-md-3 col-12 col-md-9 d-flex flex-wrap">
|
||||
<div class="btn-group mb-2">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary iam_test_connection iam_test_connection" data-id="iam_keycloak"><i class="bi bi-play"></i> {{ lang.admin.iam_test_connection }}</button>
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-success" data-item="identity-provider" data-action="edit_selected" data-id="iam_keycloak" data-api-url='edit/identity-provider' data-api-attr='{}'><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
|
||||
</div>
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-success mb-2" data-item="identity-provider" data-action="edit_selected" data-id="iam_keycloak" data-api-url='edit/identity-provider' data-api-attr='{}'><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-danger ms-auto mb-2" data-item="identity-provider" data-action="delete_selected" data-id="iam_keycloak" data-api-url='delete/identity-provider'><i class="bi bi-trash"></i> {{ lang.mailbox.remove }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{# Generic OIDC #}
|
||||
<div id="generic_oidc_settings" class="{% if not iam_settings.authsource or iam_settings.authsource != 'generic-oidc' %}d-none{% endif %}">
|
||||
<form class="form-horizontal" autocapitalize="none" data-id="iam_generic" autocorrect="off" role="form" method="post">
|
||||
<input type="hidden" name="authsource" value="generic-oidc">
|
||||
<legend class="fs-5 mt-2"><i class="bi bi-plug"></i> {{ lang.admin.iam_section_connection }}</legend><hr>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_authorize_url">{{ lang.admin.iam_authorize_url }}:</label>
|
||||
@@ -315,46 +172,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_redirect_url }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<div class="row px-2 align-items-center">
|
||||
<span class="col-10 p-0 pe-2">
|
||||
<input type="text" class="form-control" name="redirect_url" value="{{ iam_settings.redirect_url }}" required>
|
||||
</span>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary ms-auto iam_redirect_add_generic"><i class="bi bi-plus-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2" id="iam_generic_redirect_list">
|
||||
<input type="hidden" name="redirect_url_extra" value="">
|
||||
{% for key, url in iam_settings.redirect_url_extra %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-10 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="redirect_url_extra" value="{{ iam_settings.redirect_url_extra[key] }}">
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_generic_redirect_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-10 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="redirect_url_extra" value="">
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_generic_redirect_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_client_scopes">{{ lang.admin.iam_client_scopes }}:</label>
|
||||
</div>
|
||||
@@ -362,125 +179,57 @@
|
||||
<input type="text" placeholder="openid profile email mailcow_template" class="form-control" id="iam_client_scopes" name="client_scopes" value="{{ iam_settings.client_scopes }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_mapping }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<div class="row px-2 align-items-center">
|
||||
<span class="col-5 p-0 pe-2">{{ lang.user.attribute }}</span>
|
||||
<span class="col-5 p-0 pe-2">{{ lang.mailbox.template }}</span>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary ms-auto iam_rolemap_add_generic"><i class="bi bi-plus-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2" id="iam_generic_mapping_list">
|
||||
<input type="hidden" name="mappers" value="">
|
||||
<input type="hidden" name="templates" value="">
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_default_template_description }}"></i>
|
||||
<span>{{ lang.admin.iam_default_template}}</span>
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2 align-content-end">
|
||||
<select data-live-search="true" name="default_template" class="form-control" title="-- {{ lang.mailbox.template }} --">
|
||||
<option value="" {% if not iam_settings.default_template %}selected{% endif %}>-- {{ lang.mailbox.template }} --</option>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option {% if mbox_template.template == iam_settings.default_template %}selected{% endif %}>
|
||||
{{ mbox_template.template }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% for key, role in iam_settings.mappers %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="mappers" value="{{ iam_settings.mappers[key] }}" required>
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<select data-live-search="true" name="templates" class="form-control" title="-- {{ lang.mailbox.template }} --" required>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option{% if mbox_template.template == iam_settings.templates[key] %} selected{% endif %}>
|
||||
{{ mbox_template.template }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_generic_rolemap_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="mappers" value="">
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<select data-live-search="true" name="templates" class="form-control" title="-- {{ lang.mailbox.template }} --">
|
||||
<option value="" selected>-- {{ lang.mailbox.template }} --</option>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option>
|
||||
{{ mbox_template.template }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_generic_rolemap_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.ignore_ssl_error }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="ignore_ssl_error" value="1" {% if iam_settings.ignore_ssl_error == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<div class="row mb-2">
|
||||
<div class="offset-md-3 col-12 col-md-9">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary iam_test_connection" data-id="iam_generic"><i class="bi bi-play"></i> {{ lang.admin.iam_test_connection }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<legend class="fs-5 mt-4"><i class="bi bi-box-arrow-in-right"></i> {{ lang.admin.iam_section_login }}</legend><hr>
|
||||
{% include 'admin/iam-redirect-urls.twig' with {'iam_form': 'generic'} %}
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_login_provisioning_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_login_provisioning }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="login_provisioning" value="1" {% if iam_settings.login_provisioning == 1 %}checked{% endif %}>
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="login_provisioning" value="1" {% if iam_settings.login_provisioning == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4 mb-2">
|
||||
<legend class="fs-5 mt-4"><i class="bi bi-file-earmark-text"></i> {{ lang.admin.iam_section_templates }}</legend><hr>
|
||||
{% include 'admin/iam-template-mapping.twig' with {'iam_form': 'generic'} %}
|
||||
<hr class="mt-4">
|
||||
<div class="row mb-2">
|
||||
<div class="offset-md-3 col-12 col-md-9 d-flex flex-wrap">
|
||||
<div class="btn-group mb-2">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary iam_test_connection" data-id="iam_generic"><i class="bi bi-play"></i> {{ lang.admin.iam_test_connection }}</button>
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-success" data-item="identity-provider" data-action="edit_selected" data-id="iam_generic" data-api-url='edit/identity-provider' data-api-attr='{}'><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
|
||||
</div>
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-success mb-2" data-item="identity-provider" data-action="edit_selected" data-id="iam_generic" data-api-url='edit/identity-provider' data-api-attr='{}'><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-danger ms-auto mb-2" data-item="identity-provider" data-action="delete_selected" data-id="iam_generic" data-api-url='delete/identity-provider'><i class="bi bi-trash"></i> {{ lang.mailbox.remove }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{# LDAP #}
|
||||
<div id="ldap_settings" class="{% if not iam_settings.authsource or iam_settings.authsource != 'ldap' %}d-none{% endif %}">
|
||||
<form class="form-horizontal" autocapitalize="none" data-id="iam_ldap" autocorrect="off" role="form" method="post">
|
||||
<input type="hidden" name="authsource" value="ldap">
|
||||
<legend class="fs-5 mt-2"><i class="bi bi-plug"></i> {{ lang.admin.iam_section_connection }}</legend><hr>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_host_info }}"></i>
|
||||
<label class="control-label" for="iam_ldap_host">{{ lang.admin.iam_host }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4 d-flex">
|
||||
<input type="text" class="form-control" id="iam_ldap_host" name="host" value="{{ iam_settings.host }}" required>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" id="iam_ldap_host" name="host" value="{{ iam_settings.host }}" placeholder="ldap1.example.org, ldap2.example.org" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
@@ -488,96 +237,44 @@
|
||||
<label class="control-label" for="iam_ldap_port">{{ lang.admin.iam_port }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="number" class="form-control" id="iam_ldap_port" name="port" value="{{ iam_settings.port }}" required>
|
||||
<input type="number" class="form-control" id="iam_ldap_port" name="port" value="{{ iam_settings.port }}" placeholder="389" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_use_ssl_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_use_ssl }}</label>
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_encryption_info }}"></i>
|
||||
<label class="control-label" for="iam_ldap_encryption">{{ lang.admin.iam_encryption }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
id="use_ssl"
|
||||
name="use_ssl"
|
||||
value="1"
|
||||
onchange="if(this.checked) document.getElementById('use_tls').checked = false"
|
||||
{% if iam_settings.use_ssl == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
{# use_ssl and use_tls exclude each other, the select sets both #}
|
||||
<input type="hidden" name="use_ssl" value="{{ iam_settings.use_ssl ? 1 : 0 }}">
|
||||
<input type="hidden" name="use_tls" value="{{ iam_settings.use_tls ? 1 : 0 }}">
|
||||
<select id="iam_ldap_encryption" class="form-control iam_ldap_encryption">
|
||||
<option value="none" {% if not iam_settings.use_ssl and not iam_settings.use_tls %}selected{% endif %}>{{ lang.admin.iam_encryption_none }}</option>
|
||||
<option value="tls" {% if iam_settings.use_tls and not iam_settings.use_ssl %}selected{% endif %}>StartTLS</option>
|
||||
<option value="ssl" {% if iam_settings.use_ssl %}selected{% endif %}>SSL (LDAPS)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_use_tls_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_use_tls }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
id="use_tls"
|
||||
name="use_tls"
|
||||
value="1"
|
||||
onchange="if(this.checked) document.getElementById('use_ssl').checked = false"
|
||||
{% if iam_settings.use_tls == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.ignore_ssl_error }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="ignore_ssl_error" value="1" {% if iam_settings.ignore_ssl_error == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_ldap_basedn">{{ lang.admin.iam_basedn }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" id="iam_ldap_basedn" name="basedn" value="{{ iam_settings.basedn }}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_ldap_username_field">{{ lang.admin.iam_username_field }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="mail" id="iam_ldap_username_field" name="username_field" value="{{ iam_settings.username_field }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_ldap_filter">{{ lang.admin.filter }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="" id="iam_ldap_filter" name="filter" value="{{ iam_settings.filter }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_ldap_attribute_field">{{ lang.admin.iam_attribute_field }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" id="iam_ldap_attribute_field" name="attribute_field" value="{{ iam_settings.attribute_field }}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_ldap_binddn">{{ lang.admin.iam_binddn }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" id="iam_ldap_binddn" name="binddn" value="{{ iam_settings.binddn }}" required>
|
||||
<input type="text" class="form-control" id="iam_ldap_binddn" name="binddn" value="{{ iam_settings.binddn }}" placeholder="cn=mailcow,ou=services,dc=example,dc=org" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_ldap_bindpass">{{ lang.admin.iam_bindpass }}:</label>
|
||||
</div>
|
||||
@@ -589,132 +286,91 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_mapping }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<div class="row px-2 align-items-center">
|
||||
<span class="col-5 p-0 pe-2">{{ lang.user.attribute }}</span>
|
||||
<span class="col-5 p-0 pe-2">{{ lang.mailbox.template }}</span>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary ms-auto iam_rolemap_add_ldap"><i class="bi bi-plus-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="offset-md-3 col-12 col-md-9">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary iam_test_connection" data-id="iam_ldap"><i class="bi bi-play"></i> {{ lang.admin.iam_test_connection }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2" id="iam_ldap_mapping_list">
|
||||
<input type="hidden" name="mappers" value="">
|
||||
<input type="hidden" name="templates" value="">
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_default_template_description }}"></i>
|
||||
<span>{{ lang.admin.iam_default_template }}</span>
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2 align-content-end">
|
||||
<select data-live-search="true" name="default_template" class="form-control" title="-- {{ lang.mailbox.template }} --">
|
||||
<option value="" {% if not iam_settings.default_template %}selected{% endif %}>-- {{ lang.mailbox.template }} --</option>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option {% if mbox_template.template == iam_settings.default_template %}selected{% endif %}>
|
||||
{{ mbox_template.template }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex"></div>
|
||||
</div>
|
||||
<legend class="fs-5 mt-4"><i class="bi bi-person-lines-fill"></i> {{ lang.admin.iam_section_users }}</legend><hr>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label" for="iam_ldap_basedn">{{ lang.admin.iam_basedn }}:</label>
|
||||
</div>
|
||||
{% for key, role in iam_settings.mappers %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="mappers" value="{{ iam_settings.mappers[key] }}" required>
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<select data-live-search="true" name="templates" class="form-control" title="-- {{ lang.mailbox.template }} --" required>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option{% if mbox_template.template == iam_settings.templates[key] %} selected{% endif %}>
|
||||
{{ mbox_template.template }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_ldap_rolemap_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="offset-md-3 col-12 col-md-9 col-lg-4 mb-2">
|
||||
<div class="row px-2">
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<input type="text" class="form-control me-2" name="mappers" value="">
|
||||
</div>
|
||||
<div class="col-5 p-0 pe-2">
|
||||
<select data-live-search="true" name="templates" class="form-control" title="-- {{ lang.mailbox.template }} --">
|
||||
<option value="" selected>-- {{ lang.mailbox.template }} --</option>
|
||||
{% for mbox_template in mbox_templates %}
|
||||
<option>
|
||||
{{ mbox_template.template }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-2 p-0 d-flex">
|
||||
<button class="iam_ldap_rolemap_del btn btn-sm d-block d-sm-inline btn-secondary ms-auto"><i class="bi bi-x-lg"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" id="iam_ldap_basedn" name="basedn" value="{{ iam_settings.basedn }}" placeholder="ou=people,dc=example,dc=org" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_filter_info }}"></i>
|
||||
<label class="control-label" for="iam_ldap_filter">{{ lang.admin.filter }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="(objectClass=person)" id="iam_ldap_filter" name="filter" value="{{ iam_settings.filter }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_username_field_info }}"></i>
|
||||
<label class="control-label" for="iam_ldap_username_field">{{ lang.admin.iam_username_field }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="mail" id="iam_ldap_username_field" name="username_field" value="{{ iam_settings.username_field }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_id_attribute_info }}"></i>
|
||||
<label class="control-label" for="iam_ldap_id_attribute">{{ lang.admin.iam_id_attribute }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="objectGUID, entryUUID" id="iam_ldap_id_attribute" name="id_attribute" value="{{ iam_settings.id_attribute }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_disabled_filter_info }}"></i>
|
||||
<label class="control-label" for="iam_ldap_disabled_filter">{{ lang.admin.iam_disabled_filter }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input type="text" class="form-control" placeholder="(employeeType=inactive)" id="iam_ldap_disabled_filter" name="disabled_filter" value="{{ iam_settings.disabled_filter }}">
|
||||
</div>
|
||||
</div>
|
||||
<legend class="fs-5 mt-4"><i class="bi bi-box-arrow-in-right"></i> {{ lang.admin.iam_section_login }}</legend><hr>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_login_provisioning_info }}"></i>
|
||||
<label class="control-label">{{ lang.admin.iam_login_provisioning }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="col-12 col-md-9 d-flex align-items-center">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="login_provisioning" value="1" {% if iam_settings.login_provisioning == 1 %}checked{% endif %}>
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="login_provisioning" value="1" {% if iam_settings.login_provisioning == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<legend class="fs-5 mt-4"><i class="bi bi-file-earmark-text"></i> {{ lang.admin.iam_section_templates }}</legend><hr>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_periodic_full_sync }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="periodic_sync" value="1" {% if iam_settings.periodic_sync == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_import_users }}</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" name="import_users" value="1" {% if iam_settings.import_users == 1 %}checked{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
|
||||
<label class="control-label">{{ lang.admin.iam_sync_interval }}</label>
|
||||
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill mx-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.admin.iam_attribute_field_info }}"></i>
|
||||
<label class="control-label" for="iam_ldap_attribute_field">{{ lang.admin.iam_attribute_field }}:</label>
|
||||
</div>
|
||||
<div class="col-12 col-md-9 col-lg-4">
|
||||
<input class="form-control" type="number" min="1" name="sync_interval" style="width: 80px;" {% if iam_settings.sync_interval %}value="{{ iam_settings.sync_interval }}"{% else %}value="15"{% endif %}>
|
||||
<input type="text" class="form-control" id="iam_ldap_attribute_field" name="attribute_field" value="{{ iam_settings.attribute_field }}" placeholder="departmentNumber">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4 mb-2">
|
||||
{% include 'admin/iam-template-mapping.twig' with {'iam_form': 'ldap'} %}
|
||||
{% include 'admin/iam-sync-settings.twig' with {'iam_form': 'ldap'} %}
|
||||
<hr class="mt-4">
|
||||
<div class="row mb-2">
|
||||
<div class="offset-md-3 col-12 col-md-9 d-flex flex-wrap">
|
||||
<div class="btn-group mb-2">
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-secondary iam_test_connection iam_test_connection" data-id="iam_ldap"><i class="bi bi-play"></i> {{ lang.admin.iam_test_connection }}</button>
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-success" data-item="identity-provider" data-action="edit_selected" data-id="iam_ldap" data-api-url='edit/identity-provider' data-api-attr='{}'><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
|
||||
</div>
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-success mb-2" data-item="identity-provider" data-action="edit_selected" data-id="iam_ldap" data-api-url='edit/identity-provider' data-api-attr='{}'><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
|
||||
<button class="btn btn-sm d-block d-sm-inline btn-danger ms-auto mb-2" data-item="identity-provider" data-action="delete_selected" data-id="iam_ldap" data-api-url='delete/identity-provider'><i class="bi bi-trash"></i> {{ lang.mailbox.remove }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% if iam_settings.authsource == 'keycloak' or iam_settings.authsource == 'ldap' %}
|
||||
{% include 'admin/iam-sync-status.twig' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -27,6 +27,7 @@
|
||||
var lang_admin = {{ lang_admin|raw }};
|
||||
var lang_datatables = {{ lang_datatables|raw }};
|
||||
var lang_syncjobs = {{ lang_syncjobs|raw }};
|
||||
var lang_groups = {{ lang_groups|raw }};
|
||||
var csrf_token = '{{ csrf_token }}';
|
||||
var pagination_size = Math.trunc('{{ pagination_size }}');
|
||||
var table_for_domain = '{{ domain }}';
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
{# One share row of the group edit page: kind = imap|sogo, grant = {} for the add template #}
|
||||
{% set level_key = kind == 'imap' ? 'rights' : 'access' %}
|
||||
{# new IMAP shares are subscribed by default, like automapping in Exchange #}
|
||||
{% set subscribed = grant.owner is defined ? grant.subscribe|default(0) == 1 : kind == 'imap' %}
|
||||
<tr class="group-grant">
|
||||
<td class="{{ kind == 'imap' ? 'w-50' : 'w-25' }}">
|
||||
<select data-grant="owner" data-live-search="true" data-width="100%" class="form-control" title="{{ lang.groups.grant_owner }}"{% if ro %} disabled{% endif %}>
|
||||
{% for mailbox in mailboxes %}
|
||||
<option{% if mailbox == grant.owner %} selected{% endif %}>{{ mailbox }}</option>
|
||||
{% endfor %}
|
||||
{% if grant.owner and grant.owner not in mailboxes %}
|
||||
<option selected>{{ grant.owner }}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</td>
|
||||
{% if kind == 'sogo' %}
|
||||
<td>
|
||||
<select data-grant="type" data-width="100%" class="form-control"{% if ro %} disabled{% endif %}>
|
||||
<option value="Calendar"{% if grant.type == 'Calendar' %} selected{% endif %}>{{ lang.groups.type_calendar }}</option>
|
||||
<option value="Contacts"{% if grant.type == 'Contacts' %} selected{% endif %}>{{ lang.groups.type_contacts }}</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="w-25">
|
||||
<input type="text" data-grant="folder" class="form-control" value="{{ grant.folder ?? 'personal' }}" maxlength="100" title="{{ lang.groups.grant_folder }}"{% if ro %} disabled{% endif %}>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="{{ kind == 'imap' ? 'w-25' : '' }}">
|
||||
<select data-grant="{{ level_key }}" data-width="100%" class="form-control"{% if ro %} disabled{% endif %}>
|
||||
{% for level in (kind == 'imap' ? ['read', 'write', 'full'] : ['read', 'write']) %}
|
||||
<option value="{{ level }}"{% if level == attribute(grant, level_key)|default('read') %} selected{% endif %}>{{ attribute(lang.groups, 'rights_' ~ level) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td class="text-nowrap">
|
||||
<div class="form-check mb-0" title="{{ attribute(lang.groups, 'grant_subscribe_' ~ kind ~ '_hint') }}">
|
||||
<label><input type="checkbox" class="form-check-input" data-grant="subscribe" value="1"{% if subscribed %} checked{% endif %}{% if ro %} disabled{% endif %}> {{ lang.groups.grant_subscribe }}</label>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{% if grant.state %}
|
||||
<span class="badge {{ grant.state == 'applied' ? 'bg-success' : (grant.state == 'failed' ? 'bg-danger' : 'bg-secondary') }}"{% if grant.last_error %} title="{{ grant.last_error }}"{% endif %}>{{ attribute(lang.groups, 'grant_state_' ~ grant.state) }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-end">
|
||||
{% if not ro %}
|
||||
<button class="btn btn-sm btn-secondary group-grant-del" title="{{ lang.mailbox.remove }}"><i class="bi bi-x-lg"></i></button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -0,0 +1,24 @@
|
||||
{# Shares of a group (edit page, add modal): kind = imap|sogo, grants, id = table id, ro; rows go to the hidden JSON field #}
|
||||
{% set field = kind ~ '_grants' %}
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2{{ label_class|default('') }}">{{ attribute(lang.groups, field) }}</label>
|
||||
<div class="col-sm-10">
|
||||
{% if not ro %}
|
||||
<input type="hidden" name="{{ field }}" value="{{ grants|json_encode }}">
|
||||
{% endif %}
|
||||
<table class="table table-sm align-middle group-grants mb-1" id="{{ id }}" data-field="{{ field }}">
|
||||
<tbody>
|
||||
{% for grant in grants %}
|
||||
{% include 'edit/mailbox-group-grant.twig' with {'kind': kind, 'grant': grant} %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if not ro %}
|
||||
<template id="{{ id }}_template">
|
||||
{% include 'edit/mailbox-group-grant.twig' with {'kind': kind, 'grant': {}} %}
|
||||
</template>
|
||||
<button class="btn btn-sm btn-secondary group-grant-add" data-table="{{ id }}"><i class="bi bi-plus-lg"></i> {{ lang.groups.grant_add }}</button>
|
||||
{% endif %}
|
||||
<small class="text-muted d-block">{{ attribute(lang.groups, field ~ '_hint') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,142 @@
|
||||
{% extends 'edit.twig' %}
|
||||
|
||||
{% block inner_content %}
|
||||
{% if result %}
|
||||
{% set ro = not result.can_edit %}
|
||||
{% set editable_members = [] %}
|
||||
{% set fixed_members = [] %}
|
||||
{% for member in result.members %}
|
||||
{% if member.source == 'idp' or member.username not in mailboxes %}
|
||||
{% set fixed_members = fixed_members|merge([member]) %}
|
||||
{% else %}
|
||||
{% set editable_members = editable_members|merge([member.username]) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<h4>{{ lang.groups.group }}: {{ result.name }}</h4>
|
||||
{% if result.idp_ref %}
|
||||
<div class="alert alert-secondary" role="alert"><span class="badge bg-info">{{ lang.groups.idp }}</span> {{ lang.groups.idp_ref }}: <code>{{ result.idp_ref }}</code></div>
|
||||
{% endif %}
|
||||
<form data-id="edit_mailbox_group" class="form-horizontal" role="form" method="post" autocapitalize="none" autocorrect="off">
|
||||
<input type="hidden" value="0" name="active">
|
||||
<input type="hidden" value="0" name="sender_allowed">
|
||||
<input type="hidden" value="0" name="sogo_visible">
|
||||
<input type="hidden" value="0" name="internal">
|
||||
<input type="hidden" value="0" name="reapply_template">
|
||||
{% if not ro %}
|
||||
{# an empty selection still sends the field, so all editable members can be removed #}
|
||||
<input type="hidden" value="" name="members">
|
||||
{% endif %}
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2" for="group_domain">{{ lang.groups.domain }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="group_domain" value="{{ result.domain }}" disabled>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2" for="group_name">{{ lang.groups.name }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="name" id="group_name" value="{{ result.name }}" maxlength="100" required{% if ro %} disabled{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2" for="group_description">{{ lang.groups.description }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="description" id="group_description" value="{{ result.description }}" maxlength="255"{% if ro %} disabled{% endif %}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2" for="group_address">{{ lang.groups.address }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="address" id="group_address" value="{{ result.address }}" placeholder="name@{{ result.domain }}"{% if ro %} disabled{% endif %}>
|
||||
<small class="text-muted">{{ lang.groups.address_hint }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2" for="group_members">{{ lang.groups.members }}</label>
|
||||
<div class="col-sm-10">
|
||||
<select data-live-search="true" data-width="100%" name="members" id="group_members" class="form-control" multiple{% if ro %} disabled{% endif %}>
|
||||
{% for mailbox in mailboxes %}
|
||||
<option{% if mailbox in editable_members %} selected{% endif %}>{{ mailbox }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% if fixed_members %}
|
||||
<div class="mt-2">
|
||||
{% for member in fixed_members %}
|
||||
<span class="badge bg-secondary"{% if member.source == 'idp' %} title="{{ lang.groups.idp_member }}"{% endif %}>{% if member.source == 'idp' %}<i class="bi bi-cloud"></i> {% endif %}{{ member.username }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2" for="group_send_as">{{ lang.groups.send_as }}</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" rows="3" name="send_as" id="group_send_as"{% if ro %} disabled{% endif %}>{{ result.send_as|join("\n") }}</textarea>
|
||||
<small class="text-muted">{{ lang.groups.send_as_hint }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'edit/mailbox-group-grants.twig' with {'kind': 'imap', 'grants': result.imap_grants, 'id': 'group_imap_grants'} %}
|
||||
{% if not skip_sogo %}
|
||||
{% include 'edit/mailbox-group-grants.twig' with {'kind': 'sogo', 'grants': result.sogo_grants, 'id': 'group_sogo_grants'} %}
|
||||
{% endif %}
|
||||
<div class="row mb-2">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sender_allowed"{% if result.sender_allowed == 1 %} checked{% endif %}{% if ro %} disabled{% endif %}> {{ lang.groups.sender_allowed }}</label>
|
||||
</div>
|
||||
{% if not skip_sogo %}
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_visible"{% if result.sogo_visible == 1 %} checked{% endif %}{% if ro %} disabled{% endif %}> {{ lang.groups.sogo_visible }}</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="internal"{% if result.internal == 1 %} checked{% endif %}{% if ro %} disabled{% endif %}> {{ lang.groups.internal }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2" for="group_template">{{ lang.groups.template }}</label>
|
||||
{% if mailcow_cc_role == 'admin' %}
|
||||
<div class="col-sm-6">
|
||||
<select name="template_id" id="group_template" class="form-control">
|
||||
<option value="">{{ lang.groups.template_none }}</option>
|
||||
{% for template in mbox_templates %}
|
||||
<option value="{{ template.id }}"{% if template.id == result.template_id %} selected{% endif %}>{{ template.template }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="control-label col-sm-2" for="group_priority">{{ lang.groups.priority }}</label>
|
||||
<div class="col-sm-2">
|
||||
<input type="number" class="form-control" name="priority" id="group_priority" value="{{ result.priority }}">
|
||||
</div>
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="reapply_template"> {{ lang.groups.reapply_template }}</label>
|
||||
</div>
|
||||
<small class="text-muted">{{ lang.groups.template_hint }}</small>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="group_template" value="{% if result.template %}{{ result.template }} ({{ lang.groups.priority }} {{ result.priority }}){% else %}{{ lang.groups.template_none }}{% endif %}" disabled>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if result.active == 1 %} checked{% endif %}{% if ro %} disabled{% endif %}> {{ lang.groups.active }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if not ro %}
|
||||
<div class="row">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="edit_mailbox_group" data-item="{{ result.id }}" data-api-url='edit/mailbox-group' data-api-attr='{}' href="#"><i class="bi bi-check-lg"></i> {{ lang.admin.save }}</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% else %}
|
||||
{{ parent() }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -24,6 +24,7 @@
|
||||
<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="shared">
|
||||
<input type="hidden" value="0" name="force_tfa">
|
||||
<input type="hidden" value="0" name="sogo_access">
|
||||
<input type="hidden" value="0" name="protocol_access">
|
||||
@@ -46,6 +47,20 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{% if result.authsource != 'mailcow' and identity_link %}
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2">{{ lang.edit.iam_link }}</label>
|
||||
<div class="col-sm-10">
|
||||
{% if identity_link.external_id %}<code>{{ identity_link.external_id }}</code>{% else %}<span class="text-muted">{{ lang.edit.iam_not_linked }}</span>{% endif %}
|
||||
{% if identity_link.idp_disabled == 1 %}<span class="badge bg-warning text-dark">{{ lang.edit.iam_idp_disabled }}</span>{% endif %}
|
||||
{% if identity_link.missing_since %}<span class="badge bg-danger">{{ lang.edit.iam_missing_since }} {{ identity_link.missing_since }}</span>{% endif %}
|
||||
{% if mailcow_cc_role == 'admin' and identity_link.external_id %}
|
||||
<a href="#" class="btn btn-sm btn-secondary ms-2" data-action="delete_selected" data-id="identity_link" data-item="{{ mailbox }}" data-api-url="delete/identity-link"><i class="bi bi-link-45deg"></i> {{ lang.edit.iam_unlink }}</a>
|
||||
{% endif %}
|
||||
<small class="text-muted d-block">{{ lang.edit.iam_link_info }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2" for="name">{{ lang.edit.full_name }}</label>
|
||||
<div class="col-sm-10">
|
||||
@@ -121,6 +136,22 @@
|
||||
<small class="text-muted d-block">{{ lang.edit.sender_acl_info|raw }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% if mailbox_groups.groups %}
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2">{{ lang.groups.memberships }}</label>
|
||||
<div class="col-sm-10">
|
||||
{% for group in mailbox_groups.groups %}
|
||||
<a href="/edit/mailbox-group/{{ group.id }}" class="badge bg-secondary text-decoration-none">{% if group.source == 'idp' %}<i class="bi bi-cloud" title="{{ lang.groups.idp_member }}"></i> {% endif %}{{ group.name }}{% if group.address %} <{{ group.address }}>{% endif %}</a>
|
||||
{% endfor %}
|
||||
{% if mailbox_groups.template %}
|
||||
<small class="text-muted d-block">{{ lang.groups.effective_template }}: {{ mailbox_groups.template }}</small>
|
||||
{% endif %}
|
||||
{% if mailbox_groups.send_as %}
|
||||
<small class="text-muted d-block">{{ lang.groups.send_as_groups }}: {{ mailbox_groups.send_as|join(', ') }}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if acl.mailbox_relayhost == '1' %}
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2" for="relayhost">{{ lang.edit.relayhost }}</label>
|
||||
@@ -310,6 +341,14 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="shared"{% if result.attributes.shared == '1' %} checked{% endif %}> {{ lang.mailbox.shared_mailbox }}</label>
|
||||
<small class="text-muted">{{ lang.mailbox.shared_mailbox_info }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
<li role="presentation"><button class="dropdown-item" aria-selected="false" aria-controls="tab-domain-aliases" role="tab" data-bs-toggle="tab" data-bs-target="#tab-domain-aliases">{{ lang.mailbox.domain_aliases }}</button></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% if acl.mailbox_groups == 1 %}
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" aria-selected="false" aria-controls="tab-groups" role="tab" data-bs-toggle="tab" data-bs-target="#tab-groups">{{ lang.groups.groups }}</button></li>
|
||||
{% endif %}
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" aria-selected="false" aria-controls="tab-syncjobs" role="tab" data-bs-toggle="tab" data-bs-target="#tab-syncjobs">{{ lang.syncjobs.sync_jobs }}</button></li>
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" aria-selected="false" aria-controls="tab-filters" role="tab" data-bs-toggle="tab" data-bs-target="#tab-filters">{{ lang.mailbox.filters }}</button></li>
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" aria-selected="false" aria-controls="tab-bcc" role="tab" data-bs-toggle="tab" data-bs-target="#tab-bcc">{{ lang.mailbox.address_rewriting }}</button></li>
|
||||
@@ -53,6 +56,9 @@
|
||||
{% include 'mailbox/tab-resources.twig' %}
|
||||
{% include 'mailbox/tab-domain-aliases.twig' %}
|
||||
{% include 'mailbox/tab-mbox-aliases.twig' %}
|
||||
{% if acl.mailbox_groups == 1 %}
|
||||
{% include 'mailbox/tab-groups.twig' %}
|
||||
{% endif %}
|
||||
{% include 'mailbox/tab-syncjobs.twig' %}
|
||||
{% include 'mailbox/tab-filters.twig' %}
|
||||
{% include 'mailbox/tab-bcc.twig' %}
|
||||
@@ -68,6 +74,7 @@
|
||||
var acl = '{{ acl_json|raw }}';
|
||||
var lang = {{ lang_mailbox|raw }};
|
||||
lang.syncjobs = {{ lang_syncjobs|raw }};
|
||||
lang.groups = {{ lang_groups|raw }};
|
||||
var lang_rl = {{ lang_rl|raw }};
|
||||
var lang_edit = {{ lang_edit|raw }};
|
||||
var lang_datatables = {{ lang_datatables|raw }};
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<div class="tab-pane fade" id="tab-groups" role="tabpanel" aria-labelledby="tab-groups">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex fs-5">
|
||||
<button class="btn d-md-none flex-grow-1 text-start" data-bs-target="#collapse-tab-groups" data-bs-toggle="collapse" aria-controls="collapse-tab-groups">
|
||||
{{ lang.groups.groups }} <span class="badge bg-info table-lines"></span>
|
||||
</button>
|
||||
<span class="d-none d-md-block">{{ lang.groups.groups }} <span class="badge bg-info table-lines"></span></span>
|
||||
<div class="btn-group ms-auto d-flex">
|
||||
<button class="btn btn-xs btn-secondary refresh_table" data-table="mailbox_group_table">{{ lang.admin.refresh }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="collapse-tab-groups" class="card-body collapse" data-bs-parent="#mail-content">
|
||||
<p class="text-muted">{{ lang.groups.info }}</p>
|
||||
<table id="mailbox_group_table" class="table table-striped dt-responsive w-100"></table>
|
||||
<div class="mass-actions-mailbox mt-4">
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="mailbox_group" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
|
||||
<a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox_group" data-api-url='edit/mailbox-group' data-api-attr='{"active":"1"}' href="#">{{ lang.mailbox.activate }}</a></li>
|
||||
<li><a class="dropdown-item" data-action="edit_selected" data-id="mailbox_group" data-api-url='edit/mailbox-group' data-api-attr='{"active":"0"}' href="#">{{ lang.mailbox.deactivate }}</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" data-action="delete_selected" data-id="mailbox_group" data-api-url='delete/mailbox-group' href="#">{{ lang.mailbox.remove }}</a></li>
|
||||
</ul>
|
||||
<a class="btn btn-sm d-block d-sm-inline btn-success" href="#" data-bs-toggle="modal" data-bs-target="#addMailboxGroupModal"><i class="bi bi-plus-lg"></i> {{ lang.groups.add }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -197,6 +197,14 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="shared" id="add_mailbox_shared"> {{ lang.mailbox.shared_mailbox }}</label>
|
||||
<small class="text-muted">{{ lang.mailbox.shared_mailbox_info }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
@@ -1351,3 +1359,6 @@
|
||||
</div><!-- DNS info modal -->
|
||||
|
||||
{% include "modals/imapsync_source.twig" %}
|
||||
{% if acl.mailbox_groups == 1 %}
|
||||
{% include "modals/mailbox_group.twig" %}
|
||||
{% endif %}
|
||||
@@ -0,0 +1,119 @@
|
||||
<!-- add mailbox group modal -->
|
||||
<div class="modal fade" id="addMailboxGroupModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">{{ lang.groups.add }}</h3>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" role="form" data-id="add_mailbox_group" autocapitalize="none" autocorrect="off">
|
||||
<input type="hidden" value="0" name="active">
|
||||
<input type="hidden" value="0" name="sender_allowed">
|
||||
<input type="hidden" value="0" name="sogo_visible">
|
||||
<input type="hidden" value="0" name="internal">
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2 text-sm-end" for="add_group_domain">{{ lang.groups.domain }}</label>
|
||||
<div class="col-sm-10">
|
||||
<select data-live-search="true" name="domain" id="add_group_domain" class="form-control mailbox-group-domain-select" required>
|
||||
{% for domain in domains %}
|
||||
<option>{{ domain }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2 text-sm-end" for="add_group_name">{{ lang.groups.name }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="name" id="add_group_name" maxlength="100" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2 text-sm-end" for="add_group_description">{{ lang.groups.description }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" name="description" id="add_group_description" maxlength="255">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2 text-sm-end" for="add_group_local_part">{{ lang.groups.address }}</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" name="local_part" id="add_group_local_part">
|
||||
<span class="input-group-text">@<span class="mailbox-group-domain">{{ domains|first }}</span></span>
|
||||
</div>
|
||||
<small class="text-muted">{{ lang.groups.address_hint }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2 text-sm-end" for="add_group_members">{{ lang.groups.members }}</label>
|
||||
<div class="col-sm-10">
|
||||
<select data-live-search="true" data-width="100%" name="members" id="add_group_members" class="form-control" multiple>
|
||||
{% for mailbox in mailboxes %}
|
||||
<option>{{ mailbox }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2 text-sm-end" for="add_group_send_as">{{ lang.groups.send_as }}</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" rows="3" name="send_as" id="add_group_send_as"></textarea>
|
||||
<small class="text-muted">{{ lang.groups.send_as_hint }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'edit/mailbox-group-grants.twig' with {'kind': 'imap', 'grants': [], 'id': 'add_group_imap_grants', 'ro': false, 'label_class': ' text-sm-end'} %}
|
||||
{% if not skip_sogo %}
|
||||
{% include 'edit/mailbox-group-grants.twig' with {'kind': 'sogo', 'grants': [], 'id': 'add_group_sogo_grants', 'ro': false, 'label_class': ' text-sm-end'} %}
|
||||
{% endif %}
|
||||
<div class="row mb-2">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sender_allowed"> {{ lang.groups.sender_allowed }}</label>
|
||||
</div>
|
||||
{% if not skip_sogo %}
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_visible"> {{ lang.groups.sogo_visible }}</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="internal"> {{ lang.groups.internal }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if mailcow_cc_role == 'admin' %}
|
||||
<div class="row mb-2">
|
||||
<label class="control-label col-sm-2 text-sm-end" for="add_group_template">{{ lang.groups.template }}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="template_id" id="add_group_template" class="form-control">
|
||||
<option value="">{{ lang.groups.template_none }}</option>
|
||||
{% for template in mbox_templates %}
|
||||
<option value="{{ template.id }}">{{ template.template }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="control-label col-sm-2 text-sm-end" for="add_group_priority">{{ lang.groups.priority }}</label>
|
||||
<div class="col-sm-2">
|
||||
<input type="number" class="form-control" name="priority" id="add_group_priority" value="0">
|
||||
</div>
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<small class="text-muted">{{ lang.groups.template_hint }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row mb-4">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<div class="form-check">
|
||||
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.groups.active }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<div class="offset-sm-2 col-sm-10">
|
||||
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="add_item" data-id="add_mailbox_group" data-api-url='add/mailbox-group' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- add mailbox group modal -->
|
||||
@@ -61,6 +61,18 @@
|
||||
<p>{% if not user_get_alias_details.aliases_send_as_all %}<i class="bi bi-x-lg"></i>{% else %}{{ user_get_alias_details.aliases_send_as_all }}{% endif %}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 col-md-3 col-12 text-sm-end text-start mb-4"><i class="bi bi-people"></i> {{ lang.groups.memberships }}:</div>
|
||||
<div class="col-sm-8 col-md-9 col-12">
|
||||
<p>
|
||||
{% for group in mailbox_groups.groups %}
|
||||
{{ group.name }}{% if group.address %} <{{ group.address }}>{% endif %}{% if not loop.last %}<br>{% endif %}
|
||||
{% else %}
|
||||
<i class="bi bi-x-lg"></i>
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 col-md-3 col-12 text-sm-end text-start mb-4">{{ lang.user.is_catch_all }}:</div>
|
||||
<div class="col-sm-8 col-md-9 col-12">
|
||||
|
||||
Reference in new issue
Block a user