diff --git a/nextcloud_backup/rootfs/opt/nextcloud_backup/routes/api.js b/nextcloud_backup/rootfs/opt/nextcloud_backup/routes/api.js index ff58228..fd260b2 100644 --- a/nextcloud_backup/rootfs/opt/nextcloud_backup/routes/api.js +++ b/nextcloud_backup/rootfs/opt/nextcloud_backup/routes/api.js @@ -12,6 +12,7 @@ const humanFileSize = require("../tools/toolbox").humanFileSize; const cronTools = require("../tools/cronTools"); const logger = require("../config/winston"); +const { add } = require("../config/winston"); router.get("/status", (req, res, next) => { cronTools.updatetNextDate(); @@ -36,11 +37,11 @@ router.get("/formated-local-snap", function (req, res, next) { res.status(500); res.send(""); } - ); -}); - -router.get("/formated-backup-manual", function (req, res, next) { - webdav + ); + }); + + router.get("/formated-backup-manual", function (req, res, next) { + webdav .getFolderContent(webdav.getConf().back_dir + pathTools.manual) .then((contents) => { contents.sort((a, b) => { @@ -52,11 +53,11 @@ router.get("/formated-backup-manual", function (req, res, next) { .catch(() => { res.send(); }); -}); - -router.get("/formated-backup-auto", function (req, res, next) { - let url = webdav.getConf().back_dir + pathTools.auto; - webdav + }); + + router.get("/formated-backup-auto", function (req, res, next) { + let url = webdav.getConf().back_dir + pathTools.auto; + webdav .getFolderContent(url) .then((contents) => { contents.sort((a, b) => { @@ -68,13 +69,13 @@ router.get("/formated-backup-auto", function (req, res, next) { .catch(() => { res.send(); }); -}); - -router.post("/nextcloud-settings", function (req, res, next) { - let settings = req.body; - if (settings.ssl != null && settings.host != null && settings.host != "" && settings.username != null && settings.password != null) { - webdav.setConf(settings); - webdav + }); + + router.post("/nextcloud-settings", function (req, res, next) { + let settings = req.body; + if (settings.ssl != null && settings.host != null && settings.host != "" && settings.username != null && settings.password != null) { + webdav.setConf(settings); + webdav .confIsValid() .then(() => { res.status(201); @@ -84,33 +85,33 @@ router.post("/nextcloud-settings", function (req, res, next) { res.status(406); res.json({ message: err }); }); - } else { - res.status(400); - res.send(); - } -}); - -router.get("/nextcloud-settings", function (req, res, next) { - let conf = webdav.getConf(); - if (conf == null) { - res.status(404); - res.send(); - } else { - res.json(conf); - } -}); - -router.post("/manual-backup", function (req, res, next) { - let id = req.query.id; - let name = req.query.name; - let status = statusTools.getStatus(); - if (status.status == "creating" && status.status == "upload" && status.status == "download") { - res.status(503); - res.send(); - return; - } - - hassioApiTools + } else { + res.status(400); + res.send(); + } + }); + + router.get("/nextcloud-settings", function (req, res, next) { + let conf = webdav.getConf(); + if (conf == null) { + res.status(404); + res.send(); + } else { + res.json(conf); + } + }); + + router.post("/manual-backup", function (req, res, next) { + let id = req.query.id; + let name = req.query.name; + let status = statusTools.getStatus(); + if (status.status == "creating" && status.status == "upload" && status.status == "download") { + res.status(503); + res.send(); + return; + } + + hassioApiTools .downloadSnapshot(id) .then(() => { webdav.uploadFile(id, webdav.getConf().back_dir + pathTools.manual + name + ".tar"); @@ -121,54 +122,61 @@ router.post("/manual-backup", function (req, res, next) { res.status(500); res.send(); }); -}); - -router.post("/new-backup", function (req, res, next) { - let status = statusTools.getStatus(); - if (status.status === "creating" && status.status === "upload" && status.status === "download") { - res.status(503); - res.send(); - return; - } - hassioApiTools + }); + + router.post("/new-backup", function (req, res, next) { + let status = statusTools.getStatus(); + if (status.status === "creating" && status.status === "upload" && status.status === "download") { + res.status(503); + res.send(); + return; + } + hassioApiTools .getVersion() .then((version) => { let name = settingsTools.getFormatedName(true, version); hassioApiTools - .createNewBackup(name) - .then((id) => { - hassioApiTools - .downloadSnapshot(id) - .then(() => { - webdav.uploadFile(id, webdav.getConf().back_dir + pathTools.manual + name + ".tar"); - }) - .catch(() => {}); + .createNewBackup(name) + .then((id) => { + hassioApiTools + .downloadSnapshot(id) + .then(() => { + webdav.uploadFile(id, webdav.getConf().back_dir + pathTools.manual + name + ".tar"); }) .catch(() => {}); + }) + .catch(() => {}); }) .catch(() => {}); - - res.status(201); - res.send(); -}); - -router.get("/backup-settings", function (req, res, next) { - res.send(settingsTools.getSettings()); -}); - -router.post("/backup-settings", function (req, res, next) { - if (settingsTools.check(req.body)) { - settingsTools.setSettings(req.body); - cronTools.startCron(); + + res.status(201); res.send(); - } else { - res.status(400); - res.send(); - } -}); - -router.post("/clean-now", function (req, res, next) { - webdav + }); + + router.get("/backup-settings", function (req, res, next) { + hassioApiTools.getAddonList().then((addonList)=>{ + let data = {}; + data['folders'] = hassioApiTools.getFolderList(); + data['addonList'] = addonList; + data['settings'] = settingsTools.getSettings(); + res.send(data); + }) + + }); + + router.post("/backup-settings", function (req, res, next) { + if (settingsTools.check(req.body)) { + settingsTools.setSettings(req.body); + cronTools.startCron(); + res.send(); + } else { + res.status(400); + res.send(); + } + }); + + router.post("/clean-now", function (req, res, next) { + webdav .clean() .then(() => { hassioApiTools.clean().catch(); @@ -176,21 +184,22 @@ router.post("/clean-now", function (req, res, next) { .catch(() => { hassioApiTools.clean().catch(); }); - res.status(201); - res.send(); -}); - -router.post("/restore", function (req, res, next) { - if (req.body["path"] != null) { - webdav.downloadFile(req.body["path"]).then((path) => { - hassioApiTools.uploadSnapshot(path); - }); - res.status(200); + res.status(201); res.send(); - } else { - res.status(400); - res.send(); - } -}); - -module.exports = router; + }); + + router.post("/restore", function (req, res, next) { + if (req.body["path"] != null) { + webdav.downloadFile(req.body["path"]).then((path) => { + hassioApiTools.uploadSnapshot(path); + }); + res.status(200); + res.send(); + } else { + res.status(400); + res.send(); + } + }); + + module.exports = router; + \ No newline at end of file diff --git a/nextcloud_backup/rootfs/opt/nextcloud_backup/tools/hassioApiTools.js b/nextcloud_backup/rootfs/opt/nextcloud_backup/tools/hassioApiTools.js index 9d6a639..18784cb 100644 --- a/nextcloud_backup/rootfs/opt/nextcloud_backup/tools/hassioApiTools.js +++ b/nextcloud_backup/rootfs/opt/nextcloud_backup/tools/hassioApiTools.js @@ -46,6 +46,75 @@ function getVersion() { }); } +function getAddonList() { + return new Promise((resolve, reject) => { + let token = process.env.HASSIO_TOKEN; + let status = statusTools.getStatus(); + let option = { + headers: { "X-HASSIO-KEY": token }, + responseType: "json", + }; + + got("http://hassio/addons", option) + .then((result) => { + if (status.error_code === 1) { + status.status = "idle"; + status.message = null; + status.error_code = null; + statusTools.setStatus(status); + } + let addons = result.body.data.addons; + let instaled = []; + for(let index in addons){ + let current = addons[index]; + if(current.installed == true){ + instaled.push({slug:current.slug, name: current.name}) + } + } + instaled.sort((a,b)=>{ + var textA = a.name.toUpperCase(); + var textB = b.name.toUpperCase(); + return (textA < textB) ? -1 : (textA > textB) ? 1 : 0; + }); + resolve(instaled); + }) + .catch((error) => { + status.status = "error"; + status.message = "Fail to fetch addons list (" + error.message + ")"; + status.error_code = 1; + statusTools.setStatus(status); + logger.error(status.message); + reject(error.message); + }); + }); +} + +function getFolderList(){ + return [ + { + name: "Homme Assistant configuration", + slug: "homeassistant" + + }, + { + name: "SSL", + slug: "ssl" + }, + { + name: "Share", + slug: "share" + }, + { + name: "Media", + slug: "media" + }, + { + name: "Local add-ons", + slug: "addons/local" + } + ] +} + function getSnapshots() { return new Promise((resolve, reject) => { @@ -302,6 +371,8 @@ function uploadSnapshot(path) { } exports.getVersion = getVersion; +exports.getAddonList = getAddonList; +exports.getFolderList = getFolderList; exports.getSnapshots = getSnapshots; exports.downloadSnapshot = downloadSnapshot; exports.createNewBackup = createNewBackup; diff --git a/nextcloud_backup/rootfs/opt/nextcloud_backup/tools/settingsTools.js b/nextcloud_backup/rootfs/opt/nextcloud_backup/tools/settingsTools.js index 624bc7c..fb231a7 100644 --- a/nextcloud_backup/rootfs/opt/nextcloud_backup/tools/settingsTools.js +++ b/nextcloud_backup/rootfs/opt/nextcloud_backup/tools/settingsTools.js @@ -28,6 +28,7 @@ function check_cron(conf){ function check(conf, fallback = false){ + let needSave = false; if(!check_cron(conf)){ if(fallback){ logger.warn("Bad value for cron settings, fallback to default ") @@ -92,7 +93,39 @@ function check(conf, fallback = false){ return false; } } - if(fallback){ + if(conf.exclude_addon == null){ + if(fallback){ + logger.warn("Bad value for 'exclude_addon', fallback to [] ") + conf.exclude_addon = [] + } + else { + logger.error("Bad value for 'exclude_addon'") + return false; + } + } + if(conf.exclude_folder == null){ + if(fallback){ + logger.warn("Bad value for 'exclude_folder', fallback to [] ") + conf.exclude_folder = [] + } + else { + logger.error("Bad value for 'exclude_folder'") + return false; + } + } + + if(!Array.isArray(conf.exclude_folder)){ + logger.debug("exclude_folder is not array (Empty value), reset..."); + conf.exclude_folder = [] + needSave = true; + } + if(!Array.isArray(conf.exclude_addon)){ + logger.debug("exclude_addon is not array (Empty value), reset..."); + conf.exclude_addon = [] + needSave = true; + } + + if(fallback || needSave){ setSettings(conf); } return true diff --git a/nextcloud_backup/rootfs/opt/nextcloud_backup/views/index.ejs b/nextcloud_backup/rootfs/opt/nextcloud_backup/views/index.ejs index 5429201..3e6ec95 100644 --- a/nextcloud_backup/rootfs/opt/nextcloud_backup/views/index.ejs +++ b/nextcloud_backup/rootfs/opt/nextcloud_backup/views/index.ejs @@ -98,7 +98,7 @@
@@ -263,6 +263,7 @@ var loadingModal = null; document.addEventListener('DOMContentLoaded', function() { + $.ajaxSetup({traditional: true}); updateLocalSnaps(); update_status(); let tooltips = document.querySelectorAll('.tooltipped'); @@ -596,30 +597,30 @@ } } - changeSelect('#cron-drop-settings', data.cron_base); + changeSelect('#cron-drop-settings', data.settings.cron_base); $('#cron-drop-settings').change(updateDropVisibility); - $('#name-template').val(data.name_template); + $('#name-template').val(data.settings.name_template); $('#name-template + label').removeClass("active"); $('#name-template + label').addClass("active"); let timepicker = document.querySelector('#timepicker'); - $('#timepicker').val(data.cron_hour); + $('#timepicker').val(data.settings.cron_hour); $('#timepicker + label').removeClass("active"); $('#timepicker + label').addClass("active"); if (M.Timepicker.getInstance(timepicker) != null) M.Timepicker.getInstance(timepicker).destroy(); - M.Timepicker.init(timepicker, { defaultTime: data.cron_hour, twelveHour: false, container: 'body' }); - $('#cron-drop-day-month-read').val(data.cron_month_day); - $('#cron-drop-day-month').val(data.cron_month_day); + M.Timepicker.init(timepicker, { defaultTime: data.settings.cron_hour, twelveHour: false, container: 'body' }); + $('#cron-drop-day-month-read').val(data.settings.cron_month_day); + $('#cron-drop-day-month').val(data.settings.cron_month_day); $('#cron-drop-day-month-read + label').removeClass("active"); $('#cron-drop-day-month-read + label').addClass("active"); - $('#auto_clean_local').prop('checked', data.auto_clean_local == "true"); - $('#local-snap-keep').val(data.auto_clean_local_keep); - $('#auto_clean_backup').prop('checked', data.auto_clean_backup == "true"); - $('#backup-snap-keep').val(data.auto_clean_backup_keep); + $('#auto_clean_local').prop('checked', data.settings.auto_clean_local == "true"); + $('#local-snap-keep').val(data.settings.auto_clean_local_keep); + $('#auto_clean_backup').prop('checked', data.settings.auto_clean_backup == "true"); + $('#backup-snap-keep').val(data.settings.auto_clean_backup_keep); $('#backup-snap-keep + label').removeClass("active"); @@ -627,9 +628,26 @@ $('#local-snap-keep + label').removeClass("active"); $('#local-snap-keep + label').addClass("active"); - changeSelect('#cron-drop-day', data.cron_weekday); + changeSelect('#cron-drop-day', data.settings.cron_weekday); + let folder_html = "" + for(let index in data.folders){ + let thisFolder = data.folders[index]; + let exclude = data.settings.exclude_folder.includes(thisFolder.slug); + folder_html += `
  • ` + } + $("#folders-div").html(folder_html); + + let addons_html = "" + for(let index in data.addonList){ + let thisAddon = data.addonList[index]; + let exclude = data.settings.exclude_addon.includes(thisAddon.slug); + addons_html += `
  • ` + } + $("#addons-div").html(addons_html); updateDropVisibility(); loadingModal.close(); + M.Modal.getInstance(document.querySelector("#modal-settings-backup")).open() + }); } @@ -672,6 +690,19 @@ let auto_clean_local_keep = $("#local-snap-keep").val(); let auto_clean_backup_keep = $("#backup-snap-keep").val(); let name_template = $('#name-template').val(); + + let excluded_folders_nodes = document.querySelectorAll('.folders-box:not(:checked)'); + let exclude_folder = [""]; + for(let i of excluded_folders_nodes){ + exclude_folder.push(i.id); + } + + let excluded_addons_nodes = document.querySelectorAll('.addons-box:not(:checked)'); + let exclude_addon = [""]; + for(let i of excluded_addons_nodes){ + exclude_addon.push(i.id); + } + loadingModal.open(); $.post('./api/backup-settings', { @@ -684,6 +715,8 @@ auto_clean_local_keep: auto_clean_local_keep, auto_clean_backup: auto_clean_backup, auto_clean_backup_keep: auto_clean_backup_keep, + exclude_addon: exclude_addon, + exclude_folder: exclude_folder }) .done(() => { M.toast({ html: 'check_box Backup settings saved !', classes: "green" }); diff --git a/nextcloud_backup/rootfs/opt/nextcloud_backup/views/modals/backup-settings-modal.ejs b/nextcloud_backup/rootfs/opt/nextcloud_backup/views/modals/backup-settings-modal.ejs index 4644767..4db15f4 100644 --- a/nextcloud_backup/rootfs/opt/nextcloud_backup/views/modals/backup-settings-modal.ejs +++ b/nextcloud_backup/rootfs/opt/nextcloud_backup/views/modals/backup-settings-modal.ejs @@ -14,131 +14,156 @@ You can find all available variables here -
    - - -
    -
    - - -
    -
    -
    -
    - - -
    -
    - -
    -
    - - -
    -
    - -
    -
    - - -
    -
    -

    - -

    + href="https://github.com/Sebclem/hassio-nextcloud-backup/blob/master/naming_template.md">here +
    - -
    -
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +

    + +

    +
    -
    -
    -
    -

    Auto Clean Settings

    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    Auto Clean Local Snapshots
    -
    - -
    +
    +
    +
    Folders
    -
    - - +
    +
      + +
    -
    - +
    -
    -
    -
    Auto Clean Nextcloud Snapshots
    -
    - +
    +
    +
    Addons
    +
    +
    +
    +
      + +
    +
    +
    +
    +
    +
    +
    +

    Auto Clean Settings

    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    Auto Clean Local Snapshots
    +
    + +
    +
    +
    +
    +
    + + +
    -
    -
    - - +
    +
    +
    +
    Auto Clean Nextcloud Snapshots
    +
    + +
    +
    +
    +
    +
    + + +
    +
    + +
    - +
    + +
    + +
    +
    -
    - -
    - -
    -
    -
    - - - - - -
    \ No newline at end of file + + + +
    \ No newline at end of file