// Identity provider sync: status card and run requests (admin system page, identity provider tab). // Runs are executed by the identity-sync cron (every minute); the card polls until the requested run is done. var mailcowIdentity = (function($) { 'use strict'; var POLL_MS = 5000; var POLL_MAX = 36; var polls = 0; var timer = null; var STATUS_CLASS = {ok: 'bg-success', blocked: 'bg-warning text-dark', error: 'bg-danger', pending: 'bg-secondary', running: 'bg-info text-dark'}; // summary counts in display order var COUNTS = ['creates', 'links', 'deactivate', 'restore', 'release', 'missing', 'found', 'updates', 'group_creates', 'group_renames', 'memberships', 'orphaned_groups', 'membership_removals', 'conflicts', 'errors', 'skipped']; var DETAILS = ['conflicts', 'errors', 'deactivate', 'restore', 'missing', 'creates', 'group_creates']; // admin.twig injects the admin lang section as `lang` function L(key) { var src = (typeof lang_admin !== 'undefined') ? lang_admin : ((typeof lang !== 'undefined') ? lang : {}); return (src[key] !== undefined) ? src[key] : key; } function esc(s) { return escapeHtml(s === null || s === undefined ? '' : String(s)); } function badge(label, value, cls) { return '' + esc(label) + ': ' + esc(value) + ''; } function changes(run) { var s = run.summary; if (!s) return ''; if (s.error) return '' + esc(s.error) + ''; var counts = s.counts || {}; var html = ''; $.each(COUNTS, function(i, key) { if (counts[key] > 0) html += badge(L('iam_sync_count_' + key), counts[key], (key === 'errors' || key === 'conflicts') ? 'bg-danger' : null); }); if (html === '') html = '' + esc(L('iam_sync_no_changes')) + ''; var details = $.extend({}, s.details || {}, {errors: s.errors || []}); var lists = ''; $.each(DETAILS, function(i, key) { var items = details[key] || []; if (!items.length) return; lists += '
' + esc(L('iam_sync_count_' + key)) + '
'; }); if (lists !== '') html += '
' + esc(L('iam_sync_details')) + '' + lists + '
'; return html; } function render(status) { var c = status.counts || {}; var counts = badge(L('iam_sync_accounts'), c.accounts || 0) + badge(L('iam_sync_linked'), c.linked || 0) + badge(L('iam_sync_idp_disabled'), c.idp_disabled || 0, c.idp_disabled ? 'bg-warning text-dark' : null) + badge(L('iam_sync_missing'), c.missing || 0, c.missing ? 'bg-warning text-dark' : null); if (!status.sync_enabled) counts += '
' + esc(L('iam_sync_off')) + '
'; $('#iam_sync_counts').html(counts); var rows = $.map(status.runs || [], function(run) { var state = '' + esc(L('iam_sync_status_' + run.status)) + ''; return '' + esc(run.started || run.created) + '' + '' + esc(L('iam_sync_mode_' + run.mode)) + (run.requested_by ? '
' + esc(run.requested_by) + '
' : '') + '' + '' + state + '' + changes(run) + ''; }); $('#iam_sync_runs tbody').html(rows.length ? rows.join('') : '' + esc(L('iam_sync_none')) + ''); return status.runs && status.runs.length && (status.runs[0].status === 'pending' || status.runs[0].status === 'running'); } function load() { clearTimeout(timer); $.get('/api/v1/get/identity-provider/sync-status', function(status) { if (render(status || {}) && polls++ < POLL_MAX) timer = setTimeout(load, POLL_MS); }, 'json'); } function request(mode) { $.ajax({ type: 'POST', dataType: 'json', url: '/api/v1/edit/identity-provider-sync', data: {items: JSON.stringify(['sync']), attr: JSON.stringify({mode: mode}), csrf_token: csrf_token}, success: function(res) { var msg = (res && res[0]) ? res[0] : {type: 'danger', msg: 'generic_server_error'}; var key = $.isArray(msg.msg) ? msg.msg[0] : msg.msg; var text = (msg.type === 'success' ? lang_success : lang_danger)[key] || key; mailcow_alert_box(text, msg.type === 'success' ? 'success' : 'danger'); polls = 0; load(); } }); } $(document).ready(function() { if (!$('#iam_sync_status').length) return; load(); $(document).on('click', '.iam_sync_request', function(e) { e.preventDefault(); var mode = $(this).data('mode'); if (mode === 'force' && !confirm(L('iam_sync_force_confirm'))) return; request(mode); }); }); return {load: load}; })(jQuery);