From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <l.wagner@proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by lists.proxmox.com (Postfix) with ESMTPS id 78D5BEECD
 for <pve-devel@lists.proxmox.com>; Thu, 20 Jul 2023 16:33:32 +0200 (CEST)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id 97B95149C6
 for <pve-devel@lists.proxmox.com>; Thu, 20 Jul 2023 16:33:11 +0200 (CEST)
Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com
 [94.136.29.106])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by firstgate.proxmox.com (Proxmox) with ESMTPS
 for <pve-devel@lists.proxmox.com>; Thu, 20 Jul 2023 16:33:08 +0200 (CEST)
Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1])
 by proxmox-new.maurer-it.com (Proxmox) with ESMTP id E07DC41FBC
 for <pve-devel@lists.proxmox.com>; Thu, 20 Jul 2023 16:33:07 +0200 (CEST)
From: Lukas Wagner <l.wagner@proxmox.com>
To: pve-devel@lists.proxmox.com
Date: Thu, 20 Jul 2023 16:31:48 +0200
Message-Id: <20230720143236.652292-22-l.wagner@proxmox.com>
X-Mailer: git-send-email 2.39.2
In-Reply-To: <20230720143236.652292-1-l.wagner@proxmox.com>
References: <20230720143236.652292-1-l.wagner@proxmox.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results:  0
 AWL -0.088 Adjusted score from AWL reputation of From: address
 BAYES_00                 -1.9 Bayes spam probability is 0 to 1%
 DMARC_MISSING             0.1 Missing DMARC policy
 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
 T_SCC_BODY_TEXT_LINE    -0.01 -
Subject: [pve-devel] [PATCH v4 proxmox 21/69] notify: api: allow to query
 entities referenced by filter/target
X-BeenThere: pve-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/>
List-Post: <mailto:pve-devel@lists.proxmox.com>
List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, 
 <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Thu, 20 Jul 2023 14:33:32 -0000

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---

Notes:
    Changes since v3:
      - Removed unneeded drain() call

 proxmox-notify/src/api/common.rs |  11 +++
 proxmox-notify/src/api/mod.rs    | 125 +++++++++++++++++++++++++++++++
 2 files changed, 136 insertions(+)

diff --git a/proxmox-notify/src/api/common.rs b/proxmox-notify/src/api/common.rs
index 518caa8f..48761fbb 100644
--- a/proxmox-notify/src/api/common.rs
+++ b/proxmox-notify/src/api/common.rs
@@ -42,3 +42,14 @@ pub fn test_target(config: &Config, endpoint: &str) -> Result<(), ApiError> {
 
     Ok(())
 }
+
+/// Return all entities (targets, groups, filters) that are linked to the entity.
+/// For instance, if a group 'grp1' contains the targets 'a', 'b' and 'c',
+/// where grp1 has 'filter1' and 'a' has 'filter2' as filters, then
+/// the result for 'grp1' would be [grp1, a, b, c, filter1, filter2].
+/// The result will always contain the entity that was passed as a parameter.
+/// If the entity does not exist, the result will only contain the entity.
+pub fn get_referenced_entities(config: &Config, entity: &str) -> Result<Vec<String>, ApiError> {
+    let entities = super::get_referenced_entities(config, entity);
+    Ok(Vec::from_iter(entities.into_iter()))
+}
diff --git a/proxmox-notify/src/api/mod.rs b/proxmox-notify/src/api/mod.rs
index 12811baf..1d9aaca7 100644
--- a/proxmox-notify/src/api/mod.rs
+++ b/proxmox-notify/src/api/mod.rs
@@ -1,3 +1,4 @@
+use std::collections::HashSet;
 use std::error::Error as StdError;
 use std::fmt::Display;
 
@@ -101,6 +102,48 @@ fn endpoint_exists(config: &Config, name: &str) -> bool {
     exists
 }
 
+fn get_referenced_entities(config: &Config, entity: &str) -> HashSet<String> {
+    let mut to_expand = HashSet::new();
+    let mut expanded = HashSet::new();
+    to_expand.insert(entity.to_string());
+
+    let expand = |entities: &HashSet<String>| -> HashSet<String> {
+        let mut new = HashSet::new();
+
+        for entity in entities {
+            if let Ok(group) = group::get_group(config, entity) {
+                for target in group.endpoint {
+                    new.insert(target.clone());
+                }
+            }
+
+            #[cfg(feature = "sendmail")]
+            if let Ok(target) = sendmail::get_endpoint(config, entity) {
+                if let Some(filter) = target.filter {
+                    new.insert(filter.clone());
+                }
+            }
+
+            #[cfg(feature = "gotify")]
+            if let Ok(target) = gotify::get_endpoint(config, entity) {
+                if let Some(filter) = target.filter {
+                    new.insert(filter.clone());
+                }
+            }
+        }
+
+        new
+    };
+
+    while !to_expand.is_empty() {
+        let new = expand(&to_expand);
+        expanded.extend(to_expand);
+        to_expand = new;
+    }
+
+    expanded
+}
+
 #[cfg(test)]
 mod test_helpers {
     use crate::Config;
@@ -109,3 +152,85 @@ mod test_helpers {
         Config::new("", "").unwrap()
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::endpoints::gotify::{GotifyConfig, GotifyPrivateConfig};
+    use crate::endpoints::sendmail::SendmailConfig;
+    use crate::filter::FilterConfig;
+    use crate::group::GroupConfig;
+
+    #[test]
+    fn test_get_referenced_entities() {
+        let mut config = super::test_helpers::empty_config();
+
+        filter::add_filter(
+            &mut config,
+            &FilterConfig {
+                name: "filter".to_string(),
+                ..Default::default()
+            },
+        )
+        .unwrap();
+
+        sendmail::add_endpoint(
+            &mut config,
+            &SendmailConfig {
+                name: "sendmail".to_string(),
+                mailto: Some(vec!["foo@example.com".to_string()]),
+                filter: Some("filter".to_string()),
+                ..Default::default()
+            },
+        )
+        .unwrap();
+
+        gotify::add_endpoint(
+            &mut config,
+            &GotifyConfig {
+                name: "gotify".to_string(),
+                server: "localhost".to_string(),
+                filter: Some("filter".to_string()),
+                ..Default::default()
+            },
+            &GotifyPrivateConfig {
+                name: "gotify".to_string(),
+                token: "foo".to_string(),
+            },
+        )
+        .unwrap();
+
+        group::add_group(
+            &mut config,
+            &GroupConfig {
+                name: "group".to_string(),
+                endpoint: vec!["gotify".to_string(), "sendmail".to_string()],
+                filter: Some("filter".to_string()),
+                ..Default::default()
+            },
+        )
+        .unwrap();
+
+        assert_eq!(
+            get_referenced_entities(&config, "filter"),
+            HashSet::from(["filter".to_string()])
+        );
+        assert_eq!(
+            get_referenced_entities(&config, "sendmail"),
+            HashSet::from(["filter".to_string(), "sendmail".to_string()])
+        );
+        assert_eq!(
+            get_referenced_entities(&config, "gotify"),
+            HashSet::from(["filter".to_string(), "gotify".to_string()])
+        );
+        assert_eq!(
+            get_referenced_entities(&config, "group"),
+            HashSet::from([
+                "filter".to_string(),
+                "gotify".to_string(),
+                "sendmail".to_string(),
+                "group".to_string()
+            ])
+        );
+    }
+}
-- 
2.39.2