mirror of
https://github.com/Sebclem/hassio-nextcloud-backup.git
synced 2024-11-10 11:32:58 +01:00
Compare commits
7 Commits
8287bdeedc
...
ace8fe7caa
Author | SHA1 | Date | |
---|---|---|---|
ace8fe7caa | |||
9a62814c38 | |||
6f20b97488 | |||
7abd6bab8b | |||
2b639a0df5 | |||
f6db3499a4 | |||
bd444ad8d6 |
4
nextcloud_backup/backend/.vscode/launch.json
vendored
4
nextcloud_backup/backend/.vscode/launch.json
vendored
@ -12,9 +12,7 @@
|
||||
"request": "launch",
|
||||
"restart": true,
|
||||
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/nodemon",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"type": "node",
|
||||
"preLaunchTask": "npm: build:watch"
|
||||
}
|
||||
|
24
nextcloud_backup/backend/.vscode/tasks.json
vendored
24
nextcloud_backup/backend/.vscode/tasks.json
vendored
@ -1,14 +1,14 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build:watch",
|
||||
"group": "build",
|
||||
"label": "npm: build:watch",
|
||||
"detail": "tsc -w",
|
||||
"isBackground": true,
|
||||
"problemMatcher": "$tsc-watch"
|
||||
}
|
||||
]
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build:watch",
|
||||
"group": "build",
|
||||
"label": "npm: build:watch",
|
||||
"detail": "tsc -w",
|
||||
"isBackground": true,
|
||||
"problemMatcher": "$tsc-watch"
|
||||
}
|
||||
]
|
||||
}
|
@ -21,9 +21,9 @@ app.use(
|
||||
|
||||
app.set("port", process.env.PORT || 3000);
|
||||
|
||||
app.use(
|
||||
morgan("dev", { stream: { write: (message) => logger.debug(message) } })
|
||||
);
|
||||
// app.use(
|
||||
// morgan("dev", { stream: { write: (message) => logger.debug(message) } })
|
||||
// );
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(cookieParser());
|
||||
@ -35,13 +35,14 @@ app.use("/v2/api/", apiV2Router);
|
||||
Error handler
|
||||
----------------------------------------------------------
|
||||
*/
|
||||
// catch 404 and forward to error handler
|
||||
app.use((req, res, next) => {
|
||||
next(createError(404));
|
||||
});
|
||||
|
||||
// error handler
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
if (app.get("env") == "development") {
|
||||
// catch 404 and forward to error handler
|
||||
app.use((req, res, next) => {
|
||||
next(createError(404));
|
||||
});
|
||||
|
||||
// only use in development
|
||||
app.use(errorHandler());
|
||||
}
|
||||
|
@ -1,279 +0,0 @@
|
||||
// import express from "express";
|
||||
// import * as statusTools from "../tools/status.js";
|
||||
// import webdav from "../services/webdavService.js";
|
||||
// import * as settingsTools from "../tools/settingsTools.js";
|
||||
// import * as pathTools from "../tools/pathTools.js";
|
||||
// import * as hassioApiTools from "../tools/hassioApiTools.js";
|
||||
// import { humanFileSize } from "../tools/toolbox.js";
|
||||
// import cronTools from "../tools/cronTools.js";
|
||||
// import logger from "../config/winston.js";
|
||||
// import { DateTime } from "luxon";
|
||||
|
||||
// const router = express.Router();
|
||||
|
||||
// router.get("/status", (req, res, next) => {
|
||||
// cronTools.updateNextDate();
|
||||
// const status = statusTools.getStatus();
|
||||
// res.json(status);
|
||||
// });
|
||||
|
||||
// router.get("/formated-local-snap", function (req, res, next) {
|
||||
// hassioApiTools
|
||||
// .getSnapshots()
|
||||
// .then((snaps) => {
|
||||
// snaps.sort((a, b) => {
|
||||
// return a.date < b.date ? 1 : -1;
|
||||
// });
|
||||
|
||||
// res.render("localSnaps", { snaps: snaps, DateTime: DateTime });
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// logger.error(err);
|
||||
// res.status(500);
|
||||
// res.send("");
|
||||
// });
|
||||
// });
|
||||
|
||||
// router.get("/formated-backup-manual", function (req, res, next) {
|
||||
// if (webdav.getConf() == null) {
|
||||
// res.send("");
|
||||
// return;
|
||||
// }
|
||||
// webdav
|
||||
// .getFolderContent(webdav.getConf()?.back_dir + pathTools.manual)
|
||||
// .then((contents: any) => {
|
||||
// contents.sort((a: any, b: any) => {
|
||||
// return a.date < b.date ? 1 : -1;
|
||||
// });
|
||||
// //TODO Remove this when bug is fixed, etag contain '"' at start and end ?
|
||||
// for (const backup of contents) {
|
||||
// backup.etag = backup.etag.replace(/"/g, "");
|
||||
// }
|
||||
// res.render("backupSnaps", {
|
||||
// backups: contents,
|
||||
// DateTime: DateTime,
|
||||
// humanFileSize: humanFileSize,
|
||||
// });
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// res.status(500);
|
||||
// res.send(err);
|
||||
// });
|
||||
// });
|
||||
|
||||
// router.get("/formated-backup-auto", function (req, res, next) {
|
||||
// if (webdav.getConf() == null) {
|
||||
// res.send("");
|
||||
// return;
|
||||
// }
|
||||
// const url = webdav.getConf()?.back_dir + pathTools.auto;
|
||||
// webdav
|
||||
// .getFolderContent(url)
|
||||
// .then((contents: any) => {
|
||||
// contents.sort((a: any, b: any) => {
|
||||
// return a.date < b.date ? 1 : -1;
|
||||
// });
|
||||
// //TODO Remove this when bug is fixed, etag contain '"' at start and end ?
|
||||
// for (const backup of contents) {
|
||||
// backup.etag = backup.etag.replace(/"/g, "");
|
||||
// }
|
||||
// res.render("backupSnaps", {
|
||||
// backups: contents,
|
||||
// DateTime: DateTime,
|
||||
// humanFileSize: humanFileSize,
|
||||
// });
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// res.status(500);
|
||||
// res.send(err);
|
||||
// });
|
||||
// });
|
||||
|
||||
// router.post("/nextcloud-settings", function (req, res, next) {
|
||||
// const 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);
|
||||
// res.send();
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// res.status(406);
|
||||
// res.json({ message: err });
|
||||
// });
|
||||
// } else {
|
||||
// res.status(400);
|
||||
// res.send();
|
||||
// }
|
||||
// });
|
||||
|
||||
// router.get("/nextcloud-settings", function (req, res, next) {
|
||||
// const conf = webdav.getConf();
|
||||
// if (conf == null) {
|
||||
// res.status(404);
|
||||
// res.send();
|
||||
// } else {
|
||||
// res.json(conf);
|
||||
// }
|
||||
// });
|
||||
|
||||
// router.post("/manual-backup", function (req, res, next) {
|
||||
// const id = req.query.id;
|
||||
// const name = req.query.name;
|
||||
// const status = statusTools.getStatus();
|
||||
// if (
|
||||
// status.status == "creating" ||
|
||||
// status.status == "upload" ||
|
||||
// status.status == "download"
|
||||
// ) {
|
||||
// res.status(503);
|
||||
// res.send();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// hassioApiTools
|
||||
// .downloadSnapshot(id as string)
|
||||
// .then(() => {
|
||||
// webdav
|
||||
// .uploadFile(
|
||||
// id as string,
|
||||
// webdav.getConf()?.back_dir + pathTools.manual + name + ".tar"
|
||||
// )
|
||||
// .then(() => {
|
||||
// res.status(201);
|
||||
// res.send();
|
||||
// })
|
||||
// .catch(() => {
|
||||
// res.status(500);
|
||||
// res.send();
|
||||
// });
|
||||
// })
|
||||
// .catch(() => {
|
||||
// res.status(500);
|
||||
// res.send();
|
||||
// });
|
||||
// });
|
||||
|
||||
// router.post("/new-backup", function (req, res, next) {
|
||||
// const status = statusTools.getStatus();
|
||||
// if (
|
||||
// status.status == "creating" ||
|
||||
// status.status == "upload" ||
|
||||
// status.status == "download" ||
|
||||
// status.status == "stopping" ||
|
||||
// status.status == "starting"
|
||||
// ) {
|
||||
// res.status(503);
|
||||
// res.send();
|
||||
// return;
|
||||
// }
|
||||
// hassioApiTools
|
||||
// .stopAddons()
|
||||
// .then(() => {
|
||||
// hassioApiTools
|
||||
// .getVersion()
|
||||
// .then((version) => {
|
||||
// const 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"
|
||||
// )
|
||||
// .then(() => {
|
||||
// hassioApiTools.startAddons().catch(() => {
|
||||
// // Skip
|
||||
// });
|
||||
// })
|
||||
// .catch(() => {
|
||||
// // Skip
|
||||
// });
|
||||
// })
|
||||
// .catch(() => {
|
||||
// // Skip
|
||||
// });
|
||||
// })
|
||||
// .catch(() => {
|
||||
// // Skip
|
||||
// });
|
||||
// })
|
||||
// .catch(() => {
|
||||
// // Skip
|
||||
// });
|
||||
// })
|
||||
// .catch(() => {
|
||||
// hassioApiTools.startAddons().catch(() => {
|
||||
// // Skip
|
||||
// });
|
||||
// });
|
||||
|
||||
// res.status(201);
|
||||
// res.send();
|
||||
// });
|
||||
|
||||
// router.get("/backup-settings", function (req, res, next) {
|
||||
// hassioApiTools.getAddonList().then((addonList) => {
|
||||
// const data = {
|
||||
// folder: hassioApiTools.getFolderList(),
|
||||
// addonList: addonList,
|
||||
// settings: settingsTools.getSettings()
|
||||
// };
|
||||
// res.send(data);
|
||||
// });
|
||||
// });
|
||||
|
||||
// router.post("/backup-settings", function (req, res, next) {
|
||||
// const [result, message] = settingsTools.check(req.body);
|
||||
// if (result) {
|
||||
// settingsTools.setSettings(req.body);
|
||||
// cronTools.init();
|
||||
// res.send();
|
||||
// } else {
|
||||
// res.status(400);
|
||||
// res.send(message);
|
||||
// }
|
||||
// });
|
||||
|
||||
// router.post("/clean-now", function (req, res, next) {
|
||||
// webdav
|
||||
// .clean()
|
||||
// .then(() => {
|
||||
// hassioApiTools.clean().catch();
|
||||
// })
|
||||
// .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).catch();
|
||||
// });
|
||||
// res.status(200);
|
||||
// res.send();
|
||||
// } else {
|
||||
// res.status(400);
|
||||
// res.send();
|
||||
// }
|
||||
// });
|
||||
|
||||
// export default router;
|
@ -73,17 +73,20 @@ export function doBackupWorkflow(type: WorkflowType) {
|
||||
if (webdavConfig.chunckedUpload) {
|
||||
return webDavService.chunkedUpload(
|
||||
tmpFile,
|
||||
getBackupFolder(type, webdavConfig) + name,
|
||||
getBackupFolder(type, webdavConfig) + name + ".tar",
|
||||
webdavConfig
|
||||
);
|
||||
} else {
|
||||
return webDavService.webdavUploadFile(
|
||||
tmpFile,
|
||||
getBackupFolder(type, webdavConfig) + name,
|
||||
getBackupFolder(type, webdavConfig) + name + ".tar",
|
||||
webdavConfig
|
||||
);
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
return homeAssistantService.startAddons(addonsToStartStop);
|
||||
})
|
||||
.then(() => {
|
||||
logger.info("Backup workflow finished successfully !");
|
||||
messageManager.info("Backup workflow finished successfully !");
|
||||
@ -104,8 +107,7 @@ export function doBackupWorkflow(type: WorkflowType) {
|
||||
|
||||
// This methods remove addon that are no installed in HA from the conf array
|
||||
function sanitizeAddonList(addonInConf: string[], addonInHA: AddonModel[]) {
|
||||
addonInConf.filter((value) => addonInHA.some((v) => v.slug == value));
|
||||
return addonInConf;
|
||||
return addonInConf.filter((value) => addonInHA.some((v) => v.slug == value));
|
||||
}
|
||||
|
||||
function getAddonToBackup(excludedAddon: string[], addonInHA: AddonModel[]) {
|
||||
|
@ -414,6 +414,12 @@ export async function chunkedUpload(
|
||||
logger.debug("Chunked upload funished, assembling chunks.");
|
||||
try {
|
||||
await assembleChunkedUpload(chunkedUrl, finalDestination, fileSize, config);
|
||||
const status = statusTools.getStatus();
|
||||
status.status = States.IDLE;
|
||||
status.progress = undefined;
|
||||
statusTools.setStatus(status);
|
||||
logger.info(`...Upload finish !`);
|
||||
fs.unlinkSync(localPath);
|
||||
} catch (err) {
|
||||
if (err instanceof RequestError) {
|
||||
messageManager.error(
|
||||
@ -482,7 +488,7 @@ export function initChunkedUpload(
|
||||
finalDestination: string,
|
||||
config: WebdavConfig
|
||||
) {
|
||||
logger.debug(`Init chuncked upload.`);
|
||||
logger.info(`Init chuncked upload.`);
|
||||
logger.debug(`...URI: ${encodeURI(url)}`);
|
||||
logger.debug(`...Final destination: ${encodeURI(finalDestination)}`);
|
||||
return got(encodeURI(url), {
|
||||
@ -504,7 +510,7 @@ export function assembleChunkedUpload(
|
||||
config: WebdavConfig
|
||||
) {
|
||||
const chunckFile = `${url}/.file`;
|
||||
logger.debug(`Assemble chuncked upload.`);
|
||||
logger.info(`Assemble chuncked upload.`);
|
||||
logger.debug(`...URI: ${encodeURI(chunckFile)}`);
|
||||
logger.debug(`...Final destination: ${encodeURI(finalDestination)}`);
|
||||
return got(encodeURI(chunckFile), {
|
||||
|
@ -32,26 +32,49 @@
|
||||
</v-select>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-if="data.webdavEndpoint.type == WebdavEndpointType.CUSTOM">
|
||||
<v-col>
|
||||
<div class="text-subtitle-1 text-medium-emphasis">Custom Endpoint</div>
|
||||
<v-text-field
|
||||
placeholder="/remote.php/dav/files/$username"
|
||||
hint="You can use the $username variable"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
hide-details="auto"
|
||||
v-model="data.webdavEndpoint.customEndpoint"
|
||||
:error-messages="errors.customEndpoint"
|
||||
:loading="loading"
|
||||
color="orange"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<div v-if="data.webdavEndpoint.type == WebdavEndpointType.CUSTOM">
|
||||
<v-row>
|
||||
<v-col>
|
||||
<div class="text-subtitle-1 text-medium-emphasis">
|
||||
Custom endpoint
|
||||
</div>
|
||||
<v-text-field
|
||||
placeholder="/remote.php/dav/files/$username"
|
||||
hint="You can use the $username variable"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
hide-details="auto"
|
||||
v-model="data.webdavEndpoint.customEndpoint"
|
||||
:error-messages="errors.customEndpoint"
|
||||
:loading="loading"
|
||||
color="orange"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<div class="text-subtitle-1 text-medium-emphasis">
|
||||
Custom chunk endpoint
|
||||
</div>
|
||||
<v-text-field
|
||||
placeholder="/remote.php/dav/uploads/$username"
|
||||
hint="You can use the $username variable"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
hide-details="auto"
|
||||
v-model="data.webdavEndpoint.customChunkEndpoint"
|
||||
:error-messages="errors.customChunkEndpoint"
|
||||
:loading="loading"
|
||||
color="orange"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
||||
<v-row class="mt-0">
|
||||
<v-col class="d-flex align-content-end">
|
||||
<v-switch
|
||||
label="Allow Self Signed Certificate"
|
||||
label="Allow self signed certificate"
|
||||
v-model="data.allowSelfSignedCerts"
|
||||
hide-details="auto"
|
||||
density="compact"
|
||||
@ -65,7 +88,7 @@
|
||||
<v-row class="mt-0">
|
||||
<v-col class="d-flex align-content-end">
|
||||
<v-switch
|
||||
label="Chunked Upload (Beta)"
|
||||
label="Chunked upload (Beta)"
|
||||
v-model="data.chunckedUpload"
|
||||
hide-details="auto"
|
||||
density="compact"
|
||||
@ -171,6 +194,7 @@ const errors = ref({
|
||||
allowSelfSignedCerts: [],
|
||||
type: [],
|
||||
customEndpoint: [],
|
||||
customChunkEndpoint: [],
|
||||
chunckedUpload: [],
|
||||
});
|
||||
|
||||
|
@ -13,5 +13,6 @@ export interface WebdavConfig {
|
||||
webdavEndpoint: {
|
||||
type: WebdavEndpointType;
|
||||
customEndpoint?: string;
|
||||
customChunkEndpoint?: string;
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user