fix listings json api (#331) and maildir e2e tests (#335)

This commit is contained in:
Clément DOUIN 2022-03-12 00:33:50 +01:00
parent 811ea45610
commit 6b042f5e6a
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
11 changed files with 70 additions and 46 deletions

View file

@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `In-Reply-To` not set properly when replying to a message [#323] - `In-Reply-To` not set properly when replying to a message [#323]
- `Cc` missing or invalid when replying to a message [#324] - `Cc` missing or invalid when replying to a message [#324]
- Notmuch backend hangs [#329] - Notmuch backend hangs [#329]
- Maildir e2e tests [#335]
- JSON API for listings [#331]
## [0.5.8] - 2022-03-04 ## [0.5.8] - 2022-03-04
@ -499,3 +501,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#323]: https://github.com/soywod/himalaya/issues/323 [#323]: https://github.com/soywod/himalaya/issues/323
[#324]: https://github.com/soywod/himalaya/issues/324 [#324]: https://github.com/soywod/himalaya/issues/324
[#329]: https://github.com/soywod/himalaya/issues/329 [#329]: https://github.com/soywod/himalaya/issues/329
[#331]: https://github.com/soywod/himalaya/issues/331
[#335]: https://github.com/soywod/himalaya/issues/335

View file

@ -15,13 +15,16 @@ use super::{ImapFlag, ImapFlags};
/// Represents a list of IMAP envelopes. /// Represents a list of IMAP envelopes.
#[derive(Debug, Default, serde::Serialize)] #[derive(Debug, Default, serde::Serialize)]
pub struct ImapEnvelopes(pub Vec<ImapEnvelope>); pub struct ImapEnvelopes {
#[serde(rename = "response")]
pub envelopes: Vec<ImapEnvelope>,
}
impl Deref for ImapEnvelopes { impl Deref for ImapEnvelopes {
type Target = Vec<ImapEnvelope>; type Target = Vec<ImapEnvelope>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.envelopes
} }
} }
@ -99,7 +102,7 @@ impl TryFrom<RawImapEnvelopes> for ImapEnvelopes {
for raw_envelope in raw_envelopes.iter().rev() { for raw_envelope in raw_envelopes.iter().rev() {
envelopes.push(ImapEnvelope::try_from(raw_envelope).context("cannot parse envelope")?); envelopes.push(ImapEnvelope::try_from(raw_envelope).context("cannot parse envelope")?);
} }
Ok(Self(envelopes)) Ok(Self { envelopes })
} }
} }

View file

@ -4,6 +4,7 @@
//! to the mailbox. //! to the mailbox.
use anyhow::Result; use anyhow::Result;
use serde::Serialize;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::ops::Deref; use std::ops::Deref;
@ -16,14 +17,17 @@ use crate::{
use super::ImapMboxAttrs; use super::ImapMboxAttrs;
/// Represents a list of IMAP mailboxes. /// Represents a list of IMAP mailboxes.
#[derive(Debug, Default, serde::Serialize)] #[derive(Debug, Default, Serialize)]
pub struct ImapMboxes(pub Vec<ImapMbox>); pub struct ImapMboxes {
#[serde(rename = "response")]
pub mboxes: Vec<ImapMbox>,
}
impl Deref for ImapMboxes { impl Deref for ImapMboxes {
type Target = Vec<ImapMbox>; type Target = Vec<ImapMbox>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.mboxes
} }
} }
@ -130,7 +134,9 @@ pub type RawImapMboxes = imap::types::ZeroCopy<Vec<RawImapMbox>>;
impl<'a> From<RawImapMboxes> for ImapMboxes { impl<'a> From<RawImapMboxes> for ImapMboxes {
fn from(raw_mboxes: RawImapMboxes) -> Self { fn from(raw_mboxes: RawImapMboxes) -> Self {
Self(raw_mboxes.iter().map(ImapMbox::from).collect()) Self {
mboxes: raw_mboxes.iter().map(ImapMbox::from).collect(),
}
} }
} }

View file

@ -151,7 +151,7 @@ impl<'a> Backend<'a> for MaildirBackend<'a> {
envelopes.sort_by(|a, b| b.date.partial_cmp(&a.date).unwrap()); envelopes.sort_by(|a, b| b.date.partial_cmp(&a.date).unwrap());
// Applies pagination boundaries. // Applies pagination boundaries.
envelopes.0 = envelopes[page_begin..page_end].to_owned(); envelopes.envelopes = envelopes[page_begin..page_end].to_owned();
// Appends envelopes hash to the id mapper cache file and // Appends envelopes hash to the id mapper cache file and
// calculates the new short hash length. The short hash length // calculates the new short hash length. The short hash length

View file

@ -20,19 +20,22 @@ use crate::{
/// Represents a list of envelopes. /// Represents a list of envelopes.
#[derive(Debug, Default, serde::Serialize)] #[derive(Debug, Default, serde::Serialize)]
pub struct MaildirEnvelopes(pub Vec<MaildirEnvelope>); pub struct MaildirEnvelopes {
#[serde(rename = "response")]
pub envelopes: Vec<MaildirEnvelope>,
}
impl Deref for MaildirEnvelopes { impl Deref for MaildirEnvelopes {
type Target = Vec<MaildirEnvelope>; type Target = Vec<MaildirEnvelope>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.envelopes
} }
} }
impl DerefMut for MaildirEnvelopes { impl DerefMut for MaildirEnvelopes {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0 &mut self.envelopes
} }
} }
@ -114,7 +117,7 @@ impl<'a> TryFrom<RawMaildirEnvelopes> for MaildirEnvelopes {
envelopes.push(envelope); envelopes.push(envelope);
} }
Ok(MaildirEnvelopes(envelopes)) Ok(MaildirEnvelopes { envelopes })
} }
} }

