diff --git a/src/frontend/rest/services/mod.rs b/src/frontend/rest/services/mod.rs index 7f493aa..76d0407 100644 --- a/src/frontend/rest/services/mod.rs +++ b/src/frontend/rest/services/mod.rs @@ -31,6 +31,7 @@ mod packages; mod static_files; mod uninstall; mod update_updater; +mod verify_path; /// Expected incoming Request format from Hyper. pub type Request = hyper::server::Request; @@ -140,6 +141,7 @@ impl Service for WebService { (Method::Post, "/api/start-install") => install::handle(self, req), (Method::Post, "/api/uninstall") => uninstall::handle(self, req), (Method::Post, "/api/update-updater") => update_updater::handle(self, req), + (Method::Post, "/api/verify-path") => verify_path::handle(self, req), (Method::Get, _) => static_files::handle(self, req), e => { info!("Returned 404 for {:?}", e); diff --git a/src/frontend/rest/services/verify_path.rs b/src/frontend/rest/services/verify_path.rs new file mode 100644 index 0000000..f8ca0c3 --- /dev/null +++ b/src/frontend/rest/services/verify_path.rs @@ -0,0 +1,49 @@ +//! frontend/rest/services/verify_path.rs +//! +//! The /api/verify-path returns whether the path exists or not. + +use crate::frontend::rest::services::Future; +use crate::frontend::rest::services::Request; +use crate::frontend::rest::services::Response; +use crate::frontend::rest::services::WebService; +use url::form_urlencoded; + +use hyper::header::{ContentLength, ContentType}; + +use futures::future::Future as _; +use futures::stream::Stream; + +use crate::logging::LoggingErrors; + +use std::collections::HashMap; +use std::path::PathBuf; + + +/// Struct used by serde to send a JSON payload to the client containing an optional value. +#[derive(Serialize)] +struct VerifyResponse { + exists: bool, +} + +pub fn handle(_service: &WebService, req: Request) -> Future { + Box::new(req.body().concat2().map(move |b| { + let results = form_urlencoded::parse(b.as_ref()) + .into_owned() + .collect::>(); + let mut exists = false; + if let Some(path) = results.get("path") { + let path = PathBuf::from(path); + exists = path.is_dir(); + } + + let response = VerifyResponse { exists }; + + let file = serde_json::to_string(&response) + .log_expect("Failed to render JSON payload of default path object"); + + Response::new() + .with_header(ContentLength(file.len() as u64)) + .with_header(ContentType::json()) + .with_body(file) + })) +} diff --git a/src/tasks/remove_target_dir.rs b/src/tasks/remove_target_dir.rs index af27241..b492cdc 100644 --- a/src/tasks/remove_target_dir.rs +++ b/src/tasks/remove_target_dir.rs @@ -25,7 +25,13 @@ impl Task for RemoveTargetDirTask { if let Some(path) = context.install_path.as_ref() { let entries = std::fs::read_dir(path) .map_err(|e| format!("Error reading {}: {}", path.to_string_lossy(), e))?; - // remove everything except the maintenancetool + // remove everything under the path + if !context.preexisting_install { + std::fs::remove_dir_all(path) + .map_err(|e| format!("Error removing {}: {}", path.to_string_lossy(), e))?; + return Ok(TaskParamType::None); + } + // remove everything except the maintenancetool if repairing for entry in entries { let path = entry .map_err(|e| format!("Error reading file: {}", e))? diff --git a/ui/src/locales/en.json b/ui/src/locales/en.json index 91c6748..007655e 100644 --- a/ui/src/locales/en.json +++ b/ui/src/locales/en.json @@ -48,7 +48,9 @@ "modify":"Modify", "repair": "Repair", "uninstall":"Uninstall", - "prompt":"Are you sure you want to uninstall {name}?" + "view_local_files": "View local files", + "prompt":"Are you sure you want to uninstall {name}?", + "prompt_confirm":"Uninstall {name}" }, "back":"Back", "exit":"Exit", diff --git a/ui/src/views/ModifyView.vue b/ui/src/views/ModifyView.vue index bde1c5f..d5f79a3 100644 --- a/ui/src/views/ModifyView.vue +++ b/ui/src/views/ModifyView.vue @@ -20,22 +20,15 @@

- + {{ $t('modify.uninstall') }} - + +
+
- + + {{ $t('modify.view_local_files') }} + @@ -43,9 +36,7 @@ export default { name: 'ModifyView', data: function () { - return { - show_uninstall: false - } + return {} }, methods: { update: function () { @@ -58,10 +49,14 @@ export default { this.$router.push({ name: 'packages', params: { repair: true } }) }, prepare_uninstall: function () { - this.show_uninstall = true - }, - cancel_uninstall: function () { - this.show_uninstall = false + this.$buefy.dialog.confirm({ + title: this.$t('modify.uninstall'), + message: this.$t('modify.prompt', {'name': this.$root.$data.attrs.name}), + confirmText: this.$t('modify.prompt_confirm', {'name': this.$root.$data.attrs.name}), + type: 'is-danger', + hasIcon: true, + onConfirm: this.uninstall + }) }, uninstall: function () { this.$router.push('/install/uninstall') diff --git a/ui/src/views/SelectPackages.vue b/ui/src/views/SelectPackages.vue index d9a3bd2..da36540 100644 --- a/ui/src/views/SelectPackages.vue +++ b/ui/src/views/SelectPackages.vue @@ -81,8 +81,30 @@ export default { } })) }, + show_overwrite_dialog: function (confirmCallback) { + this.$buefy.dialog.confirm({ + title: 'Overwriting', + message: `Directory ${this.$root.$data.install_location} already exists.
+ Are you sure you want to overwrite the contents inside?`, + confirmText: 'Continue', + type: 'is-danger', + hasIcon: true, + onConfirm: confirmCallback + }) + }, install: function () { - this.$router.push(this.repair ? '/install/repair' : '/install/regular') + this.repair && this.$router.push('/install/repair') + var my = this + this.$http.post('/api/verify-path', `path=${this.$root.$data.install_location}`).then(function (resp) { + var data = resp.data || {} + if (!data.exists) { + my.$router.push('/install/regular') + } else { + my.show_overwrite_dialog(function () { + my.$router.push('/install/repair') + }) + } + }) }, go_back: function () { this.$router.go(-1)