mirror of
https://github.com/Sebclem/hassio-nextcloud-backup.git
synced 2024-11-10 19:42:58 +01:00
Compare commits
No commits in common. "18446ca610a7811175f9fc1f52a76a6d067f893e" and "28225dbf670a7b1ef7042b00a5547ba3e407435d" have entirely different histories.
18446ca610
...
28225dbf67
@ -8,5 +8,4 @@
|
|||||||
"javascript.inlayHints.propertyDeclarationTypes.enabled": true,
|
"javascript.inlayHints.propertyDeclarationTypes.enabled": true,
|
||||||
"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": true,
|
"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": true,
|
||||||
"javascript.inlayHints.parameterNames.enabled": "literals",
|
"javascript.inlayHints.parameterNames.enabled": "literals",
|
||||||
"editor.formatOnSave": true
|
|
||||||
}
|
}
|
@ -69,6 +69,11 @@ function postInit() {
|
|||||||
settingsTools.check(settingsTools.getSettings(), true);
|
settingsTools.check(settingsTools.getSettings(), true);
|
||||||
// cronTools.init();
|
// cronTools.init();
|
||||||
|
|
||||||
|
messageManager.error("this is error");
|
||||||
|
messageManager.info("This is info");
|
||||||
|
messageManager.warn("re gerg rg ergrge r ");
|
||||||
|
messageManager.success("zefzegz gze gerg erg zegfze gerg erg aeferg erg erg er");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default postInit;
|
export default postInit;
|
||||||
|
@ -3,7 +3,6 @@ import configRouter from "./config.js";
|
|||||||
import homeAssistant from "./homeAssistant.js"
|
import homeAssistant from "./homeAssistant.js"
|
||||||
import messageRouter from "./messages.js";
|
import messageRouter from "./messages.js";
|
||||||
import webdavRouter from "./webdav.js";
|
import webdavRouter from "./webdav.js";
|
||||||
import statusRouter from "./status.js";
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
@ -11,7 +10,6 @@ const router = express.Router();
|
|||||||
router.use("/homeAssistant", homeAssistant)
|
router.use("/homeAssistant", homeAssistant)
|
||||||
router.use("/config", configRouter);
|
router.use("/config", configRouter);
|
||||||
router.use("/webdav", webdavRouter);
|
router.use("/webdav", webdavRouter);
|
||||||
router.use("/messages", messageRouter);
|
router.use("/messages", messageRouter)
|
||||||
router.use('/status', statusRouter);
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
@ -5,7 +5,6 @@ import {
|
|||||||
validateBackupConfig,
|
validateBackupConfig,
|
||||||
} from "../services/backupConfigService.js";
|
} from "../services/backupConfigService.js";
|
||||||
import { getWebdavConfig, saveWebdavConfig, validateWebdavConfig } from "../services/webdavConfigService.js";
|
import { getWebdavConfig, saveWebdavConfig, validateWebdavConfig } from "../services/webdavConfigService.js";
|
||||||
import { checkWebdavLogin } from "../services/webdavService.js";
|
|
||||||
|
|
||||||
const configRouter = express.Router();
|
const configRouter = express.Router();
|
||||||
|
|
||||||
@ -32,9 +31,6 @@ configRouter.get("/webdav", (req, res, next) => {
|
|||||||
|
|
||||||
configRouter.put("/webdav", (req, res, next) => {
|
configRouter.put("/webdav", (req, res, next) => {
|
||||||
validateWebdavConfig(req.body)
|
validateWebdavConfig(req.body)
|
||||||
.then(() => {
|
|
||||||
return checkWebdavLogin(req.body, true)
|
|
||||||
})
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
saveWebdavConfig(req.body);
|
saveWebdavConfig(req.body);
|
||||||
res.status(204);
|
res.status(204);
|
||||||
@ -42,7 +38,7 @@ configRouter.put("/webdav", (req, res, next) => {
|
|||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
res.status(400);
|
res.status(400);
|
||||||
res.json(error.details ? error.details : error);
|
res.json(error.details);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
import express from "express";
|
|
||||||
import { getStatus } from "../tools/status.js";
|
|
||||||
|
|
||||||
const statusRouter = express.Router();
|
|
||||||
|
|
||||||
|
|
||||||
statusRouter.get('/', (req, res) => {
|
|
||||||
res.json(getStatus());
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
export default statusRouter
|
|
@ -16,9 +16,6 @@ webdavRouter.get("/backup/auto", (req, res, next) => {
|
|||||||
const config = getWebdavConfig();
|
const config = getWebdavConfig();
|
||||||
const backupConf = getBackupConfig();
|
const backupConf = getBackupConfig();
|
||||||
validateWebdavConfig(config)
|
validateWebdavConfig(config)
|
||||||
.then(() => {
|
|
||||||
return webdavService.checkWebdavLogin(config);
|
|
||||||
})
|
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
const value = await webdavService
|
const value = await webdavService
|
||||||
.getBackups(pathTools.auto, config, backupConf.nameTemplate);
|
.getBackups(pathTools.auto, config, backupConf.nameTemplate);
|
||||||
@ -34,9 +31,6 @@ webdavRouter.get("/backup/manual", (req, res, next) => {
|
|||||||
const config = getWebdavConfig();
|
const config = getWebdavConfig();
|
||||||
const backupConf = getBackupConfig();
|
const backupConf = getBackupConfig();
|
||||||
validateWebdavConfig(config)
|
validateWebdavConfig(config)
|
||||||
.then(() => {
|
|
||||||
return webdavService.checkWebdavLogin(config);
|
|
||||||
})
|
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
const value = await webdavService
|
const value = await webdavService
|
||||||
.getBackups(pathTools.manual, config, backupConf.nameTemplate);
|
.getBackups(pathTools.manual, config, backupConf.nameTemplate);
|
||||||
@ -55,9 +49,6 @@ webdavRouter.delete("/", (req, res, next) => {
|
|||||||
validateWebdavConfig(config).then(() => {
|
validateWebdavConfig(config).then(() => {
|
||||||
validator
|
validator
|
||||||
.validateAsync(body)
|
.validateAsync(body)
|
||||||
.then(() => {
|
|
||||||
return webdavService.checkWebdavLogin(config);
|
|
||||||
})
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
webdavService.deleteBackup(body.path, config)
|
webdavService.deleteBackup(body.path, config)
|
||||||
.then(()=>{
|
.then(()=>{
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|
||||||
import FormData from "form-data";
|
import FormData from "form-data";
|
||||||
import got, {
|
import got, { type OptionsOfJSONResponseBody, type Response } from "got";
|
||||||
RequestError,
|
|
||||||
type OptionsOfJSONResponseBody,
|
|
||||||
type PlainResponse,
|
|
||||||
type Response,
|
|
||||||
} from "got";
|
|
||||||
import stream from "stream";
|
import stream from "stream";
|
||||||
import { promisify } from "util";
|
import { promisify } from "util";
|
||||||
import logger from "../config/winston.js";
|
import logger from "../config/winston.js";
|
||||||
@ -23,8 +18,7 @@ import type {
|
|||||||
CoreInfoBody,
|
CoreInfoBody,
|
||||||
SupervisorResponse,
|
SupervisorResponse,
|
||||||
} from "../types/services/ha_os_response.js";
|
} from "../types/services/ha_os_response.js";
|
||||||
import { States, type Status } from "../types/status.js";
|
import type { Status } from "../types/status.js";
|
||||||
import { DateTime } from "luxon";
|
|
||||||
|
|
||||||
const pipeline = promisify(stream.pipeline);
|
const pipeline = promisify(stream.pipeline);
|
||||||
|
|
||||||
@ -92,6 +86,7 @@ function getAddonToBackup(addons: AddonModel[]) {
|
|||||||
return slugs;
|
return slugs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getFolderToBackup() {
|
function getFolderToBackup() {
|
||||||
const excluded_folder = settingsTools.getSettings().exclude_folder;
|
const excluded_folder = settingsTools.getSettings().exclude_folder;
|
||||||
const all_folder = getFolderList();
|
const all_folder = getFolderList();
|
||||||
@ -114,17 +109,9 @@ function getBackups(): Promise<Response<SupervisorResponse<BackupData>>> {
|
|||||||
option
|
option
|
||||||
).then(
|
).then(
|
||||||
(result) => {
|
(result) => {
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.hass.ok = true;
|
|
||||||
status.hass.last_check = DateTime.now();
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.hass.ok = false;
|
|
||||||
status.hass.last_check = DateTime.now();
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
messageManager.error("Fail to fetch Hassio backups", error?.message);
|
messageManager.error("Fail to fetch Hassio backups", error?.message);
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
@ -139,7 +126,7 @@ function downloadSnapshot(id: string): Promise<string> {
|
|||||||
const tmp_file = `./temp/${id}.tar`;
|
const tmp_file = `./temp/${id}.tar`;
|
||||||
const stream = fs.createWriteStream(tmp_file);
|
const stream = fs.createWriteStream(tmp_file);
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
status.status = States.BKUP_DOWNLOAD_HA;
|
status.status = "download";
|
||||||
status.progress = 0;
|
status.progress = 0;
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
const option = {
|
const option = {
|
||||||
@ -160,9 +147,7 @@ function downloadSnapshot(id: string): Promise<string> {
|
|||||||
).then(
|
).then(
|
||||||
() => {
|
() => {
|
||||||
logger.info("Download success !");
|
logger.info("Download success !");
|
||||||
const status = statusTools.getStatus();
|
status.progress = 1;
|
||||||
status.status = States.IDLE;
|
|
||||||
status.progress = undefined;
|
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Snapshot dl size : " + fs.statSync(tmp_file).size / 1024 / 1024
|
"Snapshot dl size : " + fs.statSync(tmp_file).size / 1024 / 1024
|
||||||
@ -175,10 +160,6 @@ function downloadSnapshot(id: string): Promise<string> {
|
|||||||
"Fail to download Home Assistant backup",
|
"Fail to download Home Assistant backup",
|
||||||
reason.message
|
reason.message
|
||||||
);
|
);
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.status = States.IDLE;
|
|
||||||
status.progress = undefined;
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
return Promise.reject(reason);
|
return Promise.reject(reason);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -236,7 +217,7 @@ function createNewBackup(
|
|||||||
folders: string[]
|
folders: string[]
|
||||||
) {
|
) {
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
status.status = States.BKUP_CREATION;
|
status.status = "creating";
|
||||||
status.progress = -1;
|
status.progress = -1;
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
logger.info("Creating new snapshot...");
|
logger.info("Creating new snapshot...");
|
||||||
@ -267,20 +248,12 @@ function createNewBackup(
|
|||||||
.then(
|
.then(
|
||||||
(result) => {
|
(result) => {
|
||||||
logger.info(`Snapshot created with id ${result.body.data.slug}`);
|
logger.info(`Snapshot created with id ${result.body.data.slug}`);
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.status = States.IDLE;
|
|
||||||
status.progress = undefined;
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
(reason) => {
|
(reason) => {
|
||||||
messageManager.error("Fail to create new backup.", reason.message);
|
messageManager.error("Fail to create new backup.", reason.message);
|
||||||
logger.error("Fail to create new backup");
|
logger.error("Fail to create new backup");
|
||||||
logger.error(reason);
|
logger.error(reason);
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.status = States.IDLE;
|
|
||||||
status.progress = undefined;
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
return Promise.reject(reason);
|
return Promise.reject(reason);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -324,7 +297,6 @@ function clean(backups: BackupModel[]) {
|
|||||||
function uploadSnapshot(path: string) {
|
function uploadSnapshot(path: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
status.status = States.BKUP_UPLOAD_HA;
|
|
||||||
status.progress = 0;
|
status.progress = 0;
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
logger.info("Uploading backup...");
|
logger.info("Uploading backup...");
|
||||||
@ -348,36 +320,22 @@ function uploadSnapshot(path: string) {
|
|||||||
logger.info("Upload done...");
|
logger.info("Upload done...");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on("response", (res: PlainResponse) => {
|
.on("response", (res) => {
|
||||||
if (res.statusCode !== 200) {
|
if (res.statusCode !== 200) {
|
||||||
messageManager.error(
|
logger.error(status.message);
|
||||||
"Fail to upload backup to Home Assistant",
|
|
||||||
`Code: ${res.statusCode} Body: ${res.body}`
|
|
||||||
);
|
|
||||||
logger.error("Fail to upload backup to Home Assistant");
|
|
||||||
logger.error(`Code: ${res.statusCode}`);
|
|
||||||
logger.error(`Body: ${res.body}`);
|
|
||||||
fs.unlinkSync(path);
|
fs.unlinkSync(path);
|
||||||
reject(res.statusCode);
|
reject(status.message);
|
||||||
} else {
|
} else {
|
||||||
logger.info(`...Upload finish ! (status: ${res.statusCode})`);
|
logger.info(`...Upload finish ! (status: ${res.statusCode})`);
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.status = States.IDLE;
|
|
||||||
status.progress = undefined;
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
fs.unlinkSync(path);
|
fs.unlinkSync(path);
|
||||||
resolve(res);
|
resolve(res);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on("error", (err: RequestError) => {
|
.on("error", (err) => {
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.status = States.IDLE;
|
|
||||||
status.progress = undefined;
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
fs.unlinkSync(path);
|
fs.unlinkSync(path);
|
||||||
messageManager.error(
|
messageManager.error(
|
||||||
"Fail to upload backup to Home Assistant",
|
"Fail to upload backup to Home Assistant",
|
||||||
err.message
|
err?.message
|
||||||
);
|
);
|
||||||
logger.error("Fail to upload backup to Home Assistant");
|
logger.error("Fail to upload backup to Home Assistant");
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
@ -388,10 +346,6 @@ function uploadSnapshot(path: string) {
|
|||||||
|
|
||||||
function stopAddons(addonSlugs: string[]) {
|
function stopAddons(addonSlugs: string[]) {
|
||||||
logger.info("Stopping addons...");
|
logger.info("Stopping addons...");
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.status = States.STOP_ADDON;
|
|
||||||
status.progress = -1;
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
const promises = [];
|
const promises = [];
|
||||||
const option: OptionsOfJSONResponseBody = {
|
const option: OptionsOfJSONResponseBody = {
|
||||||
headers: { authorization: `Bearer ${token}` },
|
headers: { authorization: `Bearer ${token}` },
|
||||||
@ -405,16 +359,11 @@ function stopAddons(addonSlugs: string[]) {
|
|||||||
}
|
}
|
||||||
return Promise.allSettled(promises).then((values) => {
|
return Promise.allSettled(promises).then((values) => {
|
||||||
let errors = false;
|
let errors = false;
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.status = States.IDLE;
|
|
||||||
status.progress = undefined;
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
for (const val of values) {
|
for (const val of values) {
|
||||||
if (val.status == "rejected") {
|
if (val.status == "rejected") {
|
||||||
messageManager.error("Fail to stop addon", val.reason);
|
messageManager.error("Fail to stop addon", val.reason);
|
||||||
logger.error("Fail to stop addon");
|
logger.error("Fail to stop addon");
|
||||||
logger.error(val.reason);
|
logger.error(val.reason);
|
||||||
logger.error;
|
|
||||||
errors = true;
|
errors = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,7 +378,7 @@ function stopAddons(addonSlugs: string[]) {
|
|||||||
function startAddons(addonSlugs: string[]) {
|
function startAddons(addonSlugs: string[]) {
|
||||||
logger.info("Starting addons...");
|
logger.info("Starting addons...");
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
status.status = States.START_ADDON;
|
status.status = "starting";
|
||||||
status.progress = -1;
|
status.progress = -1;
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
const promises = [];
|
const promises = [];
|
||||||
@ -444,10 +393,6 @@ function startAddons(addonSlugs: string[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Promise.allSettled(promises).then((values) => {
|
return Promise.allSettled(promises).then((values) => {
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.status = States.IDLE;
|
|
||||||
status.progress = undefined;
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
let errors = false;
|
let errors = false;
|
||||||
for (const val of values) {
|
for (const val of values) {
|
||||||
if (val.status == "rejected") {
|
if (val.status == "rejected") {
|
||||||
@ -490,6 +435,7 @@ export function getFolderList() {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function publish_state(state: Status) {
|
function publish_state(state: Status) {
|
||||||
// let data_error_sensor = {
|
// let data_error_sensor = {
|
||||||
// state: state.status == "error" ? "on" : "off",
|
// state: state.status == "error" ? "on" : "off",
|
||||||
@ -565,5 +511,5 @@ export {
|
|||||||
startAddons,
|
startAddons,
|
||||||
clean,
|
clean,
|
||||||
publish_state,
|
publish_state,
|
||||||
getBackupInfo,
|
getBackupInfo
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
import { XMLParser } from "fast-xml-parser";
|
import { XMLParser } from "fast-xml-parser";
|
||||||
import { createReadStream, stat, statSync, unlinkSync } from "fs";
|
import { createReadStream, statSync, unlinkSync } from "fs";
|
||||||
import got, {
|
import got, { HTTPError, type Method } from "got";
|
||||||
HTTPError,
|
|
||||||
RequestError,
|
|
||||||
type Method,
|
|
||||||
type PlainResponse,
|
|
||||||
} from "got";
|
|
||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
import logger from "../config/winston.js";
|
import logger from "../config/winston.js";
|
||||||
import messageManager from "../tools/messageManager.js";
|
import messageManager from "../tools/messageManager.js";
|
||||||
@ -15,7 +10,7 @@ import type { WebdavBackup } from "../types/services/webdav.js";
|
|||||||
import type { WebdavConfig } from "../types/services/webdavConfig.js";
|
import type { WebdavConfig } from "../types/services/webdavConfig.js";
|
||||||
import { templateToRegexp } from "./backupConfigService.js";
|
import { templateToRegexp } from "./backupConfigService.js";
|
||||||
import { getEndpoint } from "./webdavConfigService.js";
|
import { getEndpoint } from "./webdavConfigService.js";
|
||||||
import { States } from "../types/status.js";
|
import { WebdabStatus } from "../types/status.js";
|
||||||
|
|
||||||
const PROPFIND_BODY =
|
const PROPFIND_BODY =
|
||||||
'<?xml version="1.0" encoding="utf-8" ?>\
|
'<?xml version="1.0" encoding="utf-8" ?>\
|
||||||
@ -29,10 +24,7 @@ const PROPFIND_BODY =
|
|||||||
</d:prop>\
|
</d:prop>\
|
||||||
</d:propfind>';
|
</d:propfind>';
|
||||||
|
|
||||||
export function checkWebdavLogin(
|
export function checkWebdavLogin(config: WebdavConfig) {
|
||||||
config: WebdavConfig,
|
|
||||||
silent: boolean = false
|
|
||||||
) {
|
|
||||||
const endpoint = getEndpoint(config);
|
const endpoint = getEndpoint(config);
|
||||||
return got(config.url + endpoint, {
|
return got(config.url + endpoint, {
|
||||||
method: "OPTIONS",
|
method: "OPTIONS",
|
||||||
@ -43,21 +35,16 @@ export function checkWebdavLogin(
|
|||||||
},
|
},
|
||||||
}).then(
|
}).then(
|
||||||
(response) => {
|
(response) => {
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.webdav.logged_in = true;
|
|
||||||
status.webdav.last_check = DateTime.now();
|
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
(reason) => {
|
(reason) => {
|
||||||
if (!silent) {
|
|
||||||
messageManager.error("Fail to connect to Webdav", reason?.message);
|
messageManager.error("Fail to connect to Webdav", reason?.message);
|
||||||
}
|
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
status.webdav = {
|
status.webdav = {
|
||||||
logged_in: false,
|
state: WebdabStatus.LOGIN_FAIL,
|
||||||
folder_created: status.webdav.folder_created,
|
blocked: true,
|
||||||
last_check: DateTime.now(),
|
last_check: DateTime.now()
|
||||||
};
|
}
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
logger.error(`Fail to connect to Webdav`);
|
logger.error(`Fail to connect to Webdav`);
|
||||||
logger.error(reason);
|
logger.error(reason);
|
||||||
@ -83,8 +70,11 @@ export async function createBackupFolder(conf: WebdavConfig) {
|
|||||||
logger.error("Fail to create webdav root folder");
|
logger.error("Fail to create webdav root folder");
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
status.webdav.folder_created = false;
|
status.webdav = {
|
||||||
status.webdav.last_check = DateTime.now();
|
state: WebdabStatus.MK_FOLDER_FAIL,
|
||||||
|
blocked: true,
|
||||||
|
last_check: DateTime.now()
|
||||||
|
}
|
||||||
statusTools.setStatus(status);
|
statusTools.setStatus(status);
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
@ -102,18 +92,10 @@ export async function createBackupFolder(conf: WebdavConfig) {
|
|||||||
messageManager.error("Fail to create webdav root folder");
|
messageManager.error("Fail to create webdav root folder");
|
||||||
logger.error("Fail to create webdav root folder");
|
logger.error("Fail to create webdav root folder");
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.webdav.folder_created = false;
|
|
||||||
status.webdav.last_check = DateTime.now();
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.webdav.folder_created = true;
|
|
||||||
status.webdav.last_check = DateTime.now();
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDirectory(path: string, config: WebdavConfig) {
|
function createDirectory(path: string, config: WebdavConfig) {
|
||||||
@ -133,10 +115,6 @@ export function getBackups(
|
|||||||
config: WebdavConfig,
|
config: WebdavConfig,
|
||||||
nameTemplate: string
|
nameTemplate: string
|
||||||
) {
|
) {
|
||||||
const status = statusTools.getStatus();
|
|
||||||
if (!status.webdav.logged_in && !status.webdav.folder_created) {
|
|
||||||
return Promise.reject("Not logged in");
|
|
||||||
}
|
|
||||||
const endpoint = getEndpoint(config);
|
const endpoint = getEndpoint(config);
|
||||||
return got(config.url + endpoint + config.backupDir + folder, {
|
return got(config.url + endpoint + config.backupDir + folder, {
|
||||||
method: "PROPFIND" as Method,
|
method: "PROPFIND" as Method,
|
||||||
@ -182,8 +160,8 @@ function extractBackupInfo(backups: WebdavBackup[], template: string) {
|
|||||||
|
|
||||||
elem.creationDate = DateTime.fromFormat(date, format);
|
elem.creationDate = DateTime.fromFormat(date, format);
|
||||||
}
|
}
|
||||||
if (match?.groups?.version) {
|
if(match?.groups?.version){
|
||||||
elem.haVersion = match.groups.version;
|
elem.haVersion = match.groups.version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return backups;
|
return backups;
|
||||||
@ -246,14 +224,13 @@ function parseXmlBackupData(body: string, config: WebdavConfig) {
|
|||||||
return backups;
|
return backups;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function webdavUploadFile(
|
export function webdabUploadFile(
|
||||||
localPath: string,
|
localPath: string,
|
||||||
webdavPath: string,
|
webdavPath: string,
|
||||||
config: WebdavConfig
|
config: WebdavConfig
|
||||||
) {
|
) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
logger.info(`Uploading ${localPath} to webdav...`);
|
logger.info(`Uploading ${localPath} to webdav...`);
|
||||||
|
|
||||||
const stats = statSync(localPath);
|
const stats = statSync(localPath);
|
||||||
const stream = createReadStream(localPath);
|
const stream = createReadStream(localPath);
|
||||||
const options = {
|
const options = {
|
||||||
@ -274,9 +251,6 @@ export function webdavUploadFile(
|
|||||||
logger.debug(`...URI: ${encodeURI(url)}`);
|
logger.debug(`...URI: ${encodeURI(url)}`);
|
||||||
logger.debug(`...rejectUnauthorized: ${options.https?.rejectUnauthorized}`);
|
logger.debug(`...rejectUnauthorized: ${options.https?.rejectUnauthorized}`);
|
||||||
const status = statusTools.getStatus();
|
const status = statusTools.getStatus();
|
||||||
status.status = States.BKUP_UPLOAD_CLOUD;
|
|
||||||
status.progress = 0;
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
got.stream
|
got.stream
|
||||||
.put(encodeURI(url), options)
|
.put(encodeURI(url), options)
|
||||||
.on("uploadProgress", (e) => {
|
.on("uploadProgress", (e) => {
|
||||||
@ -289,19 +263,16 @@ export function webdavUploadFile(
|
|||||||
logger.info("Upload done...");
|
logger.info("Upload done...");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on("response", (res: PlainResponse) => {
|
.on("response", (res) => {
|
||||||
const status = statusTools.getStatus();
|
|
||||||
status.status = States.IDLE;
|
|
||||||
status.progress = undefined;
|
|
||||||
statusTools.setStatus(status);
|
|
||||||
if (res.statusCode != 201 && res.statusCode != 204) {
|
if (res.statusCode != 201 && res.statusCode != 204) {
|
||||||
messageManager.error(
|
messageManager.error(
|
||||||
"Fail to upload file to Cloud.",
|
"Fail to upload file to webdav.",
|
||||||
`Code: ${res.statusCode} Body: ${res.body}`
|
`Status code: ${res.statusCode}`
|
||||||
);
|
);
|
||||||
logger.error(`Fail to upload file to Cloud`);
|
logger.error(
|
||||||
logger.error(`Code: ${res.statusCode}`);
|
`Fail to upload file to webdav, Status code: ${res.statusCode}`
|
||||||
logger.error(`Body: ${res.body}`);
|
);
|
||||||
|
logger.error(status.message);
|
||||||
unlinkSync(localPath);
|
unlinkSync(localPath);
|
||||||
reject(res);
|
reject(res);
|
||||||
} else {
|
} else {
|
||||||
@ -310,16 +281,10 @@ export function webdavUploadFile(
|
|||||||
resolve(undefined);
|
resolve(undefined);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on("error", (err: RequestError) => {
|
.on("error", (err) => {
|
||||||
const status = statusTools.getStatus();
|
logger.error(status.message);
|
||||||
status.status = States.IDLE;
|
logger.error(err.stack);
|
||||||
status.progress = undefined;
|
reject(status.message);
|
||||||
statusTools.setStatus(status);
|
|
||||||
messageManager.error("Fail to upload backup to Cloud", err.message);
|
|
||||||
logger.error("Fail to upload backup to Cloud");
|
|
||||||
logger.error(err);
|
|
||||||
unlinkSync(localPath);
|
|
||||||
reject(err);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,25 @@
|
|||||||
import { publish_state } from "../services/homeAssistantService.js";
|
import { publish_state } from "../services/homeAssistantService.js";
|
||||||
import { States, type Status } from "../types/status.js";
|
import logger from "../config/winston.js";
|
||||||
|
import { type Status, WebdabStatus } from "../types/status.js";
|
||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
|
|
||||||
let status: Status = {
|
let status: Status = {
|
||||||
status: States.IDLE,
|
status: "idle",
|
||||||
last_backup: {},
|
last_backup: undefined,
|
||||||
next_backup: undefined,
|
next_backup: undefined,
|
||||||
progress: undefined,
|
progress: -1,
|
||||||
webdav: {
|
webdav: {
|
||||||
logged_in: false,
|
state: WebdabStatus.INIT,
|
||||||
folder_created: false,
|
|
||||||
last_check: DateTime.now(),
|
|
||||||
},
|
|
||||||
hass: {
|
|
||||||
ok: false,
|
|
||||||
last_check: DateTime.now(),
|
last_check: DateTime.now(),
|
||||||
|
blocked: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
if (status.status !== States.IDLE) {
|
if (status.status !== "idle") {
|
||||||
status.status = States.IDLE;
|
status.status = "idle";
|
||||||
status.progress = undefined;
|
status.message = undefined;
|
||||||
|
status.progress = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,3 +34,13 @@ export function setStatus(new_state: Status) {
|
|||||||
publish_state(status);
|
publish_state(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setError(message: string, error_code: number) {
|
||||||
|
// Check if we don't have another error stored
|
||||||
|
if (status.status != "error") {
|
||||||
|
status.status = "error";
|
||||||
|
status.message = message;
|
||||||
|
status.error_code = error_code;
|
||||||
|
}
|
||||||
|
logger.error(message);
|
||||||
|
}
|
||||||
|
@ -1,32 +1,24 @@
|
|||||||
import type { DateTime } from "luxon";
|
import type { DateTime } from "luxon";
|
||||||
|
|
||||||
export enum States {
|
export enum WebdabStatus {
|
||||||
IDLE = "IDLE",
|
OK = "OK",
|
||||||
BKUP_CREATION = "BKUP_CREATION",
|
LOGIN_FAIL = "LOGIN_FAIL",
|
||||||
BKUP_DOWNLOAD_HA = "BKUP_DOWNLOAD_HA",
|
UPLOAD_FAIL = "UPLOAD_FAIL",
|
||||||
BKUP_DOWNLOAD_CLOUD = "BKUP_DOWNLOAD_CLOUD",
|
CON_ERROR = "CON_ERROR",
|
||||||
BKUP_UPLOAD_HA = "BKUP_UPLOAD_HA",
|
INIT = "INIT",
|
||||||
BKUP_UPLOAD_CLOUD = "BKUP_UPLOAD_CLOUD",
|
MK_FOLDER_FAIL = "MK_FOLDER_FAIL"
|
||||||
STOP_ADDON = "STOP_ADDON",
|
|
||||||
START_ADDON = "START_ADDON",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Status {
|
export interface Status {
|
||||||
status: States;
|
status: string;
|
||||||
progress?: number;
|
progress: number;
|
||||||
last_backup: {
|
last_backup?: string;
|
||||||
success?: boolean;
|
|
||||||
last_success?: DateTime;
|
|
||||||
message?: string;
|
|
||||||
};
|
|
||||||
next_backup?: string;
|
next_backup?: string;
|
||||||
|
message?: string;
|
||||||
|
error_code?: number;
|
||||||
webdav: {
|
webdav: {
|
||||||
logged_in: boolean;
|
state: WebdabStatus;
|
||||||
folder_created: boolean;
|
|
||||||
last_check: DateTime;
|
|
||||||
};
|
|
||||||
hass: {
|
|
||||||
ok: boolean;
|
|
||||||
last_check: DateTime;
|
last_check: DateTime;
|
||||||
|
blocked: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"recommendations": ["Vue.volar"]
|
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||||
}
|
}
|
||||||
|
1
nextcloud_backup/frontend/components.d.ts
vendored
1
nextcloud_backup/frontend/components.d.ts
vendored
@ -26,7 +26,6 @@ declare module 'vue' {
|
|||||||
NavbarComponent: typeof import('./src/components/NavbarComponent.vue')['default']
|
NavbarComponent: typeof import('./src/components/NavbarComponent.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
StatusComponent: typeof import('./src/components/StatusComponent.vue')['default']
|
|
||||||
WebdavConfigForm: typeof import('./src/components/settings/WebdavConfigForm.vue')['default']
|
WebdavConfigForm: typeof import('./src/components/settings/WebdavConfigForm.vue')['default']
|
||||||
WebdavConfigMenu: typeof import('./src/components/settings/WebdavConfigMenu.vue')['default']
|
WebdavConfigMenu: typeof import('./src/components/settings/WebdavConfigMenu.vue')['default']
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/types": "^7.23.0",
|
"@babel/types": "^7.23.0",
|
||||||
"@types/luxon": "^3.4.2",
|
|
||||||
"@types/node": "^20.10.0",
|
"@types/node": "^20.10.0",
|
||||||
"@vitejs/plugin-vue": "^4.5.0",
|
"@vitejs/plugin-vue": "^4.5.0",
|
||||||
"@vue/eslint-config-typescript": "^12.0.0",
|
"@vue/eslint-config-typescript": "^12.0.0",
|
||||||
|
@ -37,9 +37,6 @@ devDependencies:
|
|||||||
'@babel/types':
|
'@babel/types':
|
||||||
specifier: ^7.23.0
|
specifier: ^7.23.0
|
||||||
version: 7.23.9
|
version: 7.23.9
|
||||||
'@types/luxon':
|
|
||||||
specifier: ^3.4.2
|
|
||||||
version: 3.4.2
|
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.10.0
|
specifier: ^20.10.0
|
||||||
version: 20.11.19
|
version: 20.11.19
|
||||||
@ -529,10 +526,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/luxon@3.4.2:
|
|
||||||
resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/node@20.11.19:
|
/@types/node@20.11.19:
|
||||||
resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==}
|
resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2,21 +2,16 @@
|
|||||||
<v-app>
|
<v-app>
|
||||||
<navbar-component></navbar-component>
|
<navbar-component></navbar-component>
|
||||||
<message-bar></message-bar>
|
<message-bar></message-bar>
|
||||||
<webdav-config-menu @saved="cloudList?.refreshBackup"></webdav-config-menu>
|
<webdav-settings-menu></webdav-settings-menu>
|
||||||
<backup-config-menu></backup-config-menu>
|
<backup-config-menu></backup-config-menu>
|
||||||
<alert-manager></alert-manager>
|
<alert-manager></alert-manager>
|
||||||
<v-main class="mx-12">
|
<v-main class="mx-12">
|
||||||
<v-row>
|
|
||||||
<v-col cols="4" offset="1">
|
|
||||||
<status-component></status-component>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<ha-list></ha-list>
|
<ha-list></ha-list>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<cloud-list ref="cloudList"></cloud-list>
|
<cloud-list></cloud-list>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-main>
|
</v-main>
|
||||||
@ -24,16 +19,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
|
||||||
import AlertManager from "./components/AlertManager.vue";
|
import AlertManager from "./components/AlertManager.vue";
|
||||||
import CloudList from "./components/cloud/CloudList.vue";
|
import CloudList from "./components/cloud/CloudList.vue";
|
||||||
import HaList from "./components/homeAssistant/HaList.vue";
|
import HaList from "./components/homeAssistant/HaList.vue";
|
||||||
import MessageBar from "./components/MessageBar.vue";
|
import MessageBar from "./components/MessageBar.vue";
|
||||||
import NavbarComponent from "./components/NavbarComponent.vue";
|
import NavbarComponent from "./components/NavbarComponent.vue";
|
||||||
import BackupConfigMenu from "./components/settings/BackupConfigMenu.vue";
|
import BackupConfigMenu from "./components/settings/BackupConfigMenu.vue";
|
||||||
import WebdavConfigMenu from "./components/settings/WebdavConfigMenu.vue";
|
import WebdavSettingsMenu from "./components/settings/WebdavConfigMenu.vue";
|
||||||
import StatusComponent from "./components/StatusComponent.vue";
|
|
||||||
const cloudList = ref<InstanceType<typeof CloudList> | null>(null);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -11,7 +11,9 @@
|
|||||||
class="mb-2"
|
class="mb-2"
|
||||||
>
|
>
|
||||||
<v-row dense>
|
<v-row dense>
|
||||||
<v-col v-html="alert.message"></v-col>
|
<v-col>
|
||||||
|
{{ alert.message }}
|
||||||
|
</v-col>
|
||||||
<v-col cols="2">
|
<v-col cols="2">
|
||||||
<v-btn
|
<v-btn
|
||||||
class="d-inline"
|
class="d-inline"
|
||||||
|
@ -1,130 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<v-card class="mt-5" border elevation="10">
|
|
||||||
<v-card-title class="text-center">Status</v-card-title>
|
|
||||||
<v-divider></v-divider>
|
|
||||||
<v-card-text>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols="6">
|
|
||||||
<v-card variant="elevated" border>
|
|
||||||
<v-card-text class="align-center d-flex justify-center">
|
|
||||||
<span class="me-auto">Home Assistant</span>
|
|
||||||
<v-tooltip content-class="bg-black">
|
|
||||||
<template v-slot:activator="{ props }">
|
|
||||||
<v-chip
|
|
||||||
v-bind="props"
|
|
||||||
variant="elevated"
|
|
||||||
:prepend-icon="hassProps.icon"
|
|
||||||
:color="hassProps.color"
|
|
||||||
:text="hassProps.text"
|
|
||||||
>
|
|
||||||
</v-chip>
|
|
||||||
</template>
|
|
||||||
Last check:
|
|
||||||
{{
|
|
||||||
status?.hass.last_check
|
|
||||||
? DateTime.fromISO(status.hass.last_check).toLocaleString(
|
|
||||||
DateTime.DATETIME_MED
|
|
||||||
)
|
|
||||||
: "UNKNOWN"
|
|
||||||
}}
|
|
||||||
</v-tooltip>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="6">
|
|
||||||
<v-card variant="elevated" border>
|
|
||||||
<v-card-text class="align-center d-flex justify-center">
|
|
||||||
<span class="me-auto">Cloud</span>
|
|
||||||
<v-tooltip content-class="bg-black">
|
|
||||||
<template v-slot:activator="{ props }">
|
|
||||||
<v-chip
|
|
||||||
v-bind="props"
|
|
||||||
variant="elevated"
|
|
||||||
:prepend-icon="webdavProps.icon"
|
|
||||||
:color="webdavProps.color"
|
|
||||||
:text="webdavProps.text"
|
|
||||||
>
|
|
||||||
</v-chip>
|
|
||||||
</template>
|
|
||||||
<span>Login: </span>
|
|
||||||
<span :class="'text-' + webdavLoggedProps.color">
|
|
||||||
{{ webdavLoggedProps.text }}
|
|
||||||
</span>
|
|
||||||
<br />
|
|
||||||
<span>Folder: </span>
|
|
||||||
<span :class="'text-' + webdavFolderProps.color">
|
|
||||||
{{ webdavFolderProps.text }}
|
|
||||||
</span>
|
|
||||||
<p>
|
|
||||||
Last check:
|
|
||||||
{{
|
|
||||||
status?.webdav.last_check
|
|
||||||
? DateTime.fromISO(
|
|
||||||
status.webdav.last_check
|
|
||||||
).toLocaleString(DateTime.DATETIME_MED)
|
|
||||||
: "UNKNOWN"
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
</v-tooltip>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { getStatus } from "@/services/statusService";
|
|
||||||
import { Status } from "@/types/status";
|
|
||||||
import { computed, ref, onBeforeUnmount } from "vue";
|
|
||||||
import { DateTime } from "luxon";
|
|
||||||
|
|
||||||
const status = ref<Status | undefined>(undefined);
|
|
||||||
|
|
||||||
function refreshStatus() {
|
|
||||||
getStatus().then((data) => {
|
|
||||||
status.value = data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const webdavProps = computed(() => {
|
|
||||||
if (status.value?.webdav.logged_in && status.value?.webdav.folder_created) {
|
|
||||||
return { icon: "mdi-check", text: "Ok", color: "green" };
|
|
||||||
} else {
|
|
||||||
return { icon: "mdi-alert", text: "Fail", color: "red" };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const webdavLoggedProps = computed(() => {
|
|
||||||
if (status.value?.webdav.logged_in) {
|
|
||||||
return { text: "Ok", color: "green" };
|
|
||||||
} else {
|
|
||||||
return { text: "Fail", color: "red" };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const webdavFolderProps = computed(() => {
|
|
||||||
if (status.value?.webdav.folder_created) {
|
|
||||||
return { text: "Ok", color: "green" };
|
|
||||||
} else {
|
|
||||||
return { text: "Fail", color: "red" };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const hassProps = computed(() => {
|
|
||||||
if (status.value?.hass.ok) {
|
|
||||||
return { icon: "mdi-check", text: "Ok", color: "green" };
|
|
||||||
} else {
|
|
||||||
return { icon: "mdi-alert", text: "Fail", color: "red" };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
refreshStatus();
|
|
||||||
const interval = setInterval(refreshStatus, 2000);
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
clearInterval(interval);
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,20 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<v-card elevation="10" border>
|
<v-card elevation="10" class="mt-10" border>
|
||||||
<v-row align="center" justify="center">
|
|
||||||
<v-col offset="2">
|
|
||||||
<v-card-title class="text-center"> Cloud </v-card-title>
|
<v-card-title class="text-center"> Cloud </v-card-title>
|
||||||
</v-col>
|
|
||||||
<v-col cols="2">
|
|
||||||
<v-btn
|
|
||||||
class="float-right mr-2"
|
|
||||||
icon="mdi-refresh"
|
|
||||||
variant="text"
|
|
||||||
@click="refreshBackup"
|
|
||||||
:loading="loading"
|
|
||||||
></v-btn>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row>
|
<v-row>
|
||||||
@ -94,22 +81,12 @@ const deleteDialog = ref<InstanceType<typeof CloudDeleteDialog> | null>(null);
|
|||||||
const deleteItem = ref<WebdavBackup | null>(null);
|
const deleteItem = ref<WebdavBackup | null>(null);
|
||||||
const autoBackups = ref<WebdavBackup[]>([]);
|
const autoBackups = ref<WebdavBackup[]>([]);
|
||||||
const manualBackups = ref<WebdavBackup[]>([]);
|
const manualBackups = ref<WebdavBackup[]>([]);
|
||||||
|
|
||||||
const loading = ref<boolean>(true);
|
|
||||||
|
|
||||||
function refreshBackup() {
|
function refreshBackup() {
|
||||||
loading.value = true;
|
getAutoBackupList().then((value) => {
|
||||||
getAutoBackupList()
|
|
||||||
.then((value) => {
|
|
||||||
autoBackups.value = value;
|
autoBackups.value = value;
|
||||||
return getManualBackupList();
|
});
|
||||||
})
|
getManualBackupList().then((value) => {
|
||||||
.then((value) => {
|
|
||||||
manualBackups.value = value;
|
manualBackups.value = value;
|
||||||
loading.value = false;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
loading.value = false;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,5 +95,10 @@ function deleteBackup(item: WebdavBackup) {
|
|||||||
deleteDialog.value?.open(item);
|
deleteDialog.value?.open(item);
|
||||||
}
|
}
|
||||||
refreshBackup();
|
refreshBackup();
|
||||||
defineExpose({ refreshBackup });
|
|
||||||
|
const interval = setInterval(refreshBackup, 2000);
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearInterval(interval);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,20 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<v-card elevation="10" border>
|
<v-card elevation="10" class="mt-10" border>
|
||||||
<v-row align="center" justify="center">
|
|
||||||
<v-col offset="2">
|
|
||||||
<v-card-title class="text-center"> Home Assistant </v-card-title>
|
<v-card-title class="text-center"> Home Assistant </v-card-title>
|
||||||
</v-col>
|
|
||||||
<v-col cols="2">
|
|
||||||
<v-btn
|
|
||||||
class="float-right mr-2"
|
|
||||||
icon="mdi-refresh"
|
|
||||||
variant="text"
|
|
||||||
@click="refreshBackup"
|
|
||||||
:loading="loading"
|
|
||||||
></v-btn>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row>
|
<v-row>
|
||||||
@ -56,19 +43,19 @@ import { getBackups } from "@/services/homeAssistantService";
|
|||||||
import HaListItem from "./HaListItem.vue";
|
import HaListItem from "./HaListItem.vue";
|
||||||
|
|
||||||
const backups = ref<BackupModel[]>([]);
|
const backups = ref<BackupModel[]>([]);
|
||||||
const loading = ref<boolean>(true);
|
|
||||||
|
|
||||||
function refreshBackup() {
|
function refreshBackup() {
|
||||||
loading.value = true;
|
|
||||||
getBackups().then((value) => {
|
getBackups().then((value) => {
|
||||||
backups.value = value;
|
backups.value = value;
|
||||||
loading.value = false;
|
});
|
||||||
}).catch(()=> {
|
|
||||||
loading.value = false;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshBackup();
|
refreshBackup();
|
||||||
|
const interval = setInterval(refreshBackup, 2000);
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearInterval(interval);
|
||||||
|
});
|
||||||
|
|
||||||
// TODO Manage delete
|
// TODO Manage delete
|
||||||
</script>
|
</script>
|
||||||
|
@ -53,10 +53,6 @@ let saveLoading = computed(() => {
|
|||||||
return saving.value || loading.value;
|
return saving.value || loading.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: "saved"): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
saving.value = true;
|
saving.value = true;
|
||||||
form.value?.save();
|
form.value?.save();
|
||||||
@ -64,16 +60,13 @@ function save() {
|
|||||||
|
|
||||||
function fail() {
|
function fail() {
|
||||||
saving.value = false;
|
saving.value = false;
|
||||||
alertStore.add(
|
alertStore.add("error", "Fail to save cloud settings !");
|
||||||
"error",
|
|
||||||
"Fail to connect to Cloud<br>Please check credentials !"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function saved() {
|
function saved() {
|
||||||
dialogStatusStore.webdav = false;
|
dialogStatusStore.webdav = false;
|
||||||
saving.value = false;
|
saving.value = false;
|
||||||
alertStore.add("success", "Cloud settings saved !");
|
alertStore.add("success", "Cloud settings saved !");
|
||||||
emit("saved");
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@/store/alert@/store/dialogStatus
|
@ -1,7 +0,0 @@
|
|||||||
import type { WebdavBackup } from "@/types/webdav";
|
|
||||||
import kyClient from "./kyClient";
|
|
||||||
import { Status } from "@/types/status";
|
|
||||||
|
|
||||||
export function getStatus() {
|
|
||||||
return kyClient.get("status").json<Status>();
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
import type { DateTime } from "luxon";
|
|
||||||
|
|
||||||
export enum States {
|
|
||||||
IDLE = "IDLE",
|
|
||||||
BKUP_CREATION = "BKUP_CREATION",
|
|
||||||
BKUP_DOWNLOAD_HA = "BKUP_DOWNLOAD_HA",
|
|
||||||
BKUP_DOWNLOAD_CLOUD = "BKUP_DOWNLOAD_CLOUD",
|
|
||||||
BKUP_UPLOAD_HA = "BKUP_UPLOAD_HA",
|
|
||||||
BKUP_UPLOAD_CLOUD = "BKUP_UPLOAD_CLOUD",
|
|
||||||
STOP_ADDON = "STOP_ADDON",
|
|
||||||
START_ADDON = "START_ADDON",
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Status {
|
|
||||||
status: States;
|
|
||||||
progress?: number;
|
|
||||||
last_backup: {
|
|
||||||
success?: boolean;
|
|
||||||
last_success?: string;
|
|
||||||
message?: string;
|
|
||||||
};
|
|
||||||
next_backup?: string;
|
|
||||||
webdav: {
|
|
||||||
logged_in: boolean;
|
|
||||||
folder_created: boolean;
|
|
||||||
last_check: string;
|
|
||||||
};
|
|
||||||
hass: {
|
|
||||||
ok: boolean;
|
|
||||||
last_check: string;
|
|
||||||
};
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user