View file

@ -19,13 +19,16 @@ use crate::{
/// Represents a list of Maildir mailboxes. /// Represents a list of Maildir mailboxes.
#[derive(Debug, Default, serde::Serialize)] #[derive(Debug, Default, serde::Serialize)]
pub struct MaildirMboxes(pub Vec<MaildirMbox>); pub struct MaildirMboxes {
#[serde(rename = "response")]
pub mboxes: Vec<MaildirMbox>,
}
impl Deref for MaildirMboxes { impl Deref for MaildirMboxes {
type Target = Vec<MaildirMbox>; type Target = Vec<MaildirMbox>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.mboxes
} }
} }
@ -113,7 +116,7 @@ impl TryFrom<RawMaildirMboxes> for MaildirMboxes {
for entry in mail_entries { for entry in mail_entries {
mboxes.push(entry?.try_into()?); mboxes.push(entry?.try_into()?);
} }
Ok(MaildirMboxes(mboxes)) Ok(MaildirMboxes { mboxes })
} }
} }

View file

@ -81,7 +81,7 @@ impl<'a> NotmuchBackend<'a> {
envelopes.sort_by(|a, b| b.date.partial_cmp(&a.date).unwrap()); envelopes.sort_by(|a, b| b.date.partial_cmp(&a.date).unwrap());
// Applies pagination boundaries. // Applies pagination boundaries.
envelopes.0 = envelopes[page_begin..page_end].to_owned(); envelopes.envelopes = envelopes[page_begin..page_end].to_owned();
// Appends envelopes hash to the id mapper cache file and // Appends envelopes hash to the id mapper cache file and
// calculates the new short hash length. The short hash length // calculates the new short hash length. The short hash length
@ -118,17 +118,17 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> {
fn get_mboxes(&mut self) -> Result<Box<dyn Mboxes>> { fn get_mboxes(&mut self) -> Result<Box<dyn Mboxes>> {
info!(">> get notmuch virtual mailboxes"); info!(">> get notmuch virtual mailboxes");
let mut virt_mboxes: Vec<_> = self let mut mboxes: Vec<_> = self
.account_config .account_config
.mailboxes .mailboxes
.iter() .iter()
.map(|(k, v)| NotmuchMbox::new(k, v)) .map(|(k, v)| NotmuchMbox::new(k, v))
.collect(); .collect();
trace!("virtual mailboxes: {:?}", virt_mboxes); trace!("virtual mailboxes: {:?}", mboxes);
virt_mboxes.sort_by(|a, b| b.name.partial_cmp(&a.name).unwrap()); mboxes.sort_by(|a, b| b.name.partial_cmp(&a.name).unwrap());
info!("<< get notmuch virtual mailboxes"); info!("<< get notmuch virtual mailboxes");
Ok(Box::new(NotmuchMboxes(virt_mboxes))) Ok(Box::new(NotmuchMboxes { mboxes }))
} }
fn del_mbox(&mut self, _mbox: &str) -> Result<()> { fn del_mbox(&mut self, _mbox: &str) -> Result<()> {
@ -202,7 +202,7 @@ impl<'a> Backend<'a> for NotmuchBackend<'a> {
// Adds the message to the maildir folder and gets its hash. // Adds the message to the maildir folder and gets its hash.
let hash = self let hash = self
.mdir .mdir
.add_msg("inbox", msg, "seen") .add_msg("", msg, "seen")
.with_context(|| { .with_context(|| {
format!( format!(
"cannot add notmuch message to maildir {:?}", "cannot add notmuch message to maildir {:?}",

View file

@ -19,19 +19,22 @@ use crate::{
/// Represents a list of envelopes. /// Represents a list of envelopes.
#[derive(Debug, Default, serde::Serialize)] #[derive(Debug, Default, serde::Serialize)]
pub struct NotmuchEnvelopes(pub Vec<NotmuchEnvelope>); pub struct NotmuchEnvelopes {
#[serde(rename = "response")]
pub envelopes: Vec<NotmuchEnvelope>,
}
impl Deref for NotmuchEnvelopes { impl Deref for NotmuchEnvelopes {
type Target = Vec<NotmuchEnvelope>; type Target = Vec<NotmuchEnvelope>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.envelopes
} }
} }
impl DerefMut for NotmuchEnvelopes { impl DerefMut for NotmuchEnvelopes {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0 &mut self.envelopes
} }
} }
@ -107,7 +110,7 @@ impl<'a> TryFrom<RawNotmuchEnvelopes> for NotmuchEnvelopes {
.context("cannot parse notmuch mail entry")?; .context("cannot parse notmuch mail entry")?;
envelopes.push(envelope); envelopes.push(envelope);
} }
Ok(NotmuchEnvelopes(envelopes)) Ok(NotmuchEnvelopes { envelopes })
} }
} }

View file

@ -17,13 +17,16 @@ use crate::{
/// Represents a list of Notmuch mailboxes. /// Represents a list of Notmuch mailboxes.
#[derive(Debug, Default, serde::Serialize)] #[derive(Debug, Default, serde::Serialize)]
pub struct NotmuchMboxes(pub Vec<NotmuchMbox>); pub struct NotmuchMboxes {
#[serde(rename = "response")]
pub mboxes: Vec<NotmuchMbox>,
}
impl Deref for NotmuchMboxes { impl Deref for NotmuchMboxes {
type Target = Vec<NotmuchMbox>; type Target = Vec<NotmuchMbox>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.mboxes
} }
} }

