161 lines
3.8 KiB
Rust
161 lines
3.8 KiB
Rust
use crate::services::service::{Request, Service};
|
|
use crate::store::{
|
|
object::Obj,
|
|
structs::{to_obj_path, ObjPath},
|
|
};
|
|
use crate::utils::path;
|
|
use serde::Deserialize;
|
|
use serde_xml_rs::from_str;
|
|
use std::path::PathBuf;
|
|
|
|
#[derive(Clone)]
|
|
pub enum Props {
|
|
CreationDate,
|
|
LastModified,
|
|
ETag,
|
|
ContentType,
|
|
RessourceType,
|
|
ContentLength,
|
|
ContentLanguage,
|
|
DisplayName,
|
|
FileId,
|
|
Permissions,
|
|
Size,
|
|
HasPreview,
|
|
Favorite,
|
|
CommentsUnread,
|
|
OwnerDisplayName,
|
|
ShareTypes,
|
|
ContainedFolderCount,
|
|
ContainedFileCountm,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
struct Propstat {
|
|
#[serde(rename = "prop")]
|
|
prop: Prop,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
struct Prop {
|
|
#[serde(rename = "getlastmodified")]
|
|
last_modified: Option<String>,
|
|
#[serde(rename = "getcontentlength")]
|
|
content_length: Option<u64>,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct Response {
|
|
#[serde(rename = "href")]
|
|
pub href: String,
|
|
#[serde(rename = "propstat")]
|
|
propstat: Propstat,
|
|
}
|
|
|
|
impl Response {
|
|
pub fn is_dir(&self) -> bool {
|
|
self.href.ends_with("/")
|
|
}
|
|
|
|
pub fn abs_path(&self) -> &str {
|
|
let path = self
|
|
.href
|
|
.strip_prefix("/remote.php/dav/files")
|
|
.expect(&format!(
|
|
"Unexpected result when requesting props. Cannot strip from {}",
|
|
self.href
|
|
));
|
|
|
|
if path.ends_with('/') {
|
|
path.strip_suffix('/').expect("Checked before")
|
|
} else {
|
|
path
|
|
}
|
|
}
|
|
|
|
pub fn obj_path(&self, ) -> ObjPath {
|
|
let mut path = self.abs_path();
|
|
// TODO
|
|
path = path.strip_prefix("/admin/tmp_test/").unwrap();
|
|
to_obj_path(&PathBuf::from(path))
|
|
}
|
|
|
|
pub fn path_depth(&self) -> u16 {
|
|
path::get_depth(self.abs_path())
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct Multistatus {
|
|
#[serde(rename = "response")]
|
|
pub responses: Vec<Response>,
|
|
}
|
|
|
|
impl From<&Props> for &str {
|
|
fn from(variant: &Props) -> Self {
|
|
match variant {
|
|
Props::CreationDate => "<d:creationdate />",
|
|
Props::LastModified => "<d:getlastmodified />",
|
|
_ => todo!("Props conversion not implemented"),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct ReqProps<'a> {
|
|
request: Request<'a>,
|
|
properties: Vec<Props>,
|
|
}
|
|
|
|
impl<'a> ReqProps<'a> {
|
|
pub fn new(service: &'a Service) -> Self {
|
|
ReqProps {
|
|
request: Request::new(service),
|
|
properties: Vec::new(),
|
|
}
|
|
}
|
|
|
|
pub fn set_path(mut self, path: String) -> Self {
|
|
self.request.propfind(path);
|
|
self
|
|
}
|
|
|
|
pub fn set_depth(mut self, depth: u16) -> Self {
|
|
self.request.headers.insert("Depth", depth.into());
|
|
self
|
|
}
|
|
|
|
pub fn get_properties(mut self, properties: Vec<Props>) -> Self {
|
|
self.properties.extend(properties);
|
|
self
|
|
}
|
|
|
|
pub fn get_property(&mut self, property: Props) {
|
|
self.properties.push(property);
|
|
}
|
|
|
|
fn get_body(&self) -> String {
|
|
let mut xml = String::from(
|
|
r#"<?xml version="1.0" encoding="UTF-8"?><d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"><d:prop>"#,
|
|
);
|
|
for property in &self.properties {
|
|
xml.push_str(property.into());
|
|
}
|
|
xml.push_str(r#"</d:prop></d:propfind>"#);
|
|
xml
|
|
}
|
|
|
|
pub async fn send(&mut self) -> Result<Multistatus, reqwest::Error> {
|
|
let res = self.request.send().await;
|
|
let xml = res.unwrap().text().await?;
|
|
let multistatus: Multistatus =
|
|
from_str(&xml).expect("Failed to unwrap xml response from req_props");
|
|
Ok(multistatus)
|
|
}
|
|
}
|
|
|
|
// impl From<Obj> for ReqProps<'_> {
|
|
// fn from(obj: Obj) -> Self {
|
|
// ReqProps::new(obj.get_obj_path().to_str().unwrap())
|
|
// }
|
|
// }
|