mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-02-24 18:06:23 +00:00
Compare commits
1 Commits
staging
...
feat/sync-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06f308a934 |
@@ -155,6 +155,11 @@ while (true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine if account is enabled in Keycloak
|
||||
$keycloak_account_active = isset($user['enabled']) ? intval($user['enabled']) : 1;
|
||||
$status = ($keycloak_account_active == 1) ? "enabled" : "disabled";
|
||||
logMsg("info", "User " . $user['email'] . " is {$status} in Keycloak");
|
||||
|
||||
// try get mailbox user
|
||||
$stmt = $pdo->prepare("SELECT
|
||||
mailbox.*,
|
||||
@@ -172,6 +177,12 @@ while (true) {
|
||||
|
||||
$_SESSION['access_all_exception'] = '1';
|
||||
if (!$row && intval($iam_settings['import_users']) == 1){
|
||||
// Skip disabled users during import if sync_disabled_users is enabled
|
||||
if (intval($iam_settings['sync_disabled_users']) == 1 && $keycloak_account_active == 0) {
|
||||
logMsg("info", "Skipping import of disabled user " . $user['email']);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($mapper_key === false){
|
||||
if (!empty($iam_settings['default_template'])) {
|
||||
$mbox_template = $iam_settings['default_template'];
|
||||
@@ -202,13 +213,26 @@ while (true) {
|
||||
continue;
|
||||
}
|
||||
$mbox_template = $iam_settings['templates'][$mapper_key];
|
||||
// mailbox user does exist, sync attribtues...
|
||||
logMsg("info", "Syncing attributes for user " . $user['email']);
|
||||
mailbox('edit', 'mailbox_from_template', array(
|
||||
|
||||
// Prepare update data with active status
|
||||
$update_data = array(
|
||||
'username' => $user['email'],
|
||||
'name' => $user['firstName'] . " " . $user['lastName'],
|
||||
'template' => $mbox_template
|
||||
));
|
||||
);
|
||||
|
||||
// Add active status if sync_disabled_users is enabled
|
||||
if (intval($iam_settings['sync_disabled_users']) == 1) {
|
||||
if ($row['active'] != $keycloak_account_active) {
|
||||
$update_data['active'] = $keycloak_account_active;
|
||||
$status_change = ($keycloak_account_active == 1) ? "enabled" : "disabled";
|
||||
logMsg("info", "Changing active status for user " . $user['email'] . " to {$status_change}");
|
||||
}
|
||||
}
|
||||
|
||||
// mailbox user does exist, sync attributes...
|
||||
logMsg("info", "Syncing attributes for user " . $user['email']);
|
||||
mailbox('edit', 'mailbox_from_template', $update_data);
|
||||
} else {
|
||||
// skip mailbox user
|
||||
logMsg("info", "Skipping user " . $user['email']);
|
||||
|
||||
@@ -118,7 +118,7 @@ if (!empty($iam_settings['filter'])) {
|
||||
}
|
||||
$response = $ldap_query->where($iam_settings['username_field'], "*")
|
||||
->where($iam_settings['attribute_field'], "*")
|
||||
->select([$iam_settings['username_field'], $iam_settings['attribute_field'], 'displayname'])
|
||||
->select([$iam_settings['username_field'], $iam_settings['attribute_field'], 'displayname', 'userAccountControl', 'pwdAccountLockedTime'])
|
||||
->paginate($max);
|
||||
|
||||
// Process the users
|
||||
@@ -138,6 +138,41 @@ foreach ($response as $user) {
|
||||
$user_template = $user[$iam_settings['attribute_field']][0];
|
||||
$mapper_key = array_search($user_template, $iam_settings['mappers']);
|
||||
|
||||
// Determine if account is disabled in LDAP (multi-provider support)
|
||||
$ldap_account_active = 1; // Default to active
|
||||
$has_disabled_attr = false;
|
||||
$disabled_check_method = "none";
|
||||
|
||||
// Try Active Directory userAccountControl first
|
||||
if (isset($user['useraccountcontrol'][0])) {
|
||||
$has_disabled_attr = true;
|
||||
$disabled_check_method = "AD-userAccountControl";
|
||||
$uac = intval($user['useraccountcontrol'][0]);
|
||||
|
||||
// UAC flag 0x0002 indicates ACCOUNTDISABLE
|
||||
// If bit is set, account is disabled
|
||||
$ldap_account_active = ($uac & 0x0002) ? 0 : 1;
|
||||
|
||||
$uac_status = ($ldap_account_active == 1) ? "enabled" : "disabled";
|
||||
logMsg("info", "User " . $user[$iam_settings['username_field']][0] . " is {$uac_status} (AD UAC: {$uac})");
|
||||
}
|
||||
// Try OpenLDAP/389DS/FreeIPA pwdAccountLockedTime
|
||||
elseif (isset($user['pwdaccountlockedtime'])) {
|
||||
$has_disabled_attr = true;
|
||||
$disabled_check_method = "OpenLDAP-pwdAccountLockedTime";
|
||||
|
||||
// If pwdAccountLockedTime attribute exists and has a value, account is locked/disabled
|
||||
$ldap_account_active = (!empty($user['pwdaccountlockedtime'][0])) ? 0 : 1;
|
||||
|
||||
$status = ($ldap_account_active == 1) ? "enabled" : "disabled";
|
||||
logMsg("info", "User " . $user[$iam_settings['username_field']][0] . " is {$status} (OpenLDAP/389DS)");
|
||||
}
|
||||
else {
|
||||
// No disabled attribute found - this is normal for some LDAP implementations
|
||||
// We'll skip disabled state sync for this user
|
||||
logMsg("debug", "User " . $user[$iam_settings['username_field']][0] . " - no disabled attribute found (userAccountControl or pwdAccountLockedTime), skipping status sync");
|
||||
}
|
||||
|
||||
if (empty($user[$iam_settings['username_field']][0])){
|
||||
logMsg("warning", "Skipping user " . $user['displayname'][0] . " due to empty LDAP ". $iam_settings['username_field'] . " property.");
|
||||
continue;
|
||||
@@ -145,6 +180,12 @@ foreach ($response as $user) {
|
||||
|
||||
$_SESSION['access_all_exception'] = '1';
|
||||
if (!$row && intval($iam_settings['import_users']) == 1){
|
||||
// Skip disabled users during import if sync_disabled_users is enabled
|
||||
if (intval($iam_settings['sync_disabled_users']) == 1 && $has_disabled_attr && $ldap_account_active == 0) {
|
||||
logMsg("info", "Skipping import of disabled user " . $user[$iam_settings['username_field']][0] . " (method: {$disabled_check_method})");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($mapper_key === false){
|
||||
if (!empty($iam_settings['default_template'])) {
|
||||
$mbox_template = $iam_settings['default_template'];
|
||||
@@ -174,13 +215,26 @@ foreach ($response as $user) {
|
||||
continue;
|
||||
}
|
||||
$mbox_template = $iam_settings['templates'][$mapper_key];
|
||||
// mailbox user does exist, sync attribtues...
|
||||
logMsg("info", "Syncing attributes for user " . $user[$iam_settings['username_field']][0]);
|
||||
mailbox('edit', 'mailbox_from_template', array(
|
||||
|
||||
// Prepare update data with active status
|
||||
$update_data = array(
|
||||
'username' => $user[$iam_settings['username_field']][0],
|
||||
'name' => $user['displayname'][0],
|
||||
'template' => $mbox_template
|
||||
));
|
||||
);
|
||||
|
||||
// Add active status if sync_disabled_users is enabled and a disabled attribute was found
|
||||
if (intval($iam_settings['sync_disabled_users']) == 1 && $has_disabled_attr) {
|
||||
if ($row['active'] != $ldap_account_active) {
|
||||
$update_data['active'] = $ldap_account_active;
|
||||
$status_change = ($ldap_account_active == 1) ? "enabled" : "disabled";
|
||||
logMsg("info", "Changing active status for user " . $user[$iam_settings['username_field']][0] . " to {$status_change} (method: {$disabled_check_method})");
|
||||
}
|
||||
}
|
||||
|
||||
// mailbox user does exist, sync attributes...
|
||||
logMsg("info", "Syncing attributes for user " . $user[$iam_settings['username_field']][0]);
|
||||
mailbox('edit', 'mailbox_from_template', $update_data);
|
||||
} else {
|
||||
// skip mailbox user
|
||||
logMsg("info", "Skipping user " . $user[$iam_settings['username_field']][0]);
|
||||
|
||||
@@ -2383,6 +2383,7 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
|
||||
case "use_tls":
|
||||
case "login_provisioning":
|
||||
case "ignore_ssl_errors":
|
||||
case "sync_disabled_users":
|
||||
$settings[$row["key"]] = boolval($row["value"]);
|
||||
break;
|
||||
default:
|
||||
@@ -2462,13 +2463,14 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
|
||||
$_data['login_provisioning'] = isset($_data['login_provisioning']) ? boolval($_data['login_provisioning']) : false;
|
||||
switch ($_data['authsource']) {
|
||||
case "keycloak":
|
||||
$_data['server_url'] = (!empty($_data['server_url'])) ? rtrim($_data['server_url'], '/') : null;
|
||||
$_data['mailpassword_flow'] = isset($_data['mailpassword_flow']) ? intval($_data['mailpassword_flow']) : 0;
|
||||
$_data['periodic_sync'] = isset($_data['periodic_sync']) ? intval($_data['periodic_sync']) : 0;
|
||||
$_data['import_users'] = isset($_data['import_users']) ? intval($_data['import_users']) : 0;
|
||||
$_data['sync_interval'] = (!empty($_data['sync_interval'])) ? intval($_data['sync_interval']) : 15;
|
||||
$_data['sync_interval'] = $_data['sync_interval'] < 1 ? 1 : $_data['sync_interval'];
|
||||
$required_settings = array('authsource', 'server_url', 'realm', 'client_id', 'client_secret', 'redirect_url', 'version', 'mailpassword_flow', 'periodic_sync', 'import_users', 'sync_interval', 'ignore_ssl_error', 'login_provisioning');
|
||||
$_data['server_url'] = (!empty($_data['server_url'])) ? rtrim($_data['server_url'], '/') : null;
|
||||
$_data['mailpassword_flow'] = isset($_data['mailpassword_flow']) ? intval($_data['mailpassword_flow']) : 0;
|
||||
$_data['periodic_sync'] = isset($_data['periodic_sync']) ? intval($_data['periodic_sync']) : 0;
|
||||
$_data['import_users'] = isset($_data['import_users']) ? intval($_data['import_users']) : 0;
|
||||
$_data['sync_disabled_users'] = isset($_data['sync_disabled_users']) ? intval($_data['sync_disabled_users']) : 0;
|
||||
$_data['sync_interval'] = (!empty($_data['sync_interval'])) ? intval($_data['sync_interval']) : 15;
|
||||
$_data['sync_interval'] = $_data['sync_interval'] < 1 ? 1 : $_data['sync_interval'];
|
||||
$required_settings = array('authsource', 'server_url', 'realm', 'client_id', 'client_secret', 'redirect_url', 'version', 'mailpassword_flow', 'periodic_sync', 'import_users', 'sync_disabled_users', 'sync_interval', 'ignore_ssl_error', 'login_provisioning');
|
||||
break;
|
||||
case "generic-oidc":
|
||||
$_data['authorize_url'] = (!empty($_data['authorize_url'])) ? $_data['authorize_url'] : null;
|
||||
@@ -2478,18 +2480,19 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
|
||||
$required_settings = array('authsource', 'authorize_url', 'token_url', 'client_id', 'client_secret', 'redirect_url', 'userinfo_url', 'client_scopes', 'ignore_ssl_error', 'login_provisioning');
|
||||
break;
|
||||
case "ldap":
|
||||
$_data['host'] = (!empty($_data['host'])) ? str_replace(" ", "", $_data['host']) : "";
|
||||
$_data['port'] = (!empty($_data['port'])) ? intval($_data['port']) : 389;
|
||||
$_data['username_field'] = (!empty($_data['username_field'])) ? strtolower($_data['username_field']) : "mail";
|
||||
$_data['attribute_field'] = (!empty($_data['attribute_field'])) ? strtolower($_data['attribute_field']) : "";
|
||||
$_data['filter'] = (!empty($_data['filter'])) ? $_data['filter'] : "";
|
||||
$_data['periodic_sync'] = isset($_data['periodic_sync']) ? intval($_data['periodic_sync']) : 0;
|
||||
$_data['import_users'] = isset($_data['import_users']) ? intval($_data['import_users']) : 0;
|
||||
$_data['use_ssl'] = isset($_data['use_ssl']) ? boolval($_data['use_ssl']) : false;
|
||||
$_data['use_tls'] = isset($_data['use_tls']) && !$_data['use_ssl'] ? boolval($_data['use_tls']) : false;
|
||||
$_data['sync_interval'] = (!empty($_data['sync_interval'])) ? intval($_data['sync_interval']) : 15;
|
||||
$_data['sync_interval'] = $_data['sync_interval'] < 1 ? 1 : $_data['sync_interval'];
|
||||
$required_settings = array('authsource', 'host', 'port', 'basedn', 'username_field', 'filter', 'attribute_field', 'binddn', 'bindpass', 'periodic_sync', 'import_users', 'sync_interval', 'use_ssl', 'use_tls', 'ignore_ssl_error', 'login_provisioning');
|
||||
$_data['host'] = (!empty($_data['host'])) ? str_replace(" ", "", $_data['host']) : "";
|
||||
$_data['port'] = (!empty($_data['port'])) ? intval($_data['port']) : 389;
|
||||
$_data['username_field'] = (!empty($_data['username_field'])) ? strtolower($_data['username_field']) : "mail";
|
||||
$_data['attribute_field'] = (!empty($_data['attribute_field'])) ? strtolower($_data['attribute_field']) : "";
|
||||
$_data['filter'] = (!empty($_data['filter'])) ? $_data['filter'] : "";
|
||||
$_data['periodic_sync'] = isset($_data['periodic_sync']) ? intval($_data['periodic_sync']) : 0;
|
||||
$_data['import_users'] = isset($_data['import_users']) ? intval($_data['import_users']) : 0;
|
||||
$_data['sync_disabled_users'] = isset($_data['sync_disabled_users']) ? intval($_data['sync_disabled_users']) : 0;
|
||||
$_data['use_ssl'] = isset($_data['use_ssl']) ? boolval($_data['use_ssl']) : false;
|
||||
$_data['use_tls'] = isset($_data['use_tls']) && !$_data['use_ssl'] ? boolval($_data['use_tls']) : false;
|
||||
$_data['sync_interval'] = (!empty($_data['sync_interval'])) ? intval($_data['sync_interval']) : 15;
|
||||
$_data['sync_interval'] = $_data['sync_interval'] < 1 ? 1 : $_data['sync_interval'];
|
||||
$required_settings = array('authsource', 'host', 'port', 'basedn', 'username_field', 'filter', 'attribute_field', 'binddn', 'bindpass', 'periodic_sync', 'import_users', 'sync_disabled_users', 'sync_interval', 'use_ssl', 'use_tls', 'ignore_ssl_error', 'login_provisioning');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -3691,6 +3691,11 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
}
|
||||
}
|
||||
|
||||
// Override active status if explicitly provided (IDP sync takes priority over template)
|
||||
if (isset($_data['active'])) {
|
||||
$mailbox_attributes['active'] = $_data['active'];
|
||||
}
|
||||
|
||||
$mailbox_attributes['quota'] = intval($mailbox_attributes['quota'] / 1048576);
|
||||
$result = mailbox('edit', 'mailbox', $mailbox_attributes);
|
||||
if ($result === false) return $result;
|
||||
|
||||
@@ -234,6 +234,8 @@
|
||||
"iam_mapping": "Attribut Mapping",
|
||||
"iam_bindpass": "Bind Passwort",
|
||||
"iam_periodic_full_sync": "Vollsynchronisation",
|
||||
"iam_sync_disabled_users": "Deaktivierte Benutzer synchronisieren",
|
||||
"iam_sync_disabled_users_info": "Mailcow-Benutzer automatisch deaktivieren, wenn sie in LDAP/Keycloak deaktiviert sind, und wieder aktivieren, wenn sie reaktiviert werden. Unterstützt Active Directory (userAccountControl), OpenLDAP, 389 Directory Server und FreeIPA (pwdAccountLockedTime).",
|
||||
"iam_port": "Port",
|
||||
"iam_realm": "Realm",
|
||||
"iam_redirect_url": "Redirect Url",
|
||||
|
||||
@@ -241,6 +241,8 @@
|
||||
"iam_mapping": "Attribute Mapping",
|
||||
"iam_bindpass": "Bind Password",
|
||||
"iam_periodic_full_sync": "Periodic Full Sync",
|
||||
"iam_sync_disabled_users": "Sync user disabled status",
|
||||
"iam_sync_disabled_users_info": "Automatically disable mailcow users when they are disabled in LDAP/Keycloak, and re-enable them when they are re-enabled. Supports Active Directory (userAccountControl), OpenLDAP, 389 Directory Server, and FreeIPA (pwdAccountLockedTime).",
|
||||
"iam_port": "Port",
|
||||
"iam_realm": "Realm",
|
||||
"iam_redirect_url": "Redirect Url",
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"alias_domain": "Aizstājdomēni",
|
||||
"alias_domain_info": "<small>Tikai derīgi domēna vārdi (komatu atdalīti).</small>",
|
||||
"automap": "Mēģiniet automatizēt mapes (\"Nosūtītie vienumi\", \"Nosūtītie\" => \"Nosūtītie\" etc.)",
|
||||
"backup_mx_options": "Releja iespējas",
|
||||
"backup_mx_options": "Dublējuma MX iespējas",
|
||||
"delete1": "Izdzēst no avota pēc pabeigšanas",
|
||||
"delete2": "Dzēsiet ziņojumus galamērķī, kas nav avotā",
|
||||
"delete2duplicates": "Izdzēst atkārtojošos vienumus galamērķī",
|
||||
@@ -65,8 +65,8 @@
|
||||
"relay_all": "Pārsūtīt visus saņēmējus",
|
||||
"relay_all_info": "↪ Ja izvēlies <b>nepārsūtīt</b> visus saņēmējus, tad Tev būs nepieciešams pievienot (\"aklo\") pastkasti katram saņēmējam, kas būtu jāpārsūta.",
|
||||
"relay_domain": "Pārsūtīt šo domēnu",
|
||||
"select": "Lūgums atlasīt…",
|
||||
"select_domain": "Lūgums vispirms atlasīt domēnu",
|
||||
"select": "Lūdzu izvēlaties...",
|
||||
"select_domain": "Lūdzu sākumā izvēlaties domēnu",
|
||||
"sieve_desc": "Īss apraksts",
|
||||
"sieve_type": "Filtra tips",
|
||||
"skipcrossduplicates": "Izlaist dublētus ziņojumus pa mapēm (pirmais nāk, pirmais kalpo)",
|
||||
@@ -153,7 +153,7 @@
|
||||
"r_info": "Pelēkie/atspējotie vienumi spēkā esošo ierobežojumu sarakstā mailcow nav zināmi kā derīgi ierobežojumi, un tos nevar pārvietot. Nezināmi ierobežojumi jebkurā gadījumā parādīšanas secībā. <br>Jaunus vienumus var pievienot <code>inc/vars.local.inc.php</code>, lai varētu tos pārslēgt.",
|
||||
"recipients": "Adresāts",
|
||||
"refresh": "Atsvaidzināt",
|
||||
"regen_api_key": "Atkārtoti izveidot API atslēgu",
|
||||
"regen_api_key": "Reģenerēt API atslēgu",
|
||||
"relay_from": "\"No:\" adrese",
|
||||
"relay_run": "Palaist testu",
|
||||
"relayhosts_hint": "Norādīt no sūtītāja atkarīgas piegādes, lai varētu tos atlasīt domēnu konfigurācijas uzvednē.<br>\n Piegādes pakalpojums vienmēr ir \"smtp\", tādējādi tiks mēģināts TLS, kad piedāvāts. Iekļautais TLS (SMTPS) netiek atbalstīts. Tiek ņemts vērā lietotāja atsevišķais izejošā TLS nosacījuma iestatījums.<br>\n Ietekmē atlasītos domēnus, tajā skaitā aizstājdomēnus.",
|
||||
@@ -185,10 +185,7 @@
|
||||
"login_time": "Pieteikšanās laiks",
|
||||
"iam_version": "Versija",
|
||||
"quarantine_max_age": "Lielākais pieļaujamais vecums dienās<br><small>Vērtībai jābūt vienādai ar vai lielākai par 1 dienu.</small>",
|
||||
"quarantine_max_score": "Atmest paziņojumu, ja e-pasta ziņojuma mēstuļu novērtējums ir augstāks par šo vērtību:<br><small>Noklusējums ir 9999.0</small>",
|
||||
"options": "Iespējas",
|
||||
"password_reset_settings": "Paroļu atkopes iestatījumi",
|
||||
"password_settings": "Paroļu iestatījumi"
|
||||
"quarantine_max_score": "Atmest paziņojumu, ja e-pasta ziņojuma mēstuļu novērtējums ir augstāks par šo vērtību:<br><small>Noklusējums ir 9999.0</small>"
|
||||
},
|
||||
"danger": {
|
||||
"access_denied": "Piekļuve liegta, vai nepareizi dati",
|
||||
@@ -260,7 +257,7 @@
|
||||
"active": "Aktīvs",
|
||||
"alias": "Labot aizstājvārdu",
|
||||
"automap": "Mēģiniet automatizēt mapes (\"Nosūtītie vienumi\", \"Nosūtītie\" => \"Nosūtītie\" utt.)",
|
||||
"backup_mx_options": "Retranslācijas iespējams",
|
||||
"backup_mx_options": "Dublēt MX iespējas",
|
||||
"delete1": "Izdzēst no avota pēc pabeigšanas",
|
||||
"delete2": "Dzēsiet ziņojumus galamērķī, kas nav avotā",
|
||||
"delete2duplicates": "Izdzēst atkārtojošos vienumus galamērķī",
|
||||
@@ -561,7 +558,7 @@
|
||||
"key_id_totp": "Identifikators Jūsu atslēgai",
|
||||
"none": "Deaktivizēt",
|
||||
"scan_qr_code": "Lūdzu, skenējiet šo kodu ar savu autentifikācijas lietojumprogrammu vai ievadiet kodu manuāli.",
|
||||
"select": "Lūgums atlasīt",
|
||||
"select": "Lūdzu izvēlaties",
|
||||
"set_tfa": "Uzstādīt difi faktoru autentifik;acijas metodi",
|
||||
"tfa": "Divpakāpju pieteikšanās",
|
||||
"totp": "Uz laiku bāzēta vienreizēja parole (Google Autentifikātors utt.)",
|
||||
|
||||
@@ -249,6 +249,17 @@
|
||||
</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_disabled_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="sync_disabled_users" value="1" {% if iam_settings.sync_disabled_users == 1 %}checked{% endif %}>
|
||||
<label class="form-check-label text-muted small">{{ lang.admin.iam_sync_disabled_users_info }}</label>
|
||||
</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>
|
||||
@@ -696,6 +707,17 @@
|
||||
</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_disabled_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="sync_disabled_users" value="1" {% if iam_settings.sync_disabled_users == 1 %}checked{% endif %}>
|
||||
<label class="form-check-label text-muted small">{{ lang.admin.iam_sync_disabled_users_info }}</label>
|
||||
</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>
|
||||
|
||||
Reference in New Issue
Block a user