use proton_sdk::crypto::VerificationStatus;
use proton_sdk::ids::NodeUid;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
pub uid: NodeUid,
pub parent_uid: Option<NodeUid>,
pub kind: NodeKind,
pub name: String,
pub creation_time: i64,
pub modification_time: i64,
pub trashed: bool,
#[serde(default)]
pub is_shared: bool,
#[serde(default)]
pub is_shared_publicly: bool,
pub signature_email: Option<String>,
#[serde(default)]
pub verification: NodeVerification,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct NodeVerification {
pub name: VerificationStatus,
pub passphrase: VerificationStatus,
pub content_key: Option<VerificationStatus>,
pub extended_attributes: Option<VerificationStatus>,
}
impl Default for NodeVerification {
fn default() -> Self {
Self {
name: VerificationStatus::NotSigned,
passphrase: VerificationStatus::NotSigned,
content_key: None,
extended_attributes: None,
}
}
}
impl NodeVerification {
pub fn is_fully_verified(&self) -> bool {
let ok = |s: VerificationStatus| {
matches!(s, VerificationStatus::Ok | VerificationStatus::NotSigned)
};
ok(self.name)
&& ok(self.passphrase)
&& self.content_key.is_none_or(ok)
&& self.extended_attributes.is_none_or(ok)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RevisionState {
Active,
Superseded,
}
impl RevisionState {
pub(crate) fn from_raw(value: Option<i32>) -> Self {
match value {
Some(2) => Self::Superseded,
_ => Self::Active,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NodeKind {
Folder,
File {
media_type: String,
total_size_on_storage: i64,
#[serde(default)]
active_revision_state: Option<RevisionState>,
claimed_size: Option<i64>,
claimed_modification_time: Option<String>,
},
}
impl Node {
pub fn is_folder(&self) -> bool {
matches!(self.kind, NodeKind::Folder)
}
pub fn is_file(&self) -> bool {
matches!(self.kind, NodeKind::File { .. })
}
pub fn tree_event_scope_id(&self) -> crate::DriveEventScopeId {
crate::DriveEventScopeId::new(self.uid.volume_id.clone())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(i32)]
pub enum ThumbnailType {
Thumbnail = 1,
Preview = 2,
}
impl ThumbnailType {
pub fn as_i32(self) -> i32 {
self as i32
}
}
#[derive(Debug, Clone)]
pub struct Thumbnail {
pub thumbnail_type: ThumbnailType,
pub content: Vec<u8>,
}
impl Thumbnail {
pub fn new(
thumbnail_type: ThumbnailType,
content: Vec<u8>,
) -> Result<Self, proton_sdk::error::ProtonError> {
if content.is_empty() {
return Err(proton_sdk::error::ProtonError::invalid_operation(
"Thumbnail content must not be empty.",
));
}
Ok(Self {
thumbnail_type,
content,
})
}
}
#[derive(Debug)]
pub struct FileThumbnail {
pub file_uid: NodeUid,
pub result: proton_sdk::error::Result<Vec<u8>>,
}
impl FileThumbnail {
pub fn ok(file_uid: NodeUid, bytes: Vec<u8>) -> Self {
Self {
file_uid,
result: Ok(bytes),
}
}
pub fn err(file_uid: NodeUid, error: proton_sdk::error::ProtonError) -> Self {
Self {
file_uid,
result: Err(error),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn revision_state_maps_the_wire_value() {
assert_eq!(RevisionState::from_raw(Some(2)), RevisionState::Superseded);
assert_eq!(RevisionState::from_raw(Some(1)), RevisionState::Active);
assert_eq!(RevisionState::from_raw(Some(0)), RevisionState::Active);
assert_eq!(RevisionState::from_raw(None), RevisionState::Active);
}
}