Skip to content

Commit

Permalink
cli: Add set-message-filter-setting list subcommand
Browse files Browse the repository at this point in the history
Allow setting message filter settings via CLI.

Signed-off-by: Manos Pitsidianakis <[email protected]>
  • Loading branch information
epilys committed Sep 1, 2024
1 parent 0da1677 commit f2163dd
Show file tree
Hide file tree
Showing 13 changed files with 375 additions and 34 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@

## crates:

- `core` the library
- `cli` a command line tool to manage lists
- `web` an `axum` based web server capable of serving archives and authenticating list owners and members
- `archive-http` static web archive generation or with a dynamic http server
- `rest-http` a REST http server to manage lists
- `mailpot` the core library
- `mailpot-cli` a command line tool to manage lists
- `mailpot-web` an `axum` based web server capable of serving archives and authenticating list owners and members
- `mailpot-archives` static web archive generation or with a dynamic http server
- `mailpot-http` a REST http server to manage lists

## Features

- easy setup
- extensible through Rust API as a [library](./core)
- basic management through [CLI tool](./cli/)
- optional lightweight web archiver ([static](./archive-http/) and [dynamic](./web/))
- optional lightweight web archiver ([static](./mailpot-archives/) and [dynamic](./mailpot-web/))
- useful for both **newsletters**, **communities** and for static **article comments**

