UNPKG

iobroker.backitup

Version:

ioBroker.backitup allows you to backup and restore your ioBroker installation and other systems, such as databases, Zigbee, scripts and many more.

952 lines (887 loc) 83 kB
// ioBroker.backitup - Copyright (c) by simatec // Please visit https://github.com/simatec/ioBroker.backitup for licence-agreement and further information //Settings var $dialogCommand = null; var $dialogDownload = null; var $output = null; var $dialogCommandProgress; var lastMessage = ''; var restoreIfWait = 5000; var storageTyp = ''; var oldJavascriptsEnabled; var oldZigbeeEnabled; var oldZigbee2MQTTEnabled; var oldesphomeEnabled; var oldNoderedEnabled; var oldJarvisEnabled; var oldHistoryEnabled; var oldYahkaEnabled; function encrypt(key, value) { var result = ''; for (var i = 0; i < value.length; i++) { result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i)); } return result; } function decrypt(key, value) { var result = ''; for (var i = 0; i < value.length; i++) { result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i)); } return result; } function initDialogDownload() { $dialogDownload = $('#dialog-download'); if (!$dialogDownload.data('inited')) { $dialogDownload.data('inited', true); $dialogDownload.modal({ dismissible: false }); } $dialogDownload.modal('open'); } function fetchMySqlConfig(isInitial) { socket.emit('getObjectView', 'system', 'instance', { startkey: 'system.adapter.sql.', endkey: 'system.adapter.sql.\u9999', include_docs: true }, function (err, res) { var found = false; if (res && res.rows && res.rows.length) { for (var i = 0; i < res.rows.length; i++) { var common = res.rows[0].value.common; var native = res.rows[i].value.native; if (common.enabled && native.dbtype === 'mysql') { $('#mySqlUser').val(native.user).trigger('change'); $('#mySqlPassword').val(native.password).trigger('change'); $('#mySqlHost').val(native.host).trigger('change'); $('#mySqlPort').val(native.port === '0' ? 3306 : native.port || 3306).trigger('change'); $('#mySqlName').val(native.dbname).trigger('change'); var id = res.rows[i].value. found = res.rows[i].value._id; break; } } if (!found) { for (var j = 0; j < res.rows.length; j++) { var _native = res.rows[j].value.native; if (_native.dbtype === 'mysql') { $('#mySqlUser').val(_native.user).trigger('change'); $('#mySqlPassword').val(_native.password).trigger('change'); $('#mySqlHost').val(_native.host).trigger('change'); $('#mySqlName').val(_native.dbname).trigger('change'); $('#mySqlPort').val(_native.port === '0' ? 3306 : native.port || 3306).trigger('change'); found = res.rows[j].value._id; break; } } } } if (found) { M.updateTextFields(); found = found.substring('system.adapter.'.length); !isInitial && showMessage(_('Config taken from %s', found), _('BackItUp Information!'), 'info'); } else { !isInitial && showMessage(_('No config found'), _('BackItUp Warning!'), 'info'); } }); } function fetchSqliteConfig(isInitial) { socket.emit('getObjectView', 'system', 'instance', { startkey: 'system.adapter.sql.', endkey: 'system.adapter.sql.\u9999', include_docs: true }, function (err, res) { var found = false; if (res && res.rows && res.rows.length) { for (var i = 0; i < res.rows.length; i++) { var common = res.rows[0].value.common; var native = res.rows[i].value.native; if (common.enabled && native && native.dbtype === 'sqlite' && native.fileName) { const pathLenght = native.fileName.split('/'); $('#sqlitePath').val(pathLenght > 1 ? native.fileName : `/opt/iobroker/iobroker-data/sqlite/${native.fileName}`).trigger('change'); var id = res.rows[i].value. found = res.rows[i].value._id; break; } } if (!found) { for (var j = 0; j < res.rows.length; j++) { var _native = res.rows[j].value.native; if (_native && _native.dbtype === 'sqlite' && _native.fileName) { const pathLenght = _native.fileName.split('/'); $('#sqlitePath').val(pathLenght > 1 ? _native.fileName : `/opt/iobroker/iobroker-data/sqlite/${_native.fileName}`).trigger('change'); found = res.rows[j].value._id; break; } } } } if (found) { M.updateTextFields(); found = found.substring('system.adapter.'.length); !isInitial && showMessage(_('Config taken from %s', found), _('BackItUp Information!'), 'info'); } else { !isInitial && showMessage(_('No config found'), _('BackItUp Warning!'), 'info'); } }); } function fetchPgSqlConfig(isInitial) { socket.emit('getObjectView', 'system', 'instance', { startkey: 'system.adapter.sql.', endkey: 'system.adapter.sql.\u9999', include_docs: true }, function (err, res) { var found = false; if (res && res.rows && res.rows.length) { for (var i = 0; i < res.rows.length; i++) { var common = res.rows[0].value.common; var native = res.rows[i].value.native; if (common.enabled && native.dbtype === 'postgresql') { $('#pgSqlUser').val(native.user).trigger('change'); $('#pgSqlPassword').val(native.password).trigger('change'); $('#pgSqlHost').val(native.host).trigger('change'); $('#pgSqlPort').val(native.port === '0' ? 5432 : native.port || 5432).trigger('change'); $('#pgSqlName').val(native.dbname).trigger('change'); var id = res.rows[i].value. found = res.rows[i].value._id; break; } } if (!found) { for (var j = 0; j < res.rows.length; j++) { var _native = res.rows[j].value.native; if (_native.dbtype === 'postgresql') { $('#pgSqlUser').val(_native.user).trigger('change'); $('#pgSqlPassword').val(_native.password).trigger('change'); $('#pgSqlHost').val(_native.host).trigger('change'); $('#pgSqlName').val(_native.dbname).trigger('change'); $('#pgSqlPort').val(_native.port === '0' ? 5432 : native.port || 5432).trigger('change'); found = res.rows[j].value._id; break; } } } } if (found) { M.updateTextFields(); found = found.substring('system.adapter.'.length); !isInitial && showMessage(_('Config taken from %s', found), _('BackItUp Information!'), 'info'); } else { !isInitial && showMessage(_('No config found'), _('BackItUp Warning!'), 'info'); } }); } function fetchInfluxDBConfig(isInitial) { socket.emit('getObjectView', 'system', 'instance', { startkey: 'system.adapter.influxdb.', endkey: 'system.adapter.influxdb.\u9999', include_docs: true }, function (err, res) { var found = false; if (res && res.rows && res.rows.length) { for (var i = 0; i < res.rows.length; i++) { var common = res.rows[0].value.common; var native = res.rows[i].value.native; if (common.enabled) { $('#influxDBHost').val(native.host).trigger('change'); $('#influxDBVersion').val(native.dbversion).trigger('change'); $('#influxDBVersion').select(); $('#influxDBProtocol').val(native.protocol).trigger('change'); $('#influxDBProtocol').select(); $('#influxDBName').val(native.dbname).trigger('change'); if (native.port && native.dbversion && native.dbversion == '2.x') { $('#influxDBPort').val(native.port).trigger('change'); } var id = res.rows[i].value. found = res.rows[i].value._id; break; } } if (!found) { for (var j = 0; j < res.rows.length; j++) { var _native = res.rows[j].value.native; $('#influxDBHost').val(_native.host).trigger('change'); $('#influxDBVersion').val(_native.dbversion).trigger('change'); $('#influxDBVersion').select(); $('#influxDBProtocol').val(_native.protocol).trigger('change'); $('#influxDBProtocol').select(); $('#influxDBName').val(_native.dbname).trigger('change'); if (_native.port && _native.dbversion && _native.dbversion == '2.x') { $('#influxDBPort').val(_native.port).trigger('change'); } found = res.rows[j].value._id; break; } } } if (found) { M.updateTextFields(); found = found.substring('system.adapter.'.length); !isInitial && showMessage(_('Config taken from %s', found), _('BackItUp Information!'), 'info'); } else { !isInitial && showMessage(_('No config found'), _('BackItUp Warning!'), 'info'); } }); } function fetchCcuConfig(isInitial) { socket.emit('getObjectView', 'system', 'instance', { startkey: 'system.adapter.hm-rpc.', endkey: 'system.adapter.hm-rpc.\u9999', include_docs: true }, function (err, res) { if (res && res.rows && res.rows.length) { var found = false; for (var i = 0; i < res.rows.length; i++) { var common = res.rows[i].value.common; if (common.enabled) { var native = res.rows[i].value.native; $('#ccuHost').val(native.homematicAddress).trigger('change'); $('#ccuUsehttps').prop('checked', native.useHttps); found = res.rows[i].value._id; break; } } if (!found) { for (var j = 0; j < res.rows.length; j++) { var _native = res.rows[j].value.native; $('#ccuHost').val(_native.homematicAddress).trigger('change'); $('#ccuUsehttps').prop('checked', _native.useHttps); found = res.rows[j].value._id; } } } if (found) { M.updateTextFields(); found = found.substring('system.adapter.'.length); !isInitial && showMessage(_('Config taken from %s', found), _('BackItUp Information!'), 'info'); } else { !isInitial && showMessage(_('No config found'), _('BackItUp Warning!'), 'info'); } }); } function fetchHistoryConfig(isInitial) { socket.emit('getObjectView', 'system', 'instance', { startkey: 'system.adapter.history.', endkey: 'system.adapter.history.\u9999', include_docs: true }, function (err, res) { let storeDir = ''; if (res && res.rows && res.rows.length) { var found = false; for (var i = 0; i < res.rows.length; i++) { var common = res.rows[i].value.common; if (common.enabled) { var native = res.rows[i].value.native; $('#historyPath').val(native.storeDir != '' && !native.storeDir.startsWith('/opt/iobroker/backups') ? native.storeDir : '/opt/iobroker/iobroker-data/history').trigger('change'); storeDir = native.storeDir; found = res.rows[i].value._id; break; } } if (!found) { for (var j = 0; j < res.rows.length; j++) { var _native = res.rows[j].value.native; $('#historyPath').val(_native.storeDir != '' && !_native.storeDir.startsWith('/opt/iobroker/backups') ? _native.storeDir : '/opt/iobroker/iobroker-data/history').trigger('change'); storeDir = _native.storeDir; found = res.rows[j].value._id; } } } if (found && storeDir == '') { M.updateTextFields(); found = found.substring('system.adapter.'.length); !isInitial && showMessage(_('<br/><br/>No storage path of %s is configured.<br/>The default path of the history adapter has been set.', found), _('BackItUp Information!'), 'info'); } else if (found && storeDir !== '' && storeDir.startsWith('/opt/iobroker/backups')) { M.updateTextFields(); found = found.substring('system.adapter.'.length); !isInitial && showMessage(_('<br/><br/>The storage path of %s must not be identical to the path for backups.<br/>The default path of the history adapter has been set.<br/><br/>Please change the path in the history adapter!', found), _('BackItUp Information!'), 'info'); } else if (found && storeDir !== '') { M.updateTextFields(); found = found.substring('system.adapter.'.length); !isInitial && showMessage(_('Config taken from %s', found), _('BackItUp Information!'), 'info'); } else { !isInitial && showMessage(_('No config found'), _('BackItUp Warning!'), 'info'); } }); } var ignoreMessage = []; function cleanIgnoreMessage(name) { for (const i in ignoreMessage) { if (ignoreMessage[i] == name) { ignoreMessage.splice(i, 1); break; } } } function checkAdapterInstall(name, backitupHost) { var ignore = false; var adapterName = name; if (name == 'pgsql' || name == 'mysql' || name == 'sqlite') { adapterName = 'sql'; } for (const i in ignoreMessage) { if (ignoreMessage[i] == name) { ignore = true; break; } } if (!ignore) { socket.emit('getObjectView', 'system', 'instance', { startkey: 'system.adapter.' + adapterName + '.', endkey: 'system.adapter.' + adapterName + '.\u9999', include_docs: true }, function (err, res) { if (res && res.rows && res.rows.length) { for (var i = 0; i < res.rows.length; i++) { var common = res.rows[i].value.common; if (common.host !== backitupHost && (adapterName == 'zigbee' || adapterName == 'esphome' || adapterName == 'zigbee2mqtt' || adapterName == 'node-red' || adapterName == 'yahka' || adapterName == 'jarvis' || adapterName == 'history')) { showMessage(_("No %s Instance found on this host. Please check your System", adapterName), _('BackItUp Warning!'), 'info'); ignoreMessage.push(name); break; } } } else if (res.rows.length == 0 && (adapterName == 'zigbee' || adapterName == 'esphome' || adapterName == 'zigbee2mqtt' || adapterName == 'node-red' || adapterName == 'yahka' || adapterName == 'jarvis' || adapterName == 'history')) { showMessage(_("No %s Instance found on this host. Please check your System", adapterName), _('BackItUp Warning!'), 'info'); ignoreMessage.push(name); } }); } } function initDialog() { $dialogCommand = $('#dialog-command'); $output = $dialogCommand.find('#stdout'); $dialogCommandProgress = $dialogCommand.find('.progress div'); $dialogCommand.find('.progress-dont-close input').on('change', function () { if (typeof localStorage !== 'undefined') { localStorage.setItem('backitup-close-on-ready', $(this).prop('checked') ? '1' : '0'); } }); if (typeof localStorage !== 'undefined') { if (localStorage.getItem('backitup-close-on-ready') === '0') { $dialogCommand.find('.progress-dont-close input').prop('checked', false); } else { $dialogCommand.find('.progress-dont-close input').prop('checked', true); } } $dialogCommand.modal({ dismissible: false }); // workaround for materialize checkbox problem $dialogCommand.find('input[type="checkbox"]+span').off('click').on('click', function () { var $input = $(this).prev(); // ignore switch if ($input.parent().parent().hasClass('switch')) return; if (!$input.prop('disabled')) { $input.prop('checked', !$input.prop('checked')).trigger('change'); } }); $dialogCommand.find('.btn').on('click', function () { $dialogCommand.modal('close'); }); } function showDialog(type, isStopped) { $output.val(_(`Started ${type} ...`)); $dialogCommand.modal('open'); $dialogCommand.find('.progress-dont-close').removeClass('disabled'); $dialogCommandProgress.show(); if (type === 'restore' && isStopped === true) { showToast($dialogCommand, _('ioBroker will be stopped and started again. Please wait'), null, 10000); } lastMessage = ''; } function getSize(bytes) { if (bytes > 1024 * 1024 * 512) { return Math.round(bytes / (1024 * 1024 * 1024) * 10) / 10 + 'GiB'; } else if (bytes > 1024 * 1024) { return Math.round(bytes / (1024 * 1024) * 10) / 10 + 'MiB'; } else if (bytes > 1024) { return Math.round(bytes / (1024) * 10) / 10 + 'KiB'; } else { return bytes + ' bytes'; } } function getName(name) { var parts = name.split('_'); if (parseInt(parts[0], 10).toString() !== parts[0]) { parts.shift(); } return new Date( parts[0], parseInt(parts[1], 10) - 1, parseInt(parts[2].split('-')[0], 10), parseInt(parts[2].split('-')[1], 10), parseInt(parts[3], 10)).toLocaleString().replace(/:00$/, ''); } function load(settings, onChange) { if (!settings) return; if (settings.redisEnabled === undefined) { settings.redisEnabled = adapter.config.backupRedis; } if (settings.cifsMount === 'CIFS') { settings.cifsMount = ''; } $('.timepicker').timepicker({ twelveHour: false }); oldJavascriptsEnabled = settings.javascriptsEnabled; oldZigbeeEnabled = settings.zigbeeEnabled; oldesphomeEnabled = settings.esphomeEnabled; oldZigbee2MQTTEnabled = settings.zigbee2mqttEnabled; oldNoderedEnabled = settings.noderedEnabled; oldJarvisEnabled = settings.jarvisEnabled; oldHistoryEnabled = settings.historyEnabled; oldYahkaEnabled = settings.yahkaEnabled; $('.value').each(function () { var $key = $(this); var id = $key.attr('id'); if ($key.attr('type') === 'checkbox') { // do not call onChange direct, because onChange could expect some arguments $key.prop('checked', settings[id]).on('change', function () { showHideSettings(settings); onChange(); }); } else { var val = settings[id]; if (id === 'mySqlPassword' || id === 'pgSqlPassword' || id === 'webdavPassword' || id === 'ccuPassword' || id === 'ftpPassword' || id === 'cifsPassword' || id === 'grafanaPassword' || id === 'redisPassword') { val = val ? decrypt((typeof systemConfig !== 'undefined' && systemConfig.native && systemConfig.native.secret) || 'Zgfr56gFe87jJOM', val) : ''; } // do not call onChange direct, because onChange could expect some arguments $key.val(val).on('change', function () { onChange(); }).on('keyup', function () { onChange(); }); } }); sendTo(null, 'getFileSystemInfo', null, function (obj) { if (obj && obj.diskState && obj.storage && obj.diskFree) { if (obj.diskState === 'warn' && obj.storage === 'local') { showMessage(_('<br/><br/><br/> On the host only %s MB free space is available! Please check your system!', obj.diskFree), _('BackItUp Information!'), 'info'); } else if (obj.diskState === 'error' && obj.storage === 'local') { showMessage(_('<br/><br/><br/> On the host only %s MB free space is available! Local backups are currently not possible. <br/><br/>Please check your system!', obj.diskFree), _('BackItUp Information!'), 'warning'); } } }); sendTo(null, 'getSystemInfo', null, function (obj) { if (obj && obj.systemOS === 'docker' && obj.dockerDB === false) { var $influxDBEnabled = $('#influxDBEnabled'); var $mySqlEnabled = $('#mySqlEnabled'); var $sqliteEnabled = $('#sqliteEnabled'); var $pgSqlEnabled = $('#pgSqlEnabled'); var $startAllRestore = $('#startAllRestore'); $('#influxDBEnabled').prop('checked', false); $('#mySqlEnabled').prop('checked', false); $('#sqliteEnabled').prop('checked', false); $('#pgSqlEnabled').prop('checked', false); $('#startAllRestore').prop('checked', false); $('#influxDBEnabled').prop('disabled', true); $('#mySqlEnabled').prop('disabled', true); $('#sqliteEnabled').prop('disabled', true); $('#pgSqlEnabled').prop('disabled', true); $('#startAllRestore').prop('disabled', true); $influxDBEnabled.addClass('disabled'); $mySqlEnabled.addClass('disabled'); $sqliteEnabled.addClass('disabled'); $pgSqlEnabled.addClass('disabled'); $startAllRestore.addClass('disabled'); // enable only Redis Remote Backup $('.redisDocker').hide(); $('.redisRemote').show(); $('.redisLocal').hide(); if ($('#redisType').val() != 'remote' && $('#redisEnabled').prop('checked')) { $('#redisType').val('remote').trigger('change'); $('#redisType').select(); } } if (obj && obj.systemOS === 'docker') { restoreIfWait = 10000; } else if (obj && obj.systemOS === 'win') { restoreIfWait = 18000; } }); ccuEvents = settings.ccuEvents || []; influxDBEvents = settings.influxDBEvents || []; mySqlEvents = settings.mySqlEvents || []; pgSqlEvents = settings.pgSqlEvents || []; if (pgSqlEvents && pgSqlEvents.length) { for (var i = 0; i < pgSqlEvents.length; i++) { var val = pgSqlEvents[i].pass ? pgSqlEvents[i].pass : ''; pgSqlEvents[i].pass = val ? decrypt((typeof systemConfig !== 'undefined' && systemConfig.native && systemConfig.native.secret) || 'Zgfr56gFe87jJOM', val) : ''; } } if (mySqlEvents && mySqlEvents.length) { for (var i = 0; i < mySqlEvents.length; i++) { var val = mySqlEvents[i].pass ? mySqlEvents[i].pass : ''; mySqlEvents[i].pass = val ? decrypt((typeof systemConfig !== 'undefined' && systemConfig.native && systemConfig.native.secret) || 'Zgfr56gFe87jJOM', val) : ''; } } if (ccuEvents && ccuEvents.length) { for (var i = 0; i < ccuEvents.length; i++) { var val = ccuEvents[i].pass ? ccuEvents[i].pass : ''; ccuEvents[i].pass = val ? decrypt((typeof systemConfig !== 'undefined' && systemConfig.native && systemConfig.native.secret) || 'Zgfr56gFe87jJOM', val) : ''; } } values2table('ccuEvents', ccuEvents, onChange); values2table('influxDBEvents', influxDBEvents, onChange, tableOnReady); values2table('mySqlEvents', mySqlEvents, onChange); values2table('pgSqlEvents', pgSqlEvents, onChange); $('#ccuAdded').on('click', function () { var devices = table2values('ccuEvents'); var id = 0; for (var i = 0; i < devices.length; i++) { id++; } setTimeout(function () { $('#ccuEvents .values-input[data-name="nameSuffix"][data-index="' + id + '"]').val(`CCU-${id + 1}`).trigger('change'); }, 250); }); $('#influxDBAdded').on('click', function () { var devices = table2values('influxDBEvents'); var id = 0; for (var i = 0; i < devices.length; i++) { id++; } setTimeout(function () { $('#influxDBEvents .values-input[data-name="port"][data-index="' + id + '"]').val(8088).trigger('change'); $('#influxDBEvents .values-input[data-name="nameSuffix"][data-index="' + id + '"]').val(`influxDB-${id + 1}`).trigger('change'); $('#influxDBEvents .values-input[data-name="protocol"][data-index="' + id + '"]').val('http').trigger('change'); $('#influxDBEvents .values-input[data-name="dbversion"][data-index="' + id + '"]').val('1.x').trigger('change'); }, 250); }); function tableOnReady() { $('#influxDBEvents .table-values-div .table-values .values-input[data-name="dbversion"]').on('change', function () { let id = $(this).data('index'); var dbversion = $('#influxDBEvents .values-input[data-name="dbversion"][data-index="' + id + '"]').val(); if (dbversion == '1.x') { $('#influxDBEvents .values-input[data-name="token"][data-index="' + id + '"]').prop('disabled', true).trigger('change'); $('#influxDBEvents .values-input[data-name="token"][data-index="' + id + '"]').addClass('hiddenToken').trigger('change'); $('#influxDBEvents .values-input[data-name="port"][data-index="' + id + '"]').val(8088).trigger('change'); } else { $('#influxDBEvents .values-input[data-name="token"][data-index="' + id + '"]').prop('disabled', false).trigger('change'); $('#influxDBEvents .values-input[data-name="token"][data-index="' + id + '"]').removeClass('hiddenToken').trigger('change'); $('#influxDBEvents .values-input[data-name="port"][data-index="' + id + '"]').val(8086).trigger('change'); } }); var devices = table2values('influxDBEvents'); id = 0; for (var i = 0; i < devices.length; i++) { var dbversion = $('#influxDBEvents .values-input[data-name="dbversion"][data-index="' + id + '"]').val(); if (dbversion == '1.x') { $('#influxDBEvents .values-input[data-name="token"][data-index="' + id + '"]').prop('disabled', true).trigger('change'); $('#influxDBEvents .values-input[data-name="token"][data-index="' + id + '"]').addClass('hiddenToken').trigger('change'); } else { $('#influxDBEvents .values-input[data-name="token"][data-index="' + id + '"]').prop('disabled', false).trigger('change'); $('#influxDBEvents .values-input[data-name="token"][data-index="' + id + '"]').removeClass('hiddenToken').trigger('change'); } id++; } } $('#mySqlAdded').on('click', function () { var devices = table2values('mySqlEvents'); var id = 0; for (var i = 0; i < devices.length; i++) { id++; } setTimeout(function () { $('#mySqlEvents .values-input[data-name="port"][data-index="' + id + '"]').val(3306).trigger('change'); $('#mySqlEvents .values-input[data-name="nameSuffix"][data-index="' + id + '"]').val(`mySqlDB-${id + 1}`).trigger('change'); }, 250); }); $('#pgSqlAdded').on('click', function () { var devices = table2values('pgSqlEvents'); var id = 0; for (var i = 0; i < devices.length; i++) { id++; } setTimeout(function () { $('#pgSqlEvents .values-input[data-name="port"][data-index="' + id + '"]').val(5432).trigger('change'); $('#pgSqlEvents .values-input[data-name="nameSuffix"][data-index="' + id + '"]').val(`pgSqlDB-${id + 1}`).trigger('change'); }, 250); }); getIsAdapterAlive(function (isAlive) { if (isAlive || common.enabled) { $('.do-backup') .removeClass('disabled') .on('click', function () { if (changed) { showError(_('Save the configuration first')); return; } var type = $(this).data('type'); socket.emit('setState', adapter + '.' + instance + '.oneClick.' + type, { val: true, ack: false }, function (err) { if (!err) { showDialog(type, null); showToast(null, _('Backup started')); } else { showError(err); } }); }).each(function () { var type = $(this).data('type'); var $btn = $(this); socket.emit('getState', adapter + '.' + instance + '.oneClick.' + type, function (err, state) { if (state && state.val) { $btn.addClass('disabled'); } }); }); socket.on('stateChange', function (id, state) { if (id === 'backitup.' + instance + '.oneClick.ccu') { if (state && state.val) { $('.btn-ccu').addClass('disabled'); } else { $('.btn-ccu').removeClass('disabled'); } } else if (id === 'backitup.' + instance + '.oneClick.total') { if (state && state.val) { $('.btn-total').addClass('disabled'); } else { $('.btn-total').removeClass('disabled'); } } else if (id === 'backitup.' + instance + '.oneClick.iobroker') { if (state && state.val) { $('.btn-iobroker').addClass('disabled'); } else { $('.btn-iobroker').removeClass('disabled'); } } else if (id === 'system.adapter.backitup.' + instance + '.alive') { if (state && state.val) { $('.do-backup').removeClass('disabled'); } else { $('.do-backup').addClass('disabled'); } } else if (id === 'backitup.' + instance + '.output.line') { if (state && state.val && state.val !== lastMessage) { lastMessage = state.val; var text = $output.val(); $output.val(text + '\n' + state.val); if (state.val.match(/^\[EXIT]/)) { var code = state.val.match(/^\[EXIT] ([-\d]+)/); $dialogCommandProgress.hide(); $dialogCommand.find('.progress-dont-close').addClass('disabled'); if ($dialogCommand.find('.progress-dont-close input').prop('checked') && (!code || code[1] === '0')) { setTimeout(function () { $dialogCommand.modal('close'); }, 1500); } } } } }); if (settings.ftpEnabled === false && settings.dropboxEnabled === false && settings.onedriveEnabled === false && settings.cifsEnabled === false && settings.googledriveEnabled === false && settings.webdavEnabled === false) { showMessage(_("<br/><br/>According to the BackItUp settings, backups are currently stored in the same local file system that is the source of the backup can be accessed more. <br/> <br/>It is recommended to use an external storage space as a backup target."), _('BackItUp Information!'), 'info'); } socket.emit('subscribeStates', 'backitup.' + instance + '.*'); socket.emit('subscribeStates', 'system.adapter.backitup.' + instance + '.alive'); socket.on('reconnect', function () { socket.emit('subscribeStates', 'backitup.' + instance + '.*'); socket.emit('subscribeStates', 'system.adapter.backitup.' + instance + '.alive'); }); $('#testWebDAV').on('click', function () { getIsAdapterAlive(function (isAlive) { if (!isAlive) { showToast(null, _('Start or enable adapter first')); } else { $('#testWebDAV').addClass('disabled'); sendTo(null, 'testWebDAV', { config: { host: $('#webdavURL').val(), username: $('#webdavUsername').val(), password: $('#webdavPassword').val(), signedCertificates: $('#webdavSignedCertificates').prop('checked') ? true : false } }, function (response) { $('#testWebDAV').removeClass('disabled'); if (response.error) { showError('Error: ' + response.error); } else { showMessage(_('The connection to the WebDAV server was established successfully.'), _('BackItUp Information!'), 'info'); } }); } }); }); $('.do-list').removeClass('disabled').on('click', function () { $('.do-list').addClass('disabled'); $('#tab-restore').find('.root').html(''); $('.doRestore').hide(); $('.search-ready').hide(); $('.search-error').hide(); $('.progress-search').show(); console.log('Restore Type: ' + $('#restoreSource').val()); sendTo(null, 'list', $('#restoreSource').val(), function (result) { $('.do-list').removeClass('disabled'); console.log(result); if (result && result.error) { $('.progress-search').hide(); $('.search-error').show(); showError(JSON.stringify(result.error)); } if (result && result.data) { $('.progress-search').hide(); $('.search-ready').show(); var text = ''; var data = result.data; console.log(data); for (var type in data) { if (!data.hasOwnProperty(type)) continue; // Storage Translate switch (type) { case 'webdav': storageTyp = 'WebDAV'; break; case 'nas / copy': storageTyp = 'NAS / Copy'; break; case 'local': storageTyp = 'Local'; break; case 'dropbox': storageTyp = 'Dropbox'; break; case 'onedrive': storageTyp = 'Onedrive'; break; case 'ftp': storageTyp = 'FTP'; break; case 'googledrive': storageTyp = 'Google Drive'; break; } text += `<li><div class="collapsible-header top"><i class="material-icons">expand_more</i><h6>${_(storageTyp)}</h6></div>`; text += `<ul class="collapsible-body collection head">`; for (var storage in data[type]) { if (data[type].hasOwnProperty(storage)) { text += `<ul class="collapsible"><li><div class="collapsible-header"><i class="material-icons">expand_more</i><h6>${storage.toUpperCase()}</h6></div>`; text += `<ul class="collapsible-body collection">`; for (var i = data[type][storage].length - 1; i >= 0; i--) { text += `<li title="${_('source type')}: ${_(storageTyp)}\n${_('Type')}: ${storage.charAt(0).toUpperCase() + storage.slice(1)}\n${_('backup time')}: ${getName(data[type][storage][i].name)}\n${_('filesize')}: ${getSize(data[type][storage][i].size)}\n\n${_('name')}:\n${data[type][storage][i].name}" class="collection-item">`; text += `<div>${_('backup time')}: ${getName(data[type][storage][i].name)} | ${_('filesize')}: ${getSize(data[type][storage][i].size)}`; text += `<a class="btn-floating secondary-content do-restore" style="height: 32.4px!important; width: 32.4px!important;" title="${_('Restore Backup File')}" data-file="${data[type][storage][i].path}" data-type="${type}"><i style="line-height: 32.4px;" class="material-icons">restore</i></a>`; text += `<a class="btn-floating secondary-content do-download" style="height: 32.4px!important; width: 32.4px!important;" title="${_('Download Backup File')}" data-file="${data[type][storage][i].path}" data-type="${type}"><i style="line-height: 32.4px;" class="material-icons">file_download</i></a>`; text += `</div></li>`; } text += '</ul></li></ul>'; } } text += '</ul></li>'; } $('.doRestore').show(); var $tabRestore = $('#tab-restore'); $tabRestore .find('.root') .html(text); $tabRestore.find('.collapsible').collapsible(); $tabRestore.find('.do-restore').on('click', function () { var type = $(this).data('type'); var file = $(this).data('file'); var name = file.split('/').pop().split('_')[0]; var message = _('<br/><br/>ioBroker will be restarted during restore.<br/><br/>Confirm with \"OK\".'); var downloadPanel = false; if ($('#restoreSource').val() === 'dropbox' || $('#restoreSource').val() === 'onedrive' || $('#restoreSource').val() === 'googledrive' || $('#restoreSource').val() === 'ftp' || $('#restoreSource').val() === 'webdav') { message = _('<br/><br/>1. Confirm with "OK" and the download begins. Please wait until the download is finished!<br/><br/>2. After download ioBroker will be restarted during restore.'); downloadPanel = true; } var isStopped = false; if (file.search('grafana') == -1 && file.search('jarvis') == -1 && file.search('javascripts') == -1 && file.search('mysql') == -1 && file.search('sqlite') == -1 && file.search('influxDB') == -1 && file.search('pgsql') == -1 && file.search('zigbee') == -1 && file.search('esphome') == -1 && file.search('zigbee2mqtt') == -1 && file.search('nodered') == -1 && file.search('yahka') == -1 && file.search('historyDB') == -1) { isStopped = true; } else { if (downloadPanel) { message = _('<br/><br/>1. Confirm with "OK" and the download begins. Please wait until the download is finished!<br/><br/>2. After the download, the restore begins without restarting ioBroker.'); } else { message = _('<br/><br/>ioBroker will not be restarted for this restore.<br/><br/>Confirm with \"OK\".'); } } if (isStopped) { message += _('<br/><br/><br/><b>After confirmation, a new tab opens with the Restore Log.</b><br/><b>If the tab does not open, please deactivate your popup blocker.</b>') } confirmMessage(name !== '' ? message : _('Ready'), _('Are you sure?'), null, [_('Cancel'), _('OK')], function (result) { if (result === 1) { if (downloadPanel) { $('.cloudRestore').show(); } else { $('.cloudRestore').hide(); } $('.do-list').addClass('disabled'); $('#tab-restore').find('.do-restore').addClass('disabled').hide(); $('#tab-restore').find('.do-download').addClass('disabled').hide(); var name = file.split('/').pop().split('_')[0]; showDialog(name !== '' ? 'restore' : '', isStopped); showToast(null, _('Restore started')); let theme; try { theme = currentTheme(); } catch (e) { // Ignore } sendTo(null, 'restore', { type: type, fileName: file, currentTheme: theme || 'none', currentProtocol: location.protocol, stopIOB: isStopped }, function (result) { if (!result || result.error) { showError('Error: ' + JSON.stringify(result.error)); } else { console.log('Restore finish!') if (isStopped) { var restoreURL = `${location.protocol}//${location.hostname}:8091/backitup-restore.html`; console.log('Restore Url: ' + restoreURL); setTimeout(() => window.open(restoreURL, '_self'), restoreIfWait); //setTimeout(() => $('<a href="' + restoreURL + '">&nbsp;</a>')[0].click(), restoreIfWait); } if (downloadPanel) { $('.cloudRestore').hide(); downloadPanel = false; } } $('.do-list').removeClass('disabled'); $('#tab-restore').find('.do-restore').removeClass('disabled').show(); $('#tab-restore').find('.do-download').removeClass('disabled').show(); }); } }); }); $tabRestore.find('.do-download').on('click', function () { var type = $(this).data('type'); var file = $(this).data('file'); type = type == 'nas / copy' ? 'cifs' : type; $('.downloadFinish').hide(); $('.downloadError').hide(); $('.downloadProgress').show(); $('.do-list').addClass('disabled'); $('#tab-restore').find('.do-restore').addClass('disabled').hide(); $('#tab-restore').find('.do-download').addClass('disabled').hide(); $('#backupDownload_name').text(` "${file.split(/[\\/]/).pop()}" `); $('#backupDownload_source').text(_(storageTyp)); initDialogDownload(); sendTo(null, 'getFile', { type: type, fileName: file, protocol: location.protocol }, function (result) { if (!result || result.error) { $dialogDownload.modal('close'); showError('<br/><br/>Error:<br/><br/>' + JSON.stringify(result.error)); } else { console.log('Download finish!') const downloadLink = document.createElement('a'); downloadLink.setAttribute('href', `${location.protocol}//${location.hostname}:${result.listenPort}/${result.fileName ? result.fileName : file.split(/[\\/]/).pop()}`); downloadLink.style.display = 'none'; document.body.appendChild(downloadLink); try { downloadLink.download = file.split(/[\\/]/).pop(); downloadLink.click(); document.body.removeChild(downloadLink); } catch (e) { console.error(`Cannot access download: ${e}`); window.alert(_('Unfortunately your browser does not support this feature')); $('.downloadProgress').hide(); $('.downloadError').show(); } sendTo(null, 'serverClose', { downloadFinish: true }, function (result) { if (result && result.serverClose) { $('.downloadProgress').hide(); $('.downloadFinish').show(); setTimeout(() => $dialogDownload.modal('close'), 5000); } }); } $('.do-list').removeClass('disabled'); $('#tab-restore').find('.do-restore').removeClass('disabled').show(); $('#tab-restore').find('.do-download').removeClass('disabled').show(); }); }); } }); }); // Dropbox Settings $('.get-dropbox-json').removeClass('disabled').on('click', function () { $('.get-dropbox-json').addClass('disabled'); sendTo(null, 'authDropbox', null, function (obj) { if (obj && obj.url && obj.code_challenge) {