nextsync/src/services/req_props.rs

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())
// }
// }