## Roadmap
Expand Down
50 changes: 50 additions & 0 deletions docs/mpot.1
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,56 @@ Don\*(Aqt import list owners.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\fB
.SS mpot list print-message-filter-settings
.\fR
.br

.br

mpot list print\-message\-filter\-settings [\-\-show\-available \fISHOW_AVAILABLE\fR] [\-\-filter \fIFILTER\fR]
.br

Print message filter settings.
.TP
\-\-show\-available
Show available schemas instead of stored settings.
.br

.br

.br
[\fIpossible values: \fRtrue, false]
.TP
\-\-filter \fIFILTER\fR
Filter results, case\-insensitive.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\fB
.SS mpot list set-message-filter-setting
.\fR
.br

.br

mpot list set\-message\-filter\-setting \-\-name \fINAME\fR \-\-value \fIVALUE\fR
.br

Print message filter settings.
.TP
\-\-name \fINAME\fR
Setting name.
.br

.br

.br
[\fIpossible values: \fRAddSubjectTagPrefixSettings, MimeRejectSettings, ArchivedAtLinkSettings]
.TP
\-\-value \fIVALUE\fR
Json value.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\fB
.SS mpot create-list
.\fR
.br
Expand Down
42 changes: 24 additions & 18 deletions mailpot-cli/build.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
/*
* This file is part of mailpot
*
* Copyright 2020 - Manos Pitsidianakis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//
// This file is part of mailpot
//
// Copyright 2020 - Manos Pitsidianakis
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use std::{
collections::{hash_map::RandomState, HashSet, VecDeque},
Expand All @@ -27,13 +26,20 @@ use clap::{ArgAction, CommandFactory};
use clap_mangen::{roff, Man};
use roff::{bold, italic, roman, Inline, Roff};

mod message_filter_settings {
include!("src/message_filter_settings.rs");
}
include!("src/args.rs");

fn main() -> std::io::Result<()> {
println!("cargo:rerun-if-changed=./src/lib.rs");
println!("cargo:rerun-if-changed=./build.rs");
std::env::set_current_dir("..").expect("could not chdir('..')");
make_manpage()?;
Ok(())
}

fn make_manpage() -> std::io::Result<()> {
let out_dir = PathBuf::from("./docs/");

let cmd = Opt::command();
Expand Down
22 changes: 22 additions & 0 deletions mailpot-cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ pub use std::path::PathBuf;

pub use clap::{builder::TypedValueParser, Args, Parser, Subcommand};

use crate::message_filter_settings::{
MessageFilterSettingName, MessageFilterSettingNameValueParser,
};

#[derive(Debug, Parser)]
#[command(
name = "mpot",
Expand Down Expand Up @@ -507,6 +511,24 @@ pub enum ListCommand {
#[arg(long)]
skip_owners: bool,
},
/// Print message filter settings.
PrintMessageFilterSettings {
/// Show available schemas instead of stored settings.
#[arg(long)]
show_available: bool,
/// Filter results, case-insensitive.
#[arg(long)]
filter: Option<String>,
},
/// Print message filter settings.
SetMessageFilterSetting {
/// Setting name.
#[arg(long, value_parser = MessageFilterSettingNameValueParser)]
name: MessageFilterSettingName,
/// Json value.
#[arg(long)]
value: String,
},
}

#[derive(Clone, Copy, Debug)]
Expand Down
59 changes: 59 additions & 0 deletions mailpot-cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,65 @@ pub fn list(db: &mut Connection, list_id: &str, cmd: ListCommand, quiet: bool) -

println!("Sent confirmation e-mail to {}", req.address());
}
PrintMessageFilterSettings {
show_available: true,
ref filter,
} => {
use crate::message_filter_settings::MessageFilterSettingNameValueParser;
let value_parser = MessageFilterSettingNameValueParser;
let Some(possible_values) =
<MessageFilterSettingNameValueParser as TypedValueParser>::possible_values(
&value_parser,
)
else {
println!("No settings available.");
return Ok(());
};
let mut possible_values = possible_values.into_iter().collect::<Vec<_>>();
possible_values.sort_by(|a, b| a.get_name().partial_cmp(b.get_name()).unwrap());
for val in possible_values.into_iter().filter(|val| {
let Some(filter) = filter.as_ref() else {
return true;
};
val.matches(filter, true)
}) {
println!("{}", val.get_name());
}
}
PrintMessageFilterSettings {
show_available: false,
filter,
} => {
let mut settings = db
.get_settings(list.pk())?
.into_iter()
.collect::<Vec<(_, _)>>();
settings.sort_by(|(a, _), (b, _)| a.partial_cmp(b).unwrap());
for (name, value) in settings.iter().filter(|(name, _)| {
let Some(filter) = filter.as_ref() else {
return true;
};
name.to_ascii_lowercase()
.contains(&filter.to_ascii_lowercase())
}) {
println!("{}: {}", name, value);
}
}
SetMessageFilterSetting { name, value } => {
let value = serde_json::from_str(&value).map_err(|err| {
ErrorKind::External(mailpot::anyhow::anyhow!(format!(
"Provided value is not valid json: {}",
err
)))
})?;
db.set_settings(list.pk(), &name.to_string(), value)?;
if !quiet {
println!(
"Successfully updated {} value for list {}.",
name, list.name
);
}
}
}
Ok(())
}
Expand Down
5 changes: 5 additions & 0 deletions mailpot-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,10 @@ mod args;
pub mod commands;
pub mod import;
pub mod lints;
#[rustfmt::skip]
#[allow(clippy::derivable_impls)]
/// This module is automatically generated by `build.rs`.
pub mod message_filter_settings;

pub use args::*;
pub use clap::{Args, CommandFactory, Parser, Subcommand};
22 changes: 22 additions & 0 deletions mailpot-cli/src/message_filter_settings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @generated
//
// This file is part of mailpot
//
// Copyright 2023 - Manos Pitsidianakis
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use clap::builder::TypedValueParser;

# [allow (clippy :: enum_variant_names)] # [derive (Clone , Copy , Debug , PartialEq , Eq , Hash)] pub enum MessageFilterSettingName { AddSubjectTagPrefixSettings , MimeRejectSettings , ArchivedAtLinkSettings } impl :: std :: str :: FromStr for MessageFilterSettingName { type Err = String ; fn from_str (s : & str) -> Result < Self , Self :: Err > { # ! [allow (clippy :: suspicious_else_formatting)] if s . eq_ignore_ascii_case (stringify ! (AddSubjectTagPrefixSettings)) { return Ok (Self :: AddSubjectTagPrefixSettings) ; } if s . eq_ignore_ascii_case (stringify ! (MimeRejectSettings)) { return Ok (Self :: MimeRejectSettings) ; } if s . eq_ignore_ascii_case (stringify ! (ArchivedAtLinkSettings)) { return Ok (Self :: ArchivedAtLinkSettings) ; } Err (format ! ("Unrecognized value: {s}")) } } impl :: std :: fmt :: Display for MessageFilterSettingName { fn fmt (& self , fmt : & mut :: std :: fmt :: Formatter) -> :: std :: fmt :: Result { write ! (fmt , "{}" , match self { Self :: AddSubjectTagPrefixSettings => stringify ! (AddSubjectTagPrefixSettings) , Self :: MimeRejectSettings => stringify ! (MimeRejectSettings) , Self :: ArchivedAtLinkSettings => stringify ! (ArchivedAtLinkSettings) }) } }# [derive (Clone , Copy , Debug)] pub struct MessageFilterSettingNameValueParser ; impl MessageFilterSettingNameValueParser { pub fn new () -> Self { Self } } impl TypedValueParser for MessageFilterSettingNameValueParser { type Value = MessageFilterSettingName ; fn parse_ref (& self , cmd : & clap :: Command , arg : Option < & clap :: Arg > , value : & std :: ffi :: OsStr ,) -> std :: result :: Result < Self :: Value , clap :: Error > { TypedValueParser :: parse (self , cmd , arg , value . to_owned ()) } fn parse (& self , cmd : & clap :: Command , _arg : Option < & clap :: Arg > , value : std :: ffi :: OsString ,) -> std :: result :: Result < Self :: Value , clap :: Error > { use std :: str :: FromStr ; use clap :: error :: ErrorKind ; if value . is_empty () { return Err (cmd . clone () . error (ErrorKind :: DisplayHelpOnMissingArgumentOrSubcommand , "Message filter setting name value required" ,)) ; } Self :: Value :: from_str (value . to_str () . ok_or_else (|| { cmd . clone () . error (ErrorKind :: InvalidValue , "Message filter setting name value is not an UTF-8 string" ,) }) ?) . map_err (| err | cmd . clone () . error (ErrorKind :: InvalidValue , err)) } fn possible_values (& self) -> Option < Box < dyn Iterator < Item = clap :: builder :: PossibleValue >> > { Some (Box :: new (["AddSubjectTagPrefixSettings" , "MimeRejectSettings" , "ArchivedAtLinkSettings"] . iter () . map (clap :: builder :: PossibleValue :: new) ,)) } } impl Default for MessageFilterSettingNameValueParser { fn default () -> Self { Self :: new () } }
8 changes: 7 additions & 1 deletion mailpot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ description = "mailing list manager"
repository = "https://github.com/meli/mailpot"
keywords = ["mail", "mailing-lists"]
categories = ["email"]
build = "build/mod.rs"

[lib]
doc-scrape-examples = true
Expand All @@ -24,7 +25,7 @@ minijinja = { version = "0.31.0", features = ["source", ] }
percent-encoding = { version = "^2.1" }
rusqlite = { version = "^0.30", features = ["bundled", "functions", "trace", "hooks", "serde_json", "array", "chrono", "unlock_notify"] }
serde = { version = "^1", features = ["derive", ] }
serde_json = "^1"
serde_json = { version = "^1" }
thiserror = { version = "1.0.48", default-features = false }
toml = { version = "^0.8.14" }
xdg = "2.4.1"
Expand All @@ -34,3 +35,8 @@ mailpot-tests = { version = "^0.1", path = "../mailpot-tests" }
reqwest = { version = "0.11", default-features = false, features = ["json", "blocking"] }
stderrlog = { version = "^0.6" }
tempfile = { version = "3.9" }

[build-dependencies]
jsonschema = { version = "0.17", default-features = false }
quote = { version = "1" }
serde_json = { version = "^1" }
2 changes: 0 additions & 2 deletions mailpot/build/make_migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use std::{fs::read_dir, io::Write, path::Path};

/// Scans migrations directory for file entries, and creates a rust file with an array containing
/// the migration slices.
///
Expand Down
Loading

0 comments on commit f2163dd

Please sign in to comment.