/* * SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ use ahash::AHashMap; use mail_parser::decoders::base64::base64_decode; use utils::map::vec_map::VecMap; use crate::{ error::set::SetError, parser::{json::Parser, Ignore, JsonObjectParser, Token}, request::{reference::MaybeReference, RequestProperty}, response::Response, types::{blob::BlobId, id::Id}, }; use super::ahash_is_empty; #[derive(Debug, Clone)] pub struct BlobUploadRequest { pub account_id: Id, pub create: VecMap, } #[derive(Debug, Clone)] pub struct UploadObject { pub type_: Option, pub data: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum DataSourceObject { Id { id: MaybeReference, length: Option, offset: Option, }, Value(Vec), } #[derive(Debug, Clone, Default, serde::Serialize)] pub struct BlobUploadResponse { #[serde(rename = "accountId")] pub account_id: Id, #[serde(rename = "created")] #[serde(skip_serializing_if = "ahash_is_empty")] pub created: AHashMap, #[serde(rename = "notCreated")] #[serde(skip_serializing_if = "VecMap::is_empty")] pub not_created: VecMap, } #[derive(Debug, Clone, Default, serde::Serialize)] pub struct BlobUploadResponseObject { pub id: BlobId, #[serde(rename = "type")] #[serde(skip_serializing_if = "Option::is_none")] pub type_: Option, pub size: usize, } impl JsonObjectParser for BlobUploadRequest { fn parse(parser: &mut Parser<'_>) -> trc::Result where Self: Sized, { let mut request = BlobUploadRequest { account_id: Id::default(), create: VecMap::new(), }; parser .next_token::()? .assert_jmap(Token::DictStart)?; while let Some(key) = parser.next_dict_key::()? { match &key.hash[0] { 0x0064_4974_6e75_6f63_6361 if !key.is_ref => { request.account_id = parser.next_token::()?.unwrap_string("accountId")?; } 0x6574_6165_7263 if !key.is_ref => { request.create = >::parse(parser)?; } _ => { parser.skip_token(parser.depth_array, parser.depth_dict)?; } } } Ok(request) } } impl JsonObjectParser for UploadObject { fn parse(parser: &mut Parser<'_>) -> trc::Result where Self: Sized, { let mut request = UploadObject { type_: None, data: Vec::new(), }; parser .next_token::()? .assert_jmap(Token::DictStart)?; while let Some(key) = parser.next_dict_key::()? { match &key.hash[0] { 0x6570_7974 if !key.is_ref => { request.type_ = parser .next_token::()? .unwrap_string_or_null("type")?; } 0x6174_6164 if !key.is_ref => { parser.next_token::()?.assert(Token::ArrayStart)?; loop { match parser.next_token::()? { Token::Comma => (), Token::ArrayEnd => break, Token::DictStart => { request.data.push(DataSourceObject::parse(parser)?); } token => return Err(token.error("", "DataSourceObject")), } } } _ => { parser.skip_token(parser.depth_array, parser.depth_dict)?; } } } Ok(request) } } impl JsonObjectParser for DataSourceObject { fn parse(parser: &mut Parser<'_>) -> trc::Result where Self: Sized, { let mut data: Option> = None; let mut blob_id: Option> = None; let mut offset: Option = None; let mut length: Option = None; while let Some(key) = parser.next_dict_key::()? { match &key.hash[0] { 0x0074_7865_5473_613a_6174_6164 if !key.is_ref => { data = parser .next_token::()? .unwrap_string("data:asText")? .into_bytes() .into(); } 0x0034_3665_7361_4273_613a_6174_6164 if !key.is_ref => { data = base64_decode( parser .next_token::()? .unwrap_string("data:asBase64")? .as_bytes(), ) .ok_or_else(|| parser.error("Failed to decode data:asBase64"))? .into(); } 0x6449_626f_6c62 if !key.is_ref => { blob_id = parser .next_token::>()? .unwrap_string("blobId")? .into(); } 0x6874_676e_656c if !key.is_ref => { length = parser .next_token::()? .unwrap_usize_or_null("length")?; } 0x7465_7366_666f if !key.is_ref => { offset = parser .next_token::()? .unwrap_usize_or_null("offset")?; } _ => { parser.skip_token(parser.depth_array, parser.depth_dict)?; } } } if let Some(data) = data { Ok(DataSourceObject::Value(data)) } else if let Some(blob_id) = blob_id { Ok(DataSourceObject::Id { id: blob_id, length, offset, }) } else { Err(parser.error("Missing data or blobId in DataSourceObject")) } } } impl BlobUploadResponse { pub fn update_created_ids(&self, response: &mut Response) { for (user_id, obj) in &self.created { response .created_ids .insert(user_id.clone(), obj.id.clone().into()); } } }