fix flags case sensitivity

This commit is contained in:
Clément DOUIN 2023-02-20 17:41:26 +01:00
parent 0ab652b4b6
commit 3631ca714b
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
13 changed files with 194 additions and 17 deletions

View file

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed config deserialization issue with `email-hooks` and - Fixed config deserialization issue with `email-hooks` and
`email-reading-format`. `email-reading-format`.
- Fixed flags case sensitivity.
## [0.7.1] - 2023-02-14 ## [0.7.1] - 2023-02-14

4
Cargo.lock generated
View file

@ -775,6 +775,7 @@ version = "0.7.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"atty", "atty",
"chrono",
"clap", "clap",
"clap_complete", "clap_complete",
"clap_mangen", "clap_mangen",
@ -803,7 +804,7 @@ dependencies = [
[[package]] [[package]]
name = "himalaya-lib" name = "himalaya-lib"
version = "0.6.0" version = "0.6.0"
source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#8c538689c9d3098f8e69493791ccbbe52eb9af58" source = "git+https://git.sr.ht/~soywod/himalaya-lib?branch=develop#26d3b9e74c978f6dc94689bff809d48fe5ba4c85"
dependencies = [ dependencies = [
"ammonia", "ammonia",
"chrono", "chrono",
@ -827,7 +828,6 @@ dependencies = [
"regex", "regex",
"rfc2047-decoder", "rfc2047-decoder",
"rusqlite", "rusqlite",
"serde",
"shellexpand", "shellexpand",
"thiserror", "thiserror",
"tree_magic", "tree_magic",

View file

@ -27,6 +27,7 @@ tempfile = "3.3"
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
atty = "0.2" atty = "0.2"
chrono = "0.4.23"
clap = "4.0" clap = "4.0"
clap_complete = "4.0" clap_complete = "4.0"
clap_mangen = "0.2" clap_mangen = "0.2"

View file

@ -14,6 +14,7 @@ use uuid::Uuid;
use crate::{ use crate::{
printer::{PrintTableOpts, Printer}, printer::{PrintTableOpts, Printer},
ui::editor, ui::editor,
Envelopes,
}; };
pub fn attachments<P: Printer, B: Backend + ?Sized>( pub fn attachments<P: Printer, B: Backend + ?Sized>(
@ -132,10 +133,10 @@ pub fn list<P: Printer, B: Backend + ?Sized>(
let folder = config.folder_alias(folder)?; let folder = config.folder_alias(folder)?;
let page_size = page_size.unwrap_or(config.email_listing_page_size()); let page_size = page_size.unwrap_or(config.email_listing_page_size());
debug!("page size: {}", page_size); debug!("page size: {}", page_size);
let msgs = backend.list_envelopes(&folder, page_size, page)?; let envelopes: Envelopes = backend.list_envelopes(&folder, page_size, page)?.into();
trace!("envelopes: {:?}", msgs); trace!("envelopes: {:?}", envelopes);
printer.print_table( printer.print_table(
Box::new(msgs), Box::new(envelopes),
PrintTableOpts { PrintTableOpts {
format: &config.email_reading_format, format: &config.email_reading_format,
max_width, max_width,
@ -291,7 +292,9 @@ pub fn search<P: Printer, B: Backend + ?Sized>(
) -> Result<()> { ) -> Result<()> {
let folder = config.folder_alias(folder)?; let folder = config.folder_alias(folder)?;
let page_size = page_size.unwrap_or(config.email_listing_page_size()); let page_size = page_size.unwrap_or(config.email_listing_page_size());
let envelopes = backend.search_envelopes(&folder, &query, "", page_size, page)?; let envelopes: Envelopes = backend
.search_envelopes(&folder, &query, "", page_size, page)?
.into();
let opts = PrintTableOpts { let opts = PrintTableOpts {
format: &config.email_reading_format, format: &config.email_reading_format,
max_width, max_width,
@ -313,7 +316,9 @@ pub fn sort<P: Printer, B: Backend + ?Sized>(
) -> Result<()> { ) -> Result<()> {
let folder = config.folder_alias(folder)?; let folder = config.folder_alias(folder)?;
let page_size = page_size.unwrap_or(config.email_listing_page_size()); let page_size = page_size.unwrap_or(config.email_listing_page_size());
let envelopes = backend.search_envelopes(&folder, &query, &sort, page_size, page)?; let envelopes: Envelopes = backend
.search_envelopes(&folder, &query, &sort, page_size, page)?
.into();
let opts = PrintTableOpts { let opts = PrintTableOpts {
format: &config.email_reading_format, format: &config.email_reading_format,
max_width, max_width,

View file

@ -1,6 +1,45 @@
use himalaya_lib::{Envelope, Flag}; use chrono::{DateTime, Local};
use serde::{Serialize, Serializer};
use crate::ui::{Cell, Row, Table}; use crate::{
ui::{Cell, Row, Table},
Flag, Flags,
};
fn date<S: Serializer>(date: &DateTime<Local>, s: S) -> Result<S::Ok, S::Error> {
s.serialize_str(&date.to_rfc3339())
}
#[derive(Clone, Debug, Default, Serialize)]
pub struct Mailbox {
pub name: Option<String>,
pub addr: String,
}
#[derive(Clone, Debug, Default, Serialize)]
pub struct Envelope {
pub id: String,
pub flags: Flags,
pub subject: String,
pub from: Mailbox,
#[serde(serialize_with = "date")]
pub date: DateTime<Local>,
}
impl From<&himalaya_lib::Envelope> for Envelope {
fn from(envelope: &himalaya_lib::Envelope) -> Self {
Envelope {
id: envelope.id.clone(),
flags: envelope.flags.clone().into(),
subject: envelope.subject.clone(),
from: Mailbox {
name: envelope.from.name.clone(),
addr: envelope.from.addr.clone(),
},
date: envelope.date.clone(),
}
}
}
impl Table for Envelope { impl Table for Envelope {
fn head() -> Row { fn head() -> Row {
@ -14,15 +53,29 @@ impl Table for Envelope {
fn row(&self) -> Row { fn row(&self) -> Row {
let id = self.id.to_string(); let id = self.id.to_string();
let flags = self.flags.to_symbols_string();
let unseen = !self.flags.contains(&Flag::Seen); let unseen = !self.flags.contains(&Flag::Seen);
let flags = {
let mut flags = String::new();
flags.push_str(if !unseen { " " } else { "" });
flags.push_str(if self.flags.contains(&Flag::Answered) {
""
} else {
" "
});
flags.push_str(if self.flags.contains(&Flag::Flagged) {
""
} else {
" "
});
flags
};
let subject = &self.subject; let subject = &self.subject;
let sender = if let Some(name) = &self.from.name { let sender = if let Some(name) = &self.from.name {
name name
} else { } else {
&self.from.addr &self.from.addr
}; };
let date = self.date.format("%d/%m/%Y %H:%M").to_string(); let date = self.date.to_rfc3339();
Row::new() Row::new()
.cell(Cell::new(id).bold_if(unseen).red()) .cell(Cell::new(id).bold_if(unseen).red())

View file

@ -1,11 +1,32 @@
use std::ops;
use anyhow::Result; use anyhow::Result;
use himalaya_lib::Envelopes; use serde::Serialize;
use crate::{ use crate::{
printer::{PrintTable, PrintTableOpts, WriteColor}, printer::{PrintTable, PrintTableOpts, WriteColor},
ui::Table, ui::Table,
Envelope,
}; };
/// Represents the list of envelopes.
#[derive(Clone, Debug, Default, Serialize)]
pub struct Envelopes(Vec<Envelope>);
impl ops::Deref for Envelopes {
type Target = Vec<Envelope>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<himalaya_lib::Envelopes> for Envelopes {
fn from(envelopes: himalaya_lib::Envelopes) -> Self {
Envelopes(envelopes.iter().map(Envelope::from).collect())
}
}
impl PrintTable for Envelopes { impl PrintTable for Envelopes {
fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> { fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> {
writeln!(writer)?; writeln!(writer)?;

View file

@ -83,7 +83,11 @@ pub fn flags_arg() -> Arg {
Arg::new(ARG_FLAGS) Arg::new(ARG_FLAGS)
.value_name("FLAGS") .value_name("FLAGS")
.help("The flags") .help("The flags")
.long_help("The list of flags. It can be one of: seen, answered, flagged, deleted, draft, recent. Other flags are considered custom.") .long_help(
"The list of flags.
It can be one of: seen, answered, flagged, deleted, or draft.
Other flags are considered custom.",
)
.num_args(1..) .num_args(1..)
.required(true) .required(true)
.last(true) .last(true)

25
src/domain/flag/flag.rs Normal file
View file

@ -0,0 +1,25 @@
use serde::Serialize;
/// Represents the flag variants.
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize)]
pub enum Flag {
Seen,
Answered,
Flagged,
Deleted,
Draft,
Custom(String),
}
impl From<&himalaya_lib::Flag> for Flag {
fn from(flag: &himalaya_lib::Flag) -> Self {
match flag {
himalaya_lib::Flag::Seen => Flag::Seen,
himalaya_lib::Flag::Answered => Flag::Answered,
himalaya_lib::Flag::Flagged => Flag::Flagged,
himalaya_lib::Flag::Deleted => Flag::Deleted,
himalaya_lib::Flag::Draft => Flag::Draft,
himalaya_lib::Flag::Custom(flag) => Flag::Custom(flag.clone()),
}
}
}

21
src/domain/flag/flags.rs Normal file
View file

@ -0,0 +1,21 @@
use serde::Serialize;
use std::{collections::HashSet, ops};
use crate::Flag;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
pub struct Flags(pub HashSet<Flag>);
impl ops::Deref for Flags {
type Target = HashSet<Flag>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<himalaya_lib::Flags> for Flags {
fn from(flags: himalaya_lib::Flags) -> Self {
Flags(flags.iter().map(Flag::from).collect())
}
}

View file

@ -1,2 +1,8 @@
pub mod args; pub mod args;
pub mod handlers; pub mod handlers;
pub mod flag;
pub use flag::*;
pub mod flags;
pub use flags::*;

View file

@ -1,7 +1,24 @@
use himalaya_lib::folder::Folder; use serde::Serialize;
use crate::ui::{Cell, Row, Table}; use crate::ui::{Cell, Row, Table};
#[derive(Clone, Debug, Default, Serialize)]
pub struct Folder {
pub delim: String,
pub name: String,
pub desc: String,
}
impl From<&himalaya_lib::Folder> for Folder {
fn from(folder: &himalaya_lib::Folder) -> Self {
Folder {
delim: folder.delim.clone(),
name: folder.name.clone(),
desc: folder.desc.clone(),
}
}
}
impl Table for Folder { impl Table for Folder {
fn head() -> Row { fn head() -> Row {
Row::new() Row::new()

View file

@ -1,11 +1,31 @@
use std::ops;
use anyhow::Result; use anyhow::Result;
use himalaya_lib::folder::Folders; use serde::Serialize;
use crate::{ use crate::{
printer::{PrintTable, PrintTableOpts, WriteColor}, printer::{PrintTable, PrintTableOpts, WriteColor},
ui::Table, ui::Table,
Folder,
}; };
#[derive(Clone, Debug, Default, Serialize)]
pub struct Folders(Vec<Folder>);
impl ops::Deref for Folders {
type Target = Vec<Folder>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<himalaya_lib::Folders> for Folders {
fn from(folders: himalaya_lib::Folders) -> Self {
Folders(folders.iter().map(Folder::from).collect())
}
}
impl PrintTable for Folders { impl PrintTable for Folders {
fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> { fn print_table(&self, writer: &mut dyn WriteColor, opts: PrintTableOpts) -> Result<()> {
writeln!(writer)?; writeln!(writer)?;

View file

@ -5,7 +5,10 @@
use anyhow::Result; use anyhow::Result;
use himalaya_lib::{AccountConfig, Backend}; use himalaya_lib::{AccountConfig, Backend};
use crate::printer::{PrintTableOpts, Printer}; use crate::{
printer::{PrintTableOpts, Printer},
Folders,
};
pub fn expunge<P: Printer, B: Backend + ?Sized>( pub fn expunge<P: Printer, B: Backend + ?Sized>(
folder: &str, folder: &str,
@ -22,7 +25,7 @@ pub fn list<P: Printer, B: Backend + ?Sized>(
printer: &mut P, printer: &mut P,
backend: &mut B, backend: &mut B,
) -> Result<()> { ) -> Result<()> {
let folders = backend.list_folders()?; let folders: Folders = backend.list_folders()?.into();
printer.print_table( printer.print_table(
// TODO: remove Box // TODO: remove Box
Box::new(folders), Box::new(folders),