View file

@ -115,21 +115,23 @@ mod tests {
unimplemented!(); unimplemented!();
} }
fn get_mboxes(&mut self) -> Result<Box<dyn Mboxes>> { fn get_mboxes(&mut self) -> Result<Box<dyn Mboxes>> {
Ok(Box::new(ImapMboxes(vec![ Ok(Box::new(ImapMboxes {
ImapMbox { mboxes: vec![
delim: "/".into(), ImapMbox {
name: "INBOX".into(), delim: "/".into(),
attrs: ImapMboxAttrs(vec![ImapMboxAttr::NoSelect]), name: "INBOX".into(),
}, attrs: ImapMboxAttrs(vec![ImapMboxAttr::NoSelect]),
ImapMbox { },
delim: "/".into(), ImapMbox {
name: "Sent".into(), delim: "/".into(),
attrs: ImapMboxAttrs(vec![ name: "Sent".into(),
ImapMboxAttr::NoInferiors, attrs: ImapMboxAttrs(vec![
ImapMboxAttr::Custom("HasNoChildren".into()), ImapMboxAttr::NoInferiors,
]), ImapMboxAttr::Custom("HasNoChildren".into()),
}, ]),
]))) },
],
}))
} }
fn del_mbox(&mut self, _: &str) -> Result<()> { fn del_mbox(&mut self, _: &str) -> Result<()> {
unimplemented!(); unimplemented!();

View file

@ -19,10 +19,7 @@ fn test_maildir_backend() {
// configure accounts // configure accounts
let account_config = AccountConfig { let account_config = AccountConfig {
mailboxes: HashMap::from_iter([ mailboxes: HashMap::from_iter([("subdir".into(), "Subdir".into())]),
("inbox".into(), "INBOX".into()),
("subdir".into(), "Subdir".into()),
]),
..AccountConfig::default() ..AccountConfig::default()
}; };
let mdir_config = MaildirBackendConfig { let mdir_config = MaildirBackendConfig {