diff --git a/src/commands/push.rs b/src/commands/push.rs index cee0e40..5abc792 100644 --- a/src/commands/push.rs +++ b/src/commands/push.rs @@ -12,6 +12,7 @@ pub mod rm_dir; pub mod deleted; pub mod modified; pub mod moved; +pub mod copied; pub fn push() { // todo err when pushing new folder diff --git a/src/commands/push/copied.rs b/src/commands/push/copied.rs new file mode 100644 index 0000000..36cdd19 --- /dev/null +++ b/src/commands/push/copied.rs @@ -0,0 +1,83 @@ +use std::path::PathBuf; +use std::io; +use crate::services::api::ApiError; +use crate::services::r#copy::Copy; +use crate::services::req_props::ReqProps; +use crate::commands::status::LocalObj; +use crate::commands::push::push_factory::{PushState, PushChange, PushFlowState}; +use crate::store::object::blob::Blob; +use crate::utils::path::path_buf_to_string; + +pub struct Copied { + pub obj: LocalObj, +} + +impl PushChange for Copied { + fn can_push(&self, whitelist: &mut Option) -> PushState { + match self.flow(&self.obj, whitelist.clone()) { + PushFlowState::Whitelisted => PushState::Done, + PushFlowState::NotOnRemote => PushState::Valid, + PushFlowState::RemoteIsNewer => PushState::Conflict, + PushFlowState::LocalIsNewer => PushState::Conflict, + PushFlowState::Error => PushState::Error, + } + } + + fn push(&self) -> io::Result<()> { + let obj = &self.obj; + let res = Copy::new() + .set_url( + &path_buf_to_string(obj.path_from.clone().unwrap()), + obj.path.to_str().unwrap()) + .send_with_err(); + + match res { + Err(ApiError::IncorrectRequest(err)) => { + eprintln!("fatal: error copying file {}: {}", obj.name, err.status()); + std::process::exit(1); + }, + Err(ApiError::RequestError(_)) => { + eprintln!("fatal: request error copying file {}", obj.name); + std::process::exit(1); + } + _ => (), + } + + // get lastmodified props to update it + let props = ReqProps::new() + .set_url(obj.path.to_str().unwrap()) + .getlastmodified() + .send_req_single(); + + let prop = match props { + Ok(o) => o, + Err(ApiError::IncorrectRequest(err)) => { + eprintln!("fatal: {}", err.status()); + std::process::exit(1); + }, + Err(ApiError::EmptyError(_)) => { + eprintln!("Failed to get body"); + std::process::exit(1); + } + Err(ApiError::RequestError(err)) => { + eprintln!("fatal: {}", err); + std::process::exit(1); + }, + Err(ApiError::Unexpected(_)) => todo!() + }; + + let lastmodified = prop.lastmodified.unwrap().timestamp_millis(); + + // create destination blob + if let Err(err) = Blob::new(obj.path.clone()).create(&lastmodified.to_string(), false) { + eprintln!("err: creating ref of {}: {}", obj.name.clone(), err); + } + + Ok(()) + } + + // download file with .distant at the end + fn conflict(&self) { + todo!() + } +} diff --git a/src/commands/push/push_factory.rs b/src/commands/push/push_factory.rs index 28dd7f1..3c0bd2a 100644 --- a/src/commands/push/push_factory.rs +++ b/src/commands/push/push_factory.rs @@ -9,6 +9,7 @@ use crate::commands::push::rm_dir::RmDir; use crate::commands::push::deleted::Deleted; use crate::commands::push::modified::Modified; use crate::commands::push::moved::Moved; +use crate::commands::push::copied::Copied; use crate::store::object::blob::Blob; #[derive(Debug)] @@ -93,6 +94,7 @@ impl PushFactory { State::Modified => Box::new(Modified { obj }), State::Deleted => Box::new(Deleted { obj }), State::Moved => Box::new(Moved { obj }), + State::Copied => Box::new(Copied { obj }), State::Default => todo!(), _ => todo!(), } diff --git a/src/services.rs b/src/services.rs index 9c85e86..e1fbd30 100644 --- a/src/services.rs +++ b/src/services.rs @@ -5,3 +5,6 @@ pub mod req_props; pub mod upload_file; pub mod delete_path; pub mod downloader; +pub mod r#move; +pub mod r#copy; +//pub mod bulk_upload; diff --git a/src/services/copy.rs b/src/services/copy.rs new file mode 100644 index 0000000..1acfe0e --- /dev/null +++ b/src/services/copy.rs @@ -0,0 +1,61 @@ +use reqwest::{Method, Response, Error, header::HeaderValue}; +use crate::services::api::{ApiBuilder, ApiError}; +use crate::clone::get_url_props; +use crate::commands::config; + +pub struct Copy { + api_builder: ApiBuilder, +} + +impl Copy { + pub fn new() -> Self { + Copy { + api_builder: ApiBuilder::new(), + } + } + + pub fn set_url(&mut self, url: &str, destination: &str) -> &mut Copy { + self.api_builder.build_request(Method::from_bytes(b"COPY").unwrap(), url); + + let remote = match config::get("remote") { + Some(r) => r, + None => { + eprintln!("fatal: unable to find a remote"); + std::process::exit(1); + } + }; + let (host, username, root) = get_url_props(&remote); + let mut url = String::from(host); + url.push_str("/remote.php/dav/files/"); + url.push_str(username.unwrap()); + url.push_str(&root); + url.push_str("/"); + if destination != "/" { + url.push_str(destination); + } + self.api_builder.set_header("Destination", HeaderValue::from_str(&url).unwrap()); + self + } + + pub async fn send(&mut self) -> Result { + self.api_builder.send().await + } + + pub fn overwrite(&mut self, overwrite: bool) -> &mut Copy { + self.api_builder.set_header("Overwrite", HeaderValue::from_str({ + if overwrite { "T" } else { "F" } + }).unwrap()); + self + } + + pub fn send_with_err(&mut self) -> Result<(), ApiError> { + let res = tokio::runtime::Runtime::new().unwrap().block_on(async { + self.send().await + }).map_err(ApiError::RequestError)?; + if res.status().is_success() { + Ok(()) + } else { + Err(ApiError::IncorrectRequest(res)) + } + } +}