Add exists API action to check file ability and protection

This commit is contained in:
timvisee 2018-04-02 18:52:08 +02:00
parent 887e09ebd2
commit 349e62ed1c
No known key found for this signature in database
GPG key ID: 109CBA0BF74036C2
3 changed files with 130 additions and 0 deletions

119
api/src/action/exists.rs Normal file
View file

@ -0,0 +1,119 @@
// TODO: define redirect policy
use reqwest::{Client, StatusCode};
use ext::status_code::StatusCodeExt;
use file::remote_file::RemoteFile;
/// The HTTP status code that is returned for expired files.
const FILE_EXPIRED_STATUS: StatusCode = StatusCode::NotFound;
/// An action to check whether a remote file exists.
/// This aciton returns an `ExistsResponse`, that defines whether the file
/// exists, and whether it is protected by a password.
pub struct Exists<'a> {
/// The remote file to check.
file: &'a RemoteFile,
}
impl<'a> Exists<'a> {
/// Construct a new exists action.
pub fn new(file: &'a RemoteFile) -> Self {
Self {
file,
}
}
/// Invoke the exists action.
pub fn invoke(self, client: &Client) -> Result<ExistsResponse, Error> {
self.check_exists(&client)
}
/// Send a request to check whether the file exists
fn check_exists(&self, client: &Client) -> Result<ExistsResponse, Error> {
// Get the download url, and parse the nonce
let exists_url = self.file.api_exists_url();
let mut response = client.get(exists_url)
.send()
.map_err(|_| Error::Request)?;
// Validate the status code
let status = response.status();
if !status.is_success() {
// Handle expired files
if status == FILE_EXPIRED_STATUS {
return Ok(ExistsResponse::new(false, false));
} else {
return Err(Error::RequestStatus(status, status.err_text()).into());
}
}
// Parse the response
let response = response.json::<ExistsResponse>()
.map_err(|_| Error::Malformed)?;
// TODO: fetch the metadata nonce from the response headers
Ok(response)
}
}
/// The exists response.
#[derive(Debug, Deserialize)]
pub struct ExistsResponse {
/// Whether the file exists.
#[serde(skip)]
exists: bool,
/// Whether this file requires a password.
#[serde(rename = "password")]
has_password: bool,
}
impl ExistsResponse {
/// Construct a new response.
pub fn new(exists: bool, has_password: bool) -> Self {
ExistsResponse {
exists,
has_password,
}
}
/// Whether the remote file exists on the server.
pub fn exists(&self) -> bool {
self.exists
}
/// Whether the remote file is protected by a password.
pub fn has_password(&self) -> bool {
self.has_password
}
}
impl Default for ExistsResponse {
fn default() -> Self {
ExistsResponse {
exists: false,
has_password: false,
}
}
}
#[derive(Fail, Debug)]
pub enum Error {
/// Sending the request to check whether the file exists failed.
#[fail(display = "Failed to send request whether the file exists")]
Request,
/// The response for checking whether the file exists indicated an error
/// and wasn't successful.
#[fail(display = "Bad HTTP response '{}' while requesting whether the file exists", _1)]
RequestStatus(StatusCode, String),
/// The response from the server when checking if the file exists was
/// malformed.
/// Maybe the server responded with a new format that isn't supported yet
/// by this client.
#[fail(display = "Received malformed authentication nonce")]
Malformed,
}

View file

@ -1,4 +1,5 @@
pub mod download; pub mod download;
pub mod exists;
pub mod info; pub mod info;
pub mod metadata; pub mod metadata;
pub mod params; pub mod params;

View file

@ -229,6 +229,16 @@ impl RemoteFile {
url url
} }
/// Get the API exists URL of the file.
pub fn api_exists_url(&self) -> Url {
// Get the share URL, and add the secret fragment
let mut url = self.url.clone();
url.set_path(format!("/api/exists/{}", self.id).as_str());
url.set_fragment(None);
url
}
} }
#[derive(Debug, Fail)] #[derive(Debug, Fail)]