This introduces a new configuration parameter `mailto-user`. A user's email address will be looked up in the product-specific user database.
Signed-off-by: Lukas Wagner <l.wag...@proxmox.com> --- proxmox-notify/src/api/sendmail.rs | 32 ++++++++++++++++--- proxmox-notify/src/context.rs | 4 ++- proxmox-notify/src/endpoints/sendmail.rs | 40 +++++++++++++++++++++--- proxmox-notify/src/schema.rs | 6 ++++ 4 files changed, 73 insertions(+), 9 deletions(-) diff --git a/proxmox-notify/src/api/sendmail.rs b/proxmox-notify/src/api/sendmail.rs index 6b0323e3..070ed6e7 100644 --- a/proxmox-notify/src/api/sendmail.rs +++ b/proxmox-notify/src/api/sendmail.rs @@ -45,6 +45,13 @@ pub fn add_endpoint(config: &mut Config, endpoint: &SendmailConfig) -> Result<() super::filter::get_filter(config, filter)?; } + if endpoint.mailto.is_none() && endpoint.mailto_user.is_none() { + return Err(ApiError::bad_request( + "must at least provide one recipient, either in mailto or in mailto-user", + None, + )); + } + config .config .set_data(&endpoint.name, SENDMAIL_TYPENAME, endpoint) @@ -81,12 +88,18 @@ pub fn update_endpoint( DeleteableSendmailProperty::Author => endpoint.author = None, DeleteableSendmailProperty::Comment => endpoint.comment = None, DeleteableSendmailProperty::Filter => endpoint.filter = None, + DeleteableSendmailProperty::Mailto => endpoint.mailto = None, + DeleteableSendmailProperty::MailtoUser => endpoint.mailto_user = None, } } } if let Some(mailto) = &updater.mailto { - endpoint.mailto = mailto.iter().map(String::from).collect(); + endpoint.mailto = Some(mailto.iter().map(String::from).collect()); + } + + if let Some(mailto_user) = &updater.mailto_user { + endpoint.mailto_user = Some(mailto_user.iter().map(String::from).collect()); } if let Some(from_address) = &updater.from_address { @@ -106,6 +119,13 @@ pub fn update_endpoint( endpoint.filter = Some(filter.into()); } + if endpoint.mailto.is_none() && endpoint.mailto_user.is_none() { + return Err(ApiError::bad_request( + "must at least provide one recipient, either in mailto or in mailto-user", + None, + )); + } + config .config .set_data(name, SENDMAIL_TYPENAME, &endpoint) @@ -143,7 +163,8 @@ pub mod tests { config, &SendmailConfig { name: name.into(), - mailto: vec!["us...@example.com".into()], + mailto: Some(vec!["us...@example.com".into()]), + mailto_user: None, from_address: Some("f...@example.com".into()), author: Some("root".into()), comment: Some("Comment".into()), @@ -187,6 +208,7 @@ pub mod tests { "sendmail-endpoint", &SendmailConfigUpdater { mailto: Some(vec!["us...@example.com".into(), "us...@example.com".into()]), + mailto_user: None, from_address: Some("r...@example.com".into()), author: Some("newauthor".into()), comment: Some("new comment".into()), @@ -212,6 +234,7 @@ pub mod tests { "sendmail-endpoint", &SendmailConfigUpdater { mailto: Some(vec!["us...@example.com".into(), "us...@example.com".into()]), + mailto_user: Some(vec!["root@pam".into()]), from_address: Some("r...@example.com".into()), author: Some("newauthor".into()), comment: Some("new comment".into()), @@ -225,11 +248,12 @@ pub mod tests { assert_eq!( endpoint.mailto, - vec![ + Some(vec![ "us...@example.com".to_string(), "us...@example.com".to_string() - ] + ]) ); + assert_eq!(endpoint.mailto_user, Some(vec!["root@pam".to_string(),])); assert_eq!(endpoint.from_address, Some("r...@example.com".to_string())); assert_eq!(endpoint.author, Some("newauthor".to_string())); assert_eq!(endpoint.comment, Some("new comment".to_string())); diff --git a/proxmox-notify/src/context.rs b/proxmox-notify/src/context.rs index 55c0eda1..25be949a 100644 --- a/proxmox-notify/src/context.rs +++ b/proxmox-notify/src/context.rs @@ -1,6 +1,8 @@ use std::sync::Mutex; -pub trait Context: Send + Sync {} +pub trait Context: Send + Sync { + fn lookup_email_for_user(&self, user: &str) -> Option<String>; +} static CONTEXT: Mutex<Option<&'static dyn Context>> = Mutex::new(None); diff --git a/proxmox-notify/src/endpoints/sendmail.rs b/proxmox-notify/src/endpoints/sendmail.rs index 9d06e7c4..c2b44b2d 100644 --- a/proxmox-notify/src/endpoints/sendmail.rs +++ b/proxmox-notify/src/endpoints/sendmail.rs @@ -1,6 +1,8 @@ +use crate::context::context; use crate::renderer::TemplateRenderer; -use crate::schema::{COMMENT_SCHEMA, EMAIL_SCHEMA, ENTITY_NAME_SCHEMA}; +use crate::schema::{COMMENT_SCHEMA, EMAIL_SCHEMA, ENTITY_NAME_SCHEMA, USER_SCHEMA}; use crate::{renderer, Endpoint, Error, Notification}; +use std::collections::HashSet; use proxmox_schema::{api, Updater}; use serde::{Deserialize, Serialize}; @@ -17,6 +19,14 @@ pub(crate) const SENDMAIL_TYPENAME: &str = "sendmail"; items: { schema: EMAIL_SCHEMA, }, + optional: true, + }, + "mailto-user": { + type: Array, + items: { + schema: USER_SCHEMA, + }, + optional: true, }, comment: { optional: true, @@ -36,7 +46,11 @@ pub struct SendmailConfig { #[updater(skip)] pub name: String, /// Mail recipients - pub mailto: Vec<String>, + #[serde(skip_serializing_if = "Option::is_none")] + pub mailto: Option<Vec<String>>, + /// Mail recipients + #[serde(skip_serializing_if = "Option::is_none")] + pub mailto_user: Option<Vec<String>>, /// `From` address for the mail #[serde(skip_serializing_if = "Option::is_none")] pub from_address: Option<String>, @@ -58,6 +72,8 @@ pub enum DeleteableSendmailProperty { Author, Comment, Filter, + Mailto, + MailtoUser, } /// A sendmail notification endpoint. @@ -67,7 +83,21 @@ pub struct SendmailEndpoint { impl Endpoint for SendmailEndpoint { fn send(&self, notification: &Notification) -> Result<(), Error> { - let recipients: Vec<&str> = self.config.mailto.iter().map(String::as_str).collect(); + let mut recipients = HashSet::new(); + + if let Some(mailto_addrs) = self.config.mailto.as_ref() { + for addr in mailto_addrs { + recipients.insert(addr.clone()); + } + } + + if let Some(users) = self.config.mailto_user.as_ref() { + for user in users { + if let Some(addr) = context().lookup_email_for_user(user) { + recipients.insert(addr); + } + } + } let properties = notification.properties.as_ref(); @@ -85,8 +115,10 @@ impl Endpoint for SendmailEndpoint { // "Proxmox Backup Server" if it is not set. let author = self.config.author.as_deref().or(Some("")); + let recipients_str: Vec<&str> = recipients.iter().map(String::as_str).collect(); + proxmox_sys::email::sendmail( - &recipients, + &recipients_str, &subject, Some(&text_part), Some(&html_part), diff --git a/proxmox-notify/src/schema.rs b/proxmox-notify/src/schema.rs index 68f11959..006e918b 100644 --- a/proxmox-notify/src/schema.rs +++ b/proxmox-notify/src/schema.rs @@ -26,6 +26,12 @@ pub const EMAIL_SCHEMA: Schema = StringSchema::new("E-Mail Address.") .max_length(64) .schema(); +pub const USER_SCHEMA: Schema = StringSchema::new("User ID including realm, e.g. root@pam.") + .format(&SINGLE_LINE_COMMENT_FORMAT) + .min_length(2) + .max_length(64) + .schema(); + pub const PROXMOX_SAFE_ID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX); -- 2.39.2 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel