Add CLI parameters command, to change parameters of shared files
This commit is contained in:
parent
0cb40d177c
commit
b66a997d1e
10 changed files with 202 additions and 6 deletions
|
@ -20,11 +20,11 @@ const HEADER_AUTH_NONCE: &'static str = "WWW-Authenticate";
|
|||
const PARAMS_DEFAULT_DOWNLOAD: u8 = 1;
|
||||
|
||||
/// The minimum allowed number of downloads, enforced by the server.
|
||||
const PARAMS_DOWNLOAD_MIN: u8 = 1;
|
||||
pub const PARAMS_DOWNLOAD_MIN: u8 = 1;
|
||||
|
||||
/// The maximum (inclusive) allowed number of downloads,
|
||||
/// enforced by the server.
|
||||
const PARAMS_DOWNLOAD_MAX: u8 = 20;
|
||||
pub const PARAMS_DOWNLOAD_MAX: u8 = 20;
|
||||
|
||||
/// An action to set parameters for a shared file.
|
||||
pub struct Params<'a> {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pub mod download;
|
||||
pub mod params;
|
||||
pub mod password;
|
||||
pub mod upload;
|
||||
|
|
53
cli/src/action/params.rs
Normal file
53
cli/src/action/params.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
use ffsend_api::action::params::{
|
||||
Params as ApiParams,
|
||||
ParamsData,
|
||||
};
|
||||
use ffsend_api::file::remote_file::RemoteFile;
|
||||
use ffsend_api::reqwest::Client;
|
||||
|
||||
use cmd::cmd_params::CmdParams;
|
||||
use error::ActionError;
|
||||
use util::print_success;
|
||||
|
||||
/// A file parameters action.
|
||||
pub struct Params<'a> {
|
||||
cmd: &'a CmdParams<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Params<'a> {
|
||||
/// Construct a new parameters action.
|
||||
pub fn new(cmd: &'a CmdParams<'a>) -> Self {
|
||||
Self {
|
||||
cmd,
|
||||
}
|
||||
}
|
||||
|
||||
/// Invoke the parameters action.
|
||||
// TODO: create a trait for this method
|
||||
pub fn invoke(&self) -> Result<(), ActionError> {
|
||||
// Get the share URL
|
||||
let url = self.cmd.url();
|
||||
|
||||
// Create a reqwest client
|
||||
let client = Client::new();
|
||||
|
||||
// Parse the remote file based on the share URL
|
||||
// TODO: handle error here
|
||||
let file = RemoteFile::parse_url(url, self.cmd.owner())?;
|
||||
|
||||
// TODO: show an informative error if the owner token isn't set
|
||||
|
||||
// Build the params data object
|
||||
let data = ParamsData::from(self.cmd.downloads());
|
||||
|
||||
// TODO: make sure the data isn't empty
|
||||
|
||||
// Execute an password action
|
||||
ApiParams::new(&file, data, None).invoke(&client)?;
|
||||
|
||||
// Print a success message
|
||||
print_success("Parameters set");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -16,8 +16,7 @@ impl<'a: 'b, 'b> CmdDownload<'a> {
|
|||
/// Build the sub command definition.
|
||||
pub fn build<'y, 'z>() -> App<'y, 'z> {
|
||||
// Build the subcommand
|
||||
#[allow(unused_mut)]
|
||||
let mut cmd = SubCommand::with_name("download")
|
||||
let cmd = SubCommand::with_name("download")
|
||||
.about("Download files.")
|
||||
.visible_alias("d")
|
||||
.visible_alias("down")
|
||||
|
|
118
cli/src/cmd/cmd_params.rs
Normal file
118
cli/src/cmd/cmd_params.rs
Normal file
|
@ -0,0 +1,118 @@
|
|||
use ffsend_api::action::params::{
|
||||
// TODO: test min/max
|
||||
PARAMS_DOWNLOAD_MIN as DOWNLOAD_MIN,
|
||||
PARAMS_DOWNLOAD_MAX as DOWNLOAD_MAX,
|
||||
};
|
||||
use ffsend_api::url::{ParseError, Url};
|
||||
|
||||
use super::clap::{App, Arg, ArgMatches, SubCommand};
|
||||
|
||||
use util::quit_error_msg;
|
||||
|
||||
/// The parameters command.
|
||||
pub struct CmdParams<'a> {
|
||||
matches: &'a ArgMatches<'a>,
|
||||
}
|
||||
|
||||
impl<'a: 'b, 'b> CmdParams<'a> {
|
||||
/// Build the sub command definition.
|
||||
pub fn build<'y, 'z>() -> App<'y, 'z> {
|
||||
// Build a list of data parameter arguments of which one is required
|
||||
let param_args = ["downloads"];
|
||||
|
||||
// Build the subcommand
|
||||
let cmd = SubCommand::with_name("parameters")
|
||||
.about("Change parameters of a shared file.")
|
||||
.visible_alias("params")
|
||||
.alias("par")
|
||||
.alias("param")
|
||||
.alias("parameter")
|
||||
.arg(Arg::with_name("URL")
|
||||
.help("The share URL")
|
||||
.required(true)
|
||||
.multiple(false))
|
||||
.arg(Arg::with_name("owner")
|
||||
.long("owner")
|
||||
.short("o")
|
||||
.alias("own")
|
||||
.alias("owner-token")
|
||||
.alias("token")
|
||||
.value_name("TOKEN")
|
||||
.help("File owner token"))
|
||||
.arg(Arg::with_name("downloads")
|
||||
.long("downloads")
|
||||
.short("d")
|
||||
.alias("download")
|
||||
.alias("down")
|
||||
.alias("dlimit")
|
||||
.required_unless_one(¶m_args)
|
||||
.value_name("COUNT")
|
||||
.help("Set the download limit parameter"));
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
/// Parse CLI arguments, from the given parent command matches.
|
||||
pub fn parse(parent: &'a ArgMatches<'a>) -> Option<CmdParams<'a>> {
|
||||
parent.subcommand_matches("parameters")
|
||||
.map(|matches| CmdParams { matches })
|
||||
}
|
||||
|
||||
/// Get the file share URL.
|
||||
///
|
||||
/// This method parses the URL into an `Url`.
|
||||
/// If the given URL is invalid,
|
||||
/// the program will quit with an error message.
|
||||
pub fn url(&'a self) -> Url {
|
||||
// Get the host
|
||||
let url = self.matches.value_of("URL")
|
||||
.expect("missing URL");
|
||||
|
||||
// Parse the URL
|
||||
// TODO: improve these error messages
|
||||
match Url::parse(url) {
|
||||
Ok(url) => url,
|
||||
Err(ParseError::EmptyHost) =>
|
||||
quit_error_msg("Emtpy host given"),
|
||||
Err(ParseError::InvalidPort) =>
|
||||
quit_error_msg("Invalid host port"),
|
||||
Err(ParseError::InvalidIpv4Address) =>
|
||||
quit_error_msg("Invalid IPv4 address in host"),
|
||||
Err(ParseError::InvalidIpv6Address) =>
|
||||
quit_error_msg("Invalid IPv6 address in host"),
|
||||
Err(ParseError::InvalidDomainCharacter) =>
|
||||
quit_error_msg("Host domains contains an invalid character"),
|
||||
Err(ParseError::RelativeUrlWithoutBase) =>
|
||||
quit_error_msg("Host domain doesn't contain a host"),
|
||||
_ => quit_error_msg("The given host is invalid"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the owner token.
|
||||
pub fn owner(&'a self) -> Option<String> {
|
||||
// TODO: validate the owner token if set
|
||||
self.matches.value_of("owner")
|
||||
.map(|token| token.to_owned())
|
||||
}
|
||||
|
||||
/// Get the download counts.
|
||||
pub fn downloads(&'a self) -> Option<u8> {
|
||||
// Get the number of downloads
|
||||
// TODO: do not unwrap, report an error
|
||||
self.matches.value_of("downloads")
|
||||
.map(|d| d.parse::<u8>().expect("invalid number of downloads"))
|
||||
.and_then(|d| {
|
||||
// Check the download count bounds
|
||||
if d < DOWNLOAD_MIN || d > DOWNLOAD_MAX {
|
||||
panic!(
|
||||
"invalid number of downloads, must be between {} and {}",
|
||||
DOWNLOAD_MIN,
|
||||
DOWNLOAD_MAX,
|
||||
);
|
||||
}
|
||||
|
||||
// Return the value
|
||||
Some(d)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -14,8 +14,7 @@ impl<'a: 'b, 'b> CmdPassword<'a> {
|
|||
/// Build the sub command definition.
|
||||
pub fn build<'y, 'z>() -> App<'y, 'z> {
|
||||
// Build the subcommand
|
||||
#[allow(unused_mut)]
|
||||
let mut cmd = SubCommand::with_name("password")
|
||||
let cmd = SubCommand::with_name("password")
|
||||
.about("Change the password of a shared file.")
|
||||
.visible_alias("p")
|
||||
.visible_alias("pass")
|
||||
|
|
|
@ -3,6 +3,7 @@ use super::clap::{App, ArgMatches};
|
|||
use app::*;
|
||||
|
||||
use super::cmd_download::CmdDownload;
|
||||
use super::cmd_params::CmdParams;
|
||||
use super::cmd_password::CmdPassword;
|
||||
use super::cmd_upload::CmdUpload;
|
||||
|
||||
|
@ -21,6 +22,7 @@ impl<'a: 'b, 'b> Handler<'a> {
|
|||
.about(APP_ABOUT)
|
||||
.subcommand(CmdUpload::build().display_order(1))
|
||||
.subcommand(CmdDownload::build().display_order(2))
|
||||
.subcommand(CmdParams::build())
|
||||
.subcommand(CmdPassword::build())
|
||||
}
|
||||
|
||||
|
@ -42,6 +44,11 @@ impl<'a: 'b, 'b> Handler<'a> {
|
|||
CmdDownload::parse(&self.matches)
|
||||
}
|
||||
|
||||
/// Get the parameters sub command, if matched.
|
||||
pub fn params(&'a self) -> Option<CmdParams<'a>> {
|
||||
CmdParams::parse(&self.matches)
|
||||
}
|
||||
|
||||
/// Get the password sub command, if matched.
|
||||
pub fn password(&'a self) -> Option<CmdPassword<'a>> {
|
||||
CmdPassword::parse(&self.matches)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
extern crate clap;
|
||||
|
||||
pub mod cmd_download;
|
||||
pub mod cmd_params;
|
||||
pub mod cmd_password;
|
||||
pub mod cmd_upload;
|
||||
pub mod handler;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use ffsend_api::action::download::Error as DownloadError;
|
||||
use ffsend_api::action::params::Error as ParamsError;
|
||||
use ffsend_api::action::password::Error as PasswordError;
|
||||
use ffsend_api::action::upload::Error as UploadError;
|
||||
use ffsend_api::file::remote_file::FileParseError;
|
||||
|
@ -27,6 +28,10 @@ pub enum ActionError {
|
|||
#[fail(display = "Failed to download the requested file")]
|
||||
Download(#[cause] DownloadError),
|
||||
|
||||
/// An error occurred while invoking the params action.
|
||||
#[fail(display = "Failed to change the parameters")]
|
||||
Params(#[cause] ParamsError),
|
||||
|
||||
/// An error occurred while invoking the password action.
|
||||
#[fail(display = "Failed to change the password")]
|
||||
Password(#[cause] PasswordError),
|
||||
|
@ -43,6 +48,12 @@ impl From<DownloadError> for ActionError {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ParamsError> for ActionError {
|
||||
fn from(err: ParamsError) -> ActionError {
|
||||
ActionError::Params(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PasswordError> for ActionError {
|
||||
fn from(err: PasswordError) -> ActionError {
|
||||
ActionError::Password(err)
|
||||
|
|
|
@ -12,6 +12,7 @@ mod progress;
|
|||
mod util;
|
||||
|
||||
use action::download::Download;
|
||||
use action::params::Params;
|
||||
use action::password::Password;
|
||||
use action::upload::Upload;
|
||||
use cmd::Handler;
|
||||
|
@ -46,6 +47,12 @@ fn invoke_action(handler: &Handler) -> Result<(), Error> {
|
|||
.map_err(|err| err.into());
|
||||
}
|
||||
|
||||
// Match the parameters command
|
||||
if let Some(cmd) = handler.params() {
|
||||
return Params::new(&cmd).invoke()
|
||||
.map_err(|err| err.into());
|
||||
}
|
||||
|
||||
// Match the password command
|
||||
if let Some(cmd) = handler.password() {
|
||||
return Password::new(&cmd).invoke()
|
||||
|
|
Loading…
Reference in a new issue