public inbox for pdm-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login
@ 2025-12-01 13:52 Dominik Csapak
  2025-12-01 13:52 ` [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
                   ` (10 more replies)
  0 siblings, 11 replies; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:52 UTC (permalink / raw)
  To: pdm-devel

This adds subscription checks + popup for
* login
* 'refresh all' for remote update panel
* 'refresh' for single node update panels

this series contains the RFC patches from fabian too
(so it can be more easily applied)

changes from v1:
* include fabians patches, and rebase on them
* don't do the subscription logic in the ui, but in the backend
  (simplifies the ui changes)
* slightly reordered the patches

proxmox-yew-comp:

Dominik Csapak (2):
  subscription: refactor api subscription check for showing the alert
  apt package manager: add optional subscription check on 'Refresh'
    button

 src/apt_package_manager.rs | 63 ++++++++++++++++++++++++++++++++++++--
 src/apt_repositories.rs    |  8 ++---
 src/lib.rs                 |  2 +-
 src/subscription_alert.rs  | 13 ++++++++
 4 files changed, 76 insertions(+), 10 deletions(-)


proxmox-datacenter-manager:

Dominik Csapak (6):
  server: api: subscription: fix permission check
  server: api: pve/pbs: node: add subscription api call
  ui: pve/pbs: updates: add subscription_url
  ui: login: enable subscription check
  ui: refactor check_subscription into lib
  ui: remote updates: add subscription check on 'Refresh all'

Fabian Grünbichler (3):
  subscription: add serverid field to node subscription info
  api types: add new SubscriptionStatistics
  api: add subscription endpoints

 lib/pdm-api-types/src/subscription.rs |  17 +++
 server/src/api/nodes/mod.rs           |   2 +
 server/src/api/nodes/subscription.rs  | 194 ++++++++++++++++++++++++++
 server/src/api/pbs/node.rs            |  39 +++++-
 server/src/api/pve/node.rs            |  27 ++++
 server/src/api/resources.rs           |   6 +-
 ui/src/lib.rs                         |   9 ++
 ui/src/main.rs                        |  40 ++----
 ui/src/pbs/node/mod.rs                |   2 +
 ui/src/pve/node/mod.rs                |   2 +
 ui/src/remotes/updates.rs             |  48 ++++++-
 11 files changed, 351 insertions(+), 35 deletions(-)
 create mode 100644 server/src/api/nodes/subscription.rs


Summary over all repositories:
  15 files changed, 427 insertions(+), 45 deletions(-)

-- 
Generated by git-murpp 0.8.1


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
@ 2025-12-01 13:52 ` Dominik Csapak
  2025-12-01 19:02   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH yew-comp v2 2/2] apt package manager: add optional subscription check on 'Refresh' button Dominik Csapak
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:52 UTC (permalink / raw)
  To: pdm-devel

so we can reuse that

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/apt_repositories.rs   |  8 ++------
 src/lib.rs                |  2 +-
 src/subscription_alert.rs | 13 +++++++++++++
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/src/apt_repositories.rs b/src/apt_repositories.rs
index ae582a6..83463c9 100644
--- a/src/apt_repositories.rs
+++ b/src/apt_repositories.rs
@@ -19,6 +19,7 @@ use pwt::widget::data_table::{
 };
 use pwt::widget::{Button, Column, Container, Fa, Row, Toolbar, Tooltip};
 
+use crate::subscription_alert::subscription_is_active;
 use crate::{
     EditWindow, ExistingProduct, LoadableComponent, LoadableComponentContext,
     LoadableComponentMaster, ProjectInfo, SubscriptionAlert,
@@ -694,12 +695,7 @@ fn standard_repo_info(
 
 impl ProxmoxAptRepositories {
     fn active_subscription(&self) -> bool {
-        match &self.subscription_status {
-            Some(Ok(data)) => {
-                data["status"].as_str().map(|s| s.to_lowercase()).as_deref() == Some("active")
-            }
-            _ => false,
-        }
+        subscription_is_active(&self.subscription_status)
     }
 
     fn create_show_subscription_dialog(
diff --git a/src/lib.rs b/src/lib.rs
index 1fefed8..8e43d35 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -181,7 +181,7 @@ mod submit_value_callback;
 pub use submit_value_callback::{IntoSubmitValueCallback, SubmitValueCallback};
 
 mod subscription_alert;
-pub use subscription_alert::{ProxmoxSubscriptionAlert, SubscriptionAlert};
+pub use subscription_alert::{subscription_is_active, ProxmoxSubscriptionAlert, SubscriptionAlert};
 
 mod subscription_panel;
 pub use subscription_panel::{ProxmoxSubscriptionPanel, SubscriptionPanel};
diff --git a/src/subscription_alert.rs b/src/subscription_alert.rs
index 2dca3c4..7734123 100644
--- a/src/subscription_alert.rs
+++ b/src/subscription_alert.rs
@@ -1,5 +1,8 @@
 use std::rc::Rc;
 
+use anyhow::Error;
+use serde_json::Value;
+
 use yew::html::{IntoEventCallback, IntoPropValue};
 use yew::virtual_dom::{VComp, VNode};
 
@@ -63,3 +66,13 @@ impl From<SubscriptionAlert> for VNode {
         VNode::from(comp)
     }
 }
+
+/// Check if the result of the subscription check returned an active subscription
+pub fn subscription_is_active(result: &Option<Result<Value, Error>>) -> bool {
+    match result {
+        Some(Ok(data)) => {
+            data["status"].as_str().map(|s| s.to_lowercase()).as_deref() == Some("active")
+        }
+        _ => false,
+    }
+}
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH yew-comp v2 2/2] apt package manager: add optional subscription check on 'Refresh' button
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
  2025-12-01 13:52 ` [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info Dominik Csapak
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

but only if the 'subscription_url' is set on the component.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/apt_package_manager.rs | 63 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 3 deletions(-)

diff --git a/src/apt_package_manager.rs b/src/apt_package_manager.rs
index d01f275..78e82a0 100644
--- a/src/apt_package_manager.rs
+++ b/src/apt_package_manager.rs
@@ -5,6 +5,7 @@ use std::pin::Pin;
 use std::rc::Rc;
 
 use anyhow::Error;
+use serde_json::Value;
 
 use yew::html::IntoEventCallback;
 use yew::html::IntoPropValue;
@@ -17,8 +18,11 @@ use pwt::widget::data_table::{
     DataTable, DataTableCellRenderArgs, DataTableColumn, DataTableHeader, DataTableHeaderGroup,
 };
 use pwt::widget::{Button, Container, Toolbar, Tooltip};
+use pwt::AsyncPool;
 
 use crate::percent_encoding::percent_encode_component;
+use crate::subscription_alert::subscription_is_active;
+use crate::SubscriptionAlert;
 use crate::{
     DataViewWindow, LoadableComponent, LoadableComponentContext, LoadableComponentMaster, XTermJs,
 };
@@ -56,6 +60,11 @@ pub struct AptPackageManager {
     #[prop_or_default]
     #[builder_cb(IntoEventCallback, into_event_callback, ())]
     pub on_upgrade: Option<Callback<()>>,
+
+    #[prop_or_default]
+    #[builder(IntoPropValue, into_prop_value)]
+    /// The base url for the subscription check
+    pub subscription_url: Option<AttrValue>,
 }
 
 impl Default for AptPackageManager {
@@ -142,12 +151,14 @@ fn update_list_to_tree(updates: &[APTUpdateInfo]) -> SlabTree<TreeEntry> {
 #[derive(Clone, PartialEq)]
 pub enum ViewState {
     ShowChangelog(String),
+    ShowSubscriptionPopup,
 }
 
 pub struct ProxmoxAptPackageManager {
     tree_store: TreeStore<TreeEntry>,
     selection: Selection,
     columns: Rc<Vec<DataTableHeader<TreeEntry>>>,
+    async_pool: AsyncPool,
 }
 
 impl LoadableComponent for ProxmoxAptPackageManager {
@@ -164,9 +175,33 @@ impl LoadableComponent for ProxmoxAptPackageManager {
             tree_store,
             selection,
             columns,
+            async_pool: AsyncPool::new(),
         }
     }
 
+    fn update(&mut self, ctx: &LoadableComponentContext<Self>, _msg: Self::Message) -> bool {
+        let link = ctx.link().clone();
+        let props = ctx.props();
+        let url = props
+            .clone()
+            .subscription_url
+            .unwrap_or("/nodes/localhost/subscription".into());
+        let task_base_url = props.task_base_url.clone();
+        let command = format!("{}/update", props.base_url);
+        self.async_pool.spawn(async move {
+            let data = crate::http_get::<Value>(url.as_str(), None).await;
+            let is_active = subscription_is_active(&Some(data));
+
+            if is_active {
+                link.task_base_url(task_base_url);
+                link.start_task(&command, None, false);
+            } else {
+                link.change_view(Some(ViewState::ShowSubscriptionPopup));
+            }
+        });
+        true
+    }
+
     fn load(
         &self,
         ctx: &LoadableComponentContext<Self>,
@@ -211,13 +246,20 @@ impl LoadableComponent for ProxmoxAptPackageManager {
             .class("pwt-w-100")
             .class("pwt-overflow-hidden")
             .class("pwt-border-bottom")
-            .with_child(Button::new(tr!("Refresh")).onclick({
+            .with_child(Button::new(tr!("Refresh")).on_activate({
                 let link = ctx.link();
-
+                let sub_check = props.subscription_url.is_some();
                 link.task_base_url(props.task_base_url.clone());
 
                 let command = format!("{}/update", props.base_url);
-                move |_| link.start_task(&command, None, false)
+
+                move |_| {
+                    if sub_check {
+                        link.send_message(());
+                    } else {
+                        link.start_task(&command, None, false);
+                    }
+                }
             }))
             .with_child(
                 Button::new(tr!("Upgrade"))
@@ -263,6 +305,21 @@ impl LoadableComponent for ProxmoxAptPackageManager {
             ViewState::ShowChangelog(package) => {
                 Some(self.create_show_changelog_dialog(ctx, package))
             }
+            ViewState::ShowSubscriptionPopup => {
+                let link = ctx.link().clone();
+                let props = ctx.props();
+                let task_base_url = props.task_base_url.clone();
+                let command = format!("{}/update", props.base_url);
+                Some(
+                    SubscriptionAlert::new("notfound")
+                        .on_close(move |_| {
+                            link.change_view(None);
+                            link.task_base_url(task_base_url.clone());
+                            link.start_task(&command, None, false);
+                        })
+                        .into(),
+                )
+            }
         }
     }
 
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
  2025-12-01 13:52 ` [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
  2025-12-01 13:53 ` [pdm-devel] [PATCH yew-comp v2 2/2] apt package manager: add optional subscription check on 'Refresh' button Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics Dominik Csapak
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

From: Fabian Grünbichler <f.gruenbichler@proxmox.com>

needed to re-use it internally for enterprise repository access.

intentionally not serialized to avoid leaking it.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
 lib/pdm-api-types/src/subscription.rs | 4 ++++
 server/src/api/resources.rs           | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/lib/pdm-api-types/src/subscription.rs b/lib/pdm-api-types/src/subscription.rs
index 35910bc7..64167cb8 100644
--- a/lib/pdm-api-types/src/subscription.rs
+++ b/lib/pdm-api-types/src/subscription.rs
@@ -110,6 +110,10 @@ pub struct NodeSubscriptionInfo {
 
     /// The subscription level of the node
     pub level: SubscriptionLevel,
+
+    /// Serverid of the node, if accessible
+    #[serde(skip_serializing)]
+    pub serverid: Option<String>,
 }
 
 #[api(
diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index 55056e1c..4beaa542 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -891,6 +891,7 @@ async fn fetch_remote_subscription_info(
                             status,
                             sockets: info.sockets,
                             key: info.key,
+                            serverid: info.serverid,
                             level: info
                                 .level
                                 .and_then(|level| level.parse().ok())
@@ -910,6 +911,7 @@ async fn fetch_remote_subscription_info(
                     sockets: None,
                     key: info.key,
                     level,
+                    serverid: info.serverid,
                 }
             });
 
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (2 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 3/9] api: add subscription endpoints Dominik Csapak
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

From: Fabian Grünbichler <f.gruenbichler@proxmox.com>

this is a different view for the global subscription status - instead of
looking at the lowest level per remote, count all nodes.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
 lib/pdm-api-types/src/subscription.rs | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/lib/pdm-api-types/src/subscription.rs b/lib/pdm-api-types/src/subscription.rs
index 64167cb8..d38611e3 100644
--- a/lib/pdm-api-types/src/subscription.rs
+++ b/lib/pdm-api-types/src/subscription.rs
@@ -143,3 +143,16 @@ pub struct RemoteSubscriptions {
 
     pub state: RemoteSubscriptionState,
 }
+
+#[api]
+#[derive(Default, Serialize, Deserialize, Clone, PartialEq)]
+#[serde(rename_all = "kebab-case")]
+/// Lists the subscription level per node for the remote
+pub struct SubscriptionStatistics {
+    /// Total number of nodes across all remotes
+    pub total_nodes: usize,
+    /// Total number of active subscriptions across all remotes
+    pub active_subscriptions: usize,
+    /// Total number of community level subscriptions across all remotes
+    pub community: usize,
+}
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 3/9] api: add subscription endpoints
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (3 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check Dominik Csapak
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

From: Fabian Grünbichler <f.gruenbichler@proxmox.com>

for the PDM system itself, by proxy of how many of the remote nodes have valid
subscriptions above a certain level.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
 server/src/api/nodes/mod.rs          |   2 +
 server/src/api/nodes/subscription.rs | 194 +++++++++++++++++++++++++++
 server/src/api/resources.rs          |   2 +-
 3 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 server/src/api/nodes/subscription.rs

diff --git a/server/src/api/nodes/mod.rs b/server/src/api/nodes/mod.rs
index a0fe14ab..3a795d65 100644
--- a/server/src/api/nodes/mod.rs
+++ b/server/src/api/nodes/mod.rs
@@ -11,6 +11,7 @@ pub mod journal;
 pub mod network;
 pub mod rrddata;
 pub mod status;
+pub mod subscription;
 pub mod syslog;
 pub mod tasks;
 pub mod termproxy;
@@ -45,6 +46,7 @@ pub const SUBDIRS: SubdirMap = &sorted!([
     ("journal", &journal::ROUTER),
     ("network", &network::ROUTER),
     ("rrdata", &rrddata::ROUTER),
+    ("subscription", &subscription::ROUTER),
     ("status", &status::ROUTER),
     ("syslog", &syslog::ROUTER),
     ("tasks", &tasks::ROUTER),
diff --git a/server/src/api/nodes/subscription.rs b/server/src/api/nodes/subscription.rs
new file mode 100644
index 00000000..d9b44d59
--- /dev/null
+++ b/server/src/api/nodes/subscription.rs
@@ -0,0 +1,194 @@
+use std::collections::HashMap;
+
+use anyhow::{bail, Error};
+
+use proxmox_router::{Permission, Router};
+use proxmox_schema::api;
+use proxmox_schema::api_types::NODE_SCHEMA;
+use proxmox_subscription::files::update_apt_auth;
+use proxmox_subscription::{SubscriptionInfo, SubscriptionStatus};
+use proxmox_sys::fs::CreateOptions;
+
+use pdm_api_types::remotes::RemoteType;
+use pdm_api_types::subscription::{
+    NodeSubscriptionInfo, SubscriptionLevel, SubscriptionStatistics,
+};
+use pdm_api_types::PRIV_SYS_MODIFY;
+
+use crate::api::resources::get_subscription_info_for_remote;
+
+const PRODUCT_URL: &str = "https://www.proxmox.com/en/proxmox-datacenter-manager/pricing";
+const APT_AUTH_FN: &str = "/etc/apt/auth.conf.d/pdm.conf";
+const APT_AUTH_URL: &str = "enterprise.proxmox.com/debian/pdm";
+
+// minimum ratio of nodes with active subscriptions
+const SUBSCRIPTION_THRESHOLD: f64 = 0.9;
+// max ratio of nodes with community subscriptions, among nodes with subscriptions
+const COMMUNITY_THRESHOLD: f64 = 0.4;
+
+fn apt_auth_file_opts() -> CreateOptions {
+    let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
+    CreateOptions::new().perm(mode).owner(nix::unistd::ROOT)
+}
+
+async fn get_all_subscription_infos(
+) -> Result<HashMap<String, (RemoteType, HashMap<String, Option<NodeSubscriptionInfo>>)>, Error> {
+    let (remotes_config, _digest) = pdm_config::remotes::config()?;
+
+    let mut subscription_info = HashMap::new();
+    for (remote_name, remote) in remotes_config.iter() {
+        match get_subscription_info_for_remote(remote, 24 * 60 * 60).await {
+            Ok(info) => {
+                subscription_info.insert(remote_name.to_string(), (remote.ty, info));
+            }
+            Err(err) => {
+                log::debug!("Failed to get subscription info for remote {remote_name} - {err}");
+                subscription_info.insert(remote_name.to_string(), (remote.ty, HashMap::new()));
+            }
+        }
+    }
+    Ok(subscription_info)
+}
+
+fn count_subscriptions(
+    subscription_infos: &HashMap<
+        String,
+        (RemoteType, HashMap<String, Option<NodeSubscriptionInfo>>),
+    >,
+) -> SubscriptionStatistics {
+    let mut stats = SubscriptionStatistics::default();
+    for (_remote, (_remote_type, remote_infos)) in subscription_infos.iter() {
+        if remote_infos.is_empty() {
+            // count remotes without info as at least one node
+            stats.total_nodes += 1;
+            continue;
+        }
+        for (_node, node_info) in remote_infos.iter() {
+            stats.total_nodes += 1;
+            if let Some(info) = node_info {
+                if info.status == SubscriptionStatus::Active {
+                    stats.active_subscriptions += 1;
+                    if info.level == SubscriptionLevel::Community {
+                        stats.community += 1;
+                    }
+                }
+            }
+        }
+    }
+    stats
+}
+
+fn check_counts(stats: SubscriptionStatistics) -> Result<(), Error> {
+    let subscribed_ratio = stats.active_subscriptions as f64 / stats.total_nodes as f64;
+    let community_ratio = stats.community as f64 / stats.active_subscriptions as f64;
+
+    if subscribed_ratio > SUBSCRIPTION_THRESHOLD {
+        if community_ratio < COMMUNITY_THRESHOLD {
+            return Ok(());
+        } else {
+            bail!("Too many remote nodes with community level subscription!");
+        }
+    } else {
+        bail!("Too many remote nodes without active subscription!");
+    }
+}
+
+#[api(
+    access: { permission: &Permission::Anybody, },
+    input: {
+        properties: {
+            node: {
+                schema: NODE_SCHEMA,
+            },
+        },
+    },
+    returns: {
+        type: SubscriptionInfo,
+    }
+)]
+/// Return subscription status
+pub async fn get_subscription() -> Result<SubscriptionInfo, Error> {
+    let infos = get_all_subscription_infos().await?;
+
+    let stats = count_subscriptions(&infos);
+
+    if let Err(err) = check_counts(stats) {
+        Ok(SubscriptionInfo {
+            status: SubscriptionStatus::Invalid,
+            message: Some(format!("{err}")),
+            serverid: None,
+            url: Some(PRODUCT_URL.into()),
+            ..Default::default()
+        })
+    } else {
+        Ok(SubscriptionInfo {
+            status: SubscriptionStatus::Active,
+            url: Some(PRODUCT_URL.into()),
+            ..Default::default()
+        })
+    }
+}
+
+#[api(
+    input: {
+        properties: {
+            node: {
+                schema: NODE_SCHEMA,
+            },
+        },
+    },
+    protected: true,
+    access: {
+        permission: &Permission::Privilege(&["system"], PRIV_SYS_MODIFY, false),
+    },
+)]
+/// Update subscription information
+pub async fn check_subscription() -> Result<(), Error> {
+    let infos = get_all_subscription_infos().await?;
+    let stats = count_subscriptions(&infos);
+
+    if let Err(err) = check_counts(stats) {
+        update_apt_auth(APT_AUTH_FN, apt_auth_file_opts(), APT_AUTH_URL, None, None)?;
+        return Err(err);
+    }
+
+    let mut found = false;
+    'outer: for (remote, (remote_type, remote_info)) in infos.iter() {
+        if *remote_type != RemoteType::Pve || *remote_type != RemoteType::Pbs {
+            continue;
+        }
+        for (node, node_info) in remote_info.iter() {
+            if let Some(info) = node_info {
+                if info.status == SubscriptionStatus::Active
+                    && info.level >= SubscriptionLevel::Basic
+                    && info.key.is_some()
+                    && info.serverid.is_some()
+                {
+                    log::info!("Using subscription of node '{node}' of remote '{remote}' for enterprise repository access");
+                    update_apt_auth(
+                        APT_AUTH_FN,
+                        apt_auth_file_opts(),
+                        APT_AUTH_URL,
+                        info.key.clone(),
+                        info.serverid.clone(),
+                    )?;
+                    found = true;
+                    break 'outer;
+                }
+            }
+        }
+    }
+
+    if !found {
+        log::warn!(
+            "No valid Basic+ subscription found for configuring enterprise repository access.."
+        );
+        update_apt_auth(APT_AUTH_FN, apt_auth_file_opts(), APT_AUTH_URL, None, None)?;
+    }
+
+    Ok(())
+}
+
+pub const ROUTER: Router = Router::new()
+    .get(&API_METHOD_GET_SUBSCRIPTION)
+    .post(&API_METHOD_CHECK_SUBSCRIPTION);
diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index 4beaa542..adab021a 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -767,7 +767,7 @@ static SUBSCRIPTION_CACHE: LazyLock<RwLock<HashMap<String, CachedSubscriptionSta
 ///
 /// If recent enough cached data is available, it is returned
 /// instead of calling out to the remote.
-async fn get_subscription_info_for_remote(
+pub async fn get_subscription_info_for_remote(
     remote: &Remote,
     max_age: u64,
 ) -> Result<HashMap<String, Option<NodeSubscriptionInfo>>, Error> {
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (4 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 3/9] api: add subscription endpoints Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call Dominik Csapak
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

we have here a 'check_priv' that should return if the permission check
was successful. So instead of wrongly check for 'is_err', rather check
for 'is_ok'.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 server/src/api/resources.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/server/src/api/resources.rs b/server/src/api/resources.rs
index adab021a..1193c26a 100644
--- a/server/src/api/resources.rs
+++ b/server/src/api/resources.rs
@@ -616,7 +616,7 @@ pub async fn get_subscription_status(
                 PRIV_RESOURCE_AUDIT,
                 false,
             )
-            .is_err()
+            .is_ok()
     };
 
     for (remote_name, remote) in remotes_config {
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (5 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url Dominik Csapak
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

returns the subscription information per node

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 server/src/api/pbs/node.rs | 39 +++++++++++++++++++++++++++++++++++++-
 server/src/api/pve/node.rs | 27 ++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/server/src/api/pbs/node.rs b/server/src/api/pbs/node.rs
index cf8cbea5..aafefc2a 100644
--- a/server/src/api/pbs/node.rs
+++ b/server/src/api/pbs/node.rs
@@ -1,6 +1,17 @@
-use proxmox_router::{list_subdirs_api_method, Router, SubdirMap};
+use anyhow::Error;
+
+use proxmox_router::{list_subdirs_api_method, Permission, Router, SubdirMap};
+use proxmox_schema::api;
 use proxmox_sortable_macro::sortable;
 
+use pdm_api_types::remotes::REMOTE_ID_SCHEMA;
+use pdm_api_types::PRIV_RESOURCE_AUDIT;
+
+use pbs_api_types::NODE_SCHEMA;
+
+use crate::connection;
+use crate::pbs_client::get_remote;
+
 pub const ROUTER: Router = Router::new()
     .get(&list_subdirs_api_method!(SUBDIRS))
     .subdirs(SUBDIRS);
@@ -8,6 +19,10 @@ pub const ROUTER: Router = Router::new()
 #[sortable]
 const SUBDIRS: SubdirMap = &sorted!([
     ("apt", &crate::api::remote_updates::APT_ROUTER),
+    (
+        "subscription",
+        &Router::new().get(&API_METHOD_GET_SUBSCRIPTION)
+    ),
     (
         "termproxy",
         &Router::new().post(&crate::api::remote_shell::API_METHOD_SHELL_TICKET)
@@ -17,3 +32,25 @@ const SUBDIRS: SubdirMap = &sorted!([
         &Router::new().upgrade(&crate::api::remote_shell::API_METHOD_SHELL_WEBSOCKET)
     ),
 ]);
+
+#[api(
+    input: {
+        properties: {
+            remote: { schema: REMOTE_ID_SCHEMA },
+            node: { schema: NODE_SCHEMA }, // not used, always localhost
+        },
+    },
+    access: {
+        permission: &Permission::Privilege(&["resource", "{remote}"], PRIV_RESOURCE_AUDIT, false),
+        description: "The user needs to have at least the `Resource.Audit` privilege on `/resource/{remote}`."
+    },
+    returns: { type: proxmox_subscription::SubscriptionInfo }
+)]
+/// Get subscription for the PBS remote
+async fn get_subscription(remote: String) -> Result<proxmox_subscription::SubscriptionInfo, Error> {
+    let (remotes, _) = pdm_config::remotes::config()?;
+    let remote = get_remote(&remotes, &remote)?;
+    Ok(connection::make_pbs_client(remote)?
+        .get_subscription()
+        .await?)
+}
diff --git a/server/src/api/pve/node.rs b/server/src/api/pve/node.rs
index d8690f63..376234c7 100644
--- a/server/src/api/pve/node.rs
+++ b/server/src/api/pve/node.rs
@@ -29,6 +29,10 @@ const SUBDIRS: SubdirMap = &sorted!([
     ),
     ("storage", &STORAGE_ROUTER),
     ("status", &Router::new().get(&API_METHOD_GET_STATUS)),
+    (
+        "subscription",
+        &Router::new().get(&API_METHOD_GET_SUBSCRIPTION)
+    ),
 ]);
 
 const STORAGE_ROUTER: Router = Router::new()
@@ -153,3 +157,26 @@ async fn get_status(remote: String, node: String) -> Result<pve_api_types::NodeS
     let result = client.node_status(&node).await?;
     Ok(result)
 }
+
+#[api(
+    input: {
+        properties: {
+            remote: { schema: REMOTE_ID_SCHEMA },
+            node: { schema: NODE_SCHEMA },
+        },
+    },
+    access: {
+        permission: &Permission::Privilege(&["resource", "{remote}", "node", "{node}"], PRIV_RESOURCE_AUDIT, false),
+    },
+    returns: { type: pve_api_types::NodeStatus },
+)]
+/// Get subscription for the node
+async fn get_subscription(
+    remote: String,
+    node: String,
+) -> Result<pve_api_types::NodeSubscriptionInfo, Error> {
+    let (remotes, _) = pdm_config::remotes::config()?;
+    let client = super::connect_to_remote(&remotes, &remote)?;
+    let result = client.get_subscription(&node).await?;
+    Ok(result)
+}
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (6 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check Dominik Csapak
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

so the 'Refresh' button does a subscription check.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 ui/src/pbs/node/mod.rs | 2 ++
 ui/src/pve/node/mod.rs | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/ui/src/pbs/node/mod.rs b/ui/src/pbs/node/mod.rs
index 2033bb14..19ddce72 100644
--- a/ui/src/pbs/node/mod.rs
+++ b/ui/src/pbs/node/mod.rs
@@ -89,10 +89,12 @@ impl yew::Component for PbsNodePanelComp {
                     move |_| {
                         let base_url = format!("/pbs/remotes/{remote}/nodes/localhost/apt");
                         let task_base_url = format!("/pbs/remotes/{remote}/tasks");
+                        let sub_url = format!("/pbs/remotes/{remote}/nodes/localhost/subscription");
 
                         AptPackageManager::new()
                             .base_url(base_url)
                             .task_base_url(task_base_url)
+                            .subscription_url(sub_url)
                             .enable_upgrade(true)
                             .on_upgrade({
                                 let remote = remote.clone();
diff --git a/ui/src/pve/node/mod.rs b/ui/src/pve/node/mod.rs
index 1fcd92eb..332c26a8 100644
--- a/ui/src/pve/node/mod.rs
+++ b/ui/src/pve/node/mod.rs
@@ -86,10 +86,12 @@ impl yew::Component for PveNodePanelComp {
                     move |_| {
                         let base_url = format!("/pve/remotes/{remote}/nodes/{node}/apt");
                         let task_base_url = format!("/pve/remotes/{remote}/tasks");
+                        let sub_url = format!("/pve/remotes/{remote}/nodes/{node}/subscription");
 
                         AptPackageManager::new()
                             .base_url(base_url)
                             .task_base_url(task_base_url)
+                            .subscription_url(sub_url)
                             .enable_upgrade(true)
                             .on_upgrade({
                                 let remote = remote.clone();
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (7 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib Dominik Csapak
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

show popup when the local subscription check fails

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
changes from v1:
* use nodes/localhost endpoint instead of the dashboard one

 ui/src/main.rs | 22 ++++++----------------
 1 file changed, 6 insertions(+), 16 deletions(-)

diff --git a/ui/src/main.rs b/ui/src/main.rs
index 454a2927..9cff3833 100644
--- a/ui/src/main.rs
+++ b/ui/src/main.rs
@@ -1,6 +1,6 @@
 use anyhow::Error;
 use gloo_timers::callback::Timeout;
-use serde_json::json;
+use serde_json::{json, Value};
 use wasm_bindgen::JsCast;
 use web_sys::HtmlElement;
 
@@ -21,7 +21,6 @@ use proxmox_yew_comp::{
 };
 
 //use pbs::MainMenu;
-use pdm_api_types::subscription::{RemoteSubscriptionState, RemoteSubscriptions};
 use pdm_api_types::views::ViewConfig;
 use pdm_ui::{
     register_pve_tasks, MainMenu, RemoteList, RemoteListCacheEntry, SearchProvider, TopNavBar,
@@ -64,16 +63,10 @@ struct DatacenterManagerApp {
 }
 
 async fn check_subscription() -> Msg {
-    let data: Result<Vec<RemoteSubscriptions>, _> = http_get("/resources/subscription", None).await;
+    let data: Result<Value, _> = http_get("/nodes/localhost/subscription", None).await;
 
-    let show_alert = match data {
-        Ok(list) => list
-            .into_iter()
-            .any(|info| info.state == RemoteSubscriptionState::None),
-        Err(_) => false,
-    };
-
-    if show_alert {
+    let is_active = proxmox_yew_comp::subscription_is_active(&Some(data));
+    if !is_active {
         Msg::ShowSubscriptionAlert
     } else {
         Msg::ConfirmSubscription
@@ -246,11 +239,8 @@ impl Component for DatacenterManagerApp {
                 true
             }
             Msg::ShowSubscriptionAlert => {
-                // Disable for alpha and rework for a beta or stable version to avoid friction if a
-                // few unsubscribed test instances are present in another subscribed (big) setup.
-                // self.show_subscription_alert = Some(true);
-                self.subscription_confirmed = true;
-                self.show_subscription_alert = Some(false);
+                self.subscription_confirmed = false;
+                self.show_subscription_alert = Some(true);
                 true
             }
             Msg::Logout => {
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (8 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

so we can reuse the global subscription check logic elsewhere

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 ui/src/lib.rs  |  9 +++++++++
 ui/src/main.rs | 28 ++++++++++++----------------
 2 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/ui/src/lib.rs b/ui/src/lib.rs
index 27a51084..d8225a42 100644
--- a/ui/src/lib.rs
+++ b/ui/src/lib.rs
@@ -3,6 +3,9 @@ use pdm_api_types::remotes::RemoteType;
 use pdm_api_types::resource::{PveLxcResource, PveNetworkResource, PveQemuResource};
 use pdm_client::types::Resource;
 use serde::{Deserialize, Serialize};
+use serde_json::Value;
+
+use proxmox_yew_comp::http_get;
 
 mod administration;
 
@@ -234,3 +237,9 @@ pub(crate) fn locale_compare(first: String, second: &str, numeric: bool) -> std:
         .locale_compare(second, &Array::new(), &options)
         .cmp(&0)
 }
+
+/// Returns true if the global subscription checks succeeded
+pub async fn check_subscription() -> bool {
+    let data: Result<Value, _> = http_get("/nodes/localhost/subscription", None).await;
+    proxmox_yew_comp::subscription_is_active(&Some(data))
+}
diff --git a/ui/src/main.rs b/ui/src/main.rs
index 9cff3833..b7dd3ef1 100644
--- a/ui/src/main.rs
+++ b/ui/src/main.rs
@@ -1,6 +1,6 @@
 use anyhow::Error;
 use gloo_timers::callback::Timeout;
-use serde_json::{json, Value};
+use serde_json::json;
 use wasm_bindgen::JsCast;
 use web_sys::HtmlElement;
 
@@ -23,8 +23,8 @@ use proxmox_yew_comp::{
 //use pbs::MainMenu;
 use pdm_api_types::views::ViewConfig;
 use pdm_ui::{
-    register_pve_tasks, MainMenu, RemoteList, RemoteListCacheEntry, SearchProvider, TopNavBar,
-    ViewListContext,
+    check_subscription, register_pve_tasks, MainMenu, RemoteList, RemoteListCacheEntry,
+    SearchProvider, TopNavBar, ViewListContext,
 };
 
 type MsgRemoteList = Result<RemoteList, Error>;
@@ -62,17 +62,6 @@ struct DatacenterManagerApp {
     async_pool: AsyncPool,
 }
 
-async fn check_subscription() -> Msg {
-    let data: Result<Value, _> = http_get("/nodes/localhost/subscription", None).await;
-
-    let is_active = proxmox_yew_comp::subscription_is_active(&Some(data));
-    if !is_active {
-        Msg::ShowSubscriptionAlert
-    } else {
-        Msg::ConfirmSubscription
-    }
-}
-
 /*
 async fn get_fingerprint() -> Option<Msg> {
     http_get("/nodes/localhost/status", None)
@@ -89,8 +78,15 @@ impl DatacenterManagerApp {
                 if self.subscription_confirmed {
                     ctx.link().send_message(Msg::ConfirmSubscription);
                 } else {
-                    self.async_pool
-                        .send_future(ctx.link().clone(), check_subscription());
+                    self.async_pool.send_future(ctx.link().clone(), async move {
+                        let is_active = check_subscription().await;
+
+                        if !is_active {
+                            Msg::ShowSubscriptionAlert
+                        } else {
+                            Msg::ConfirmSubscription
+                        }
+                    });
                 }
             } else {
                 ctx.link().send_message(Msg::ConfirmSubscription);
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all'
  2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
                   ` (9 preceding siblings ...)
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib Dominik Csapak
@ 2025-12-01 13:53 ` Dominik Csapak
  2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht
  10 siblings, 1 reply; 22+ messages in thread
From: Dominik Csapak @ 2025-12-01 13:53 UTC (permalink / raw)
  To: pdm-devel

in pve/pbs we do a check on refreshing too, so it's only fitting to do
one here as well.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 ui/src/remotes/updates.rs | 48 +++++++++++++++++++++++++++++++++++----
 1 file changed, 43 insertions(+), 5 deletions(-)

diff --git a/ui/src/remotes/updates.rs b/ui/src/remotes/updates.rs
index 020a2c4b..2237d310 100644
--- a/ui/src/remotes/updates.rs
+++ b/ui/src/remotes/updates.rs
@@ -19,7 +19,7 @@ use proxmox_deb_version;
 
 use proxmox_yew_comp::{
     AptPackageManager, AptRepositories, ExistingProduct, LoadableComponent,
-    LoadableComponentContext, LoadableComponentMaster,
+    LoadableComponentContext, LoadableComponentMaster, SubscriptionAlert,
 };
 use pwt::props::{CssBorderBuilder, CssPaddingBuilder, WidgetStyleBuilder};
 use pwt::widget::{Button, Container, Panel, Tooltip};
@@ -35,7 +35,7 @@ use pwt::{
     },
 };
 
-use crate::{get_deep_url, get_deep_url_low_level, pdm_client};
+use crate::{check_subscription, get_deep_url, get_deep_url_low_level, pdm_client};
 
 #[derive(PartialEq, Properties)]
 pub struct UpdateTree {}
@@ -120,6 +120,7 @@ enum RemoteUpdateTreeMsg {
     LoadFinished(UpdateSummary),
     KeySelected(Option<Key>),
     RefreshAll,
+    CheckSubscription,
 }
 
 struct UpdateTreeComponent {
@@ -303,10 +304,15 @@ fn build_store_from_response(update_summary: UpdateSummary) -> SlabTree<UpdateTr
     tree
 }
 
+#[derive(PartialEq)]
+enum ViewState {
+    ShowSubscriptionAlert,
+}
+
 impl LoadableComponent for UpdateTreeComponent {
     type Properties = UpdateTree;
     type Message = RemoteUpdateTreeMsg;
-    type ViewState = ();
+    type ViewState = ViewState;
 
     fn create(ctx: &LoadableComponentContext<Self>) -> Self {
         let link = ctx.link();
@@ -343,6 +349,24 @@ impl LoadableComponent for UpdateTreeComponent {
         })
     }
 
+    fn dialog_view(
+        &self,
+        ctx: &LoadableComponentContext<Self>,
+        view_state: &Self::ViewState,
+    ) -> Option<Html> {
+        let link = ctx.link().clone();
+        match view_state {
+            ViewState::ShowSubscriptionAlert => Some(
+                SubscriptionAlert::new("notfound")
+                    .on_close(move |_| {
+                        link.change_view(None);
+                        link.send_message(RemoteUpdateTreeMsg::RefreshAll);
+                    })
+                    .into(),
+            ),
+        }
+    }
+
     fn update(&mut self, ctx: &LoadableComponentContext<Self>, msg: Self::Message) -> bool {
         match msg {
             Self::Message::LoadFinished(updates) => {
@@ -363,6 +387,18 @@ impl LoadableComponent for UpdateTreeComponent {
                     return true;
                 }
             }
+            Self::Message::CheckSubscription => {
+                let link = ctx.link();
+
+                link.clone().spawn(async move {
+                    let is_active = check_subscription().await;
+                    if !is_active {
+                        link.change_view(Some(ViewState::ShowSubscriptionAlert));
+                    } else {
+                        link.send_message(RemoteUpdateTreeMsg::RefreshAll);
+                    }
+                });
+            }
             Self::Message::RefreshAll => {
                 let link = ctx.link();
 
@@ -407,7 +443,7 @@ impl UpdateTreeComponent {
         let refresh_all_button = Button::new(tr!("Refresh all")).on_activate({
             let link = ctx.link().clone();
             move |_| {
-                link.send_message(RemoteUpdateTreeMsg::RefreshAll);
+                link.send_message(RemoteUpdateTreeMsg::CheckSubscription);
             }
         });
 
@@ -667,7 +703,9 @@ fn render_version_column(tree_entry: &UpdateTreeEntry, expanded: bool) -> Html {
             let (icon, extra) = match remote_entry.mixed_versions {
                 MixedVersions::None => ("", "".to_string()),
                 MixedVersions::DifferentMajor => ("times-circle", tr!("major difference")),
-                MixedVersions::DifferentMinor => ("exclamation-triangle", tr!("substantial difference")),
+                MixedVersions::DifferentMinor => {
+                    ("exclamation-triangle", tr!("substantial difference"))
+                }
                 MixedVersions::DifferentPatch => ("info-circle", tr!("small difference")),
             };
             let version_string = remote_entry.product_version.clone().unwrap_or_default();
-- 
2.47.3



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] applied: [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert
  2025-12-01 13:52 ` [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
@ 2025-12-01 19:02   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 19:02 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:52:59 +0100, Dominik Csapak wrote:
> so we can reuse that
> 
> 

Applied, thanks!

[1/2] subscription: refactor api subscription check for showing the alert
      commit: e4a37b08caa53a1112e3deba9d0c1acd1f09e317
[2/2] apt package manager: add optional subscription check on 'Refresh' button
      commit: d63ed6a9bf4b3dd951e902724df387761705e6fe


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] applied: [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:01 +0100, Dominik Csapak wrote:
> needed to re-use it internally for enterprise repository access.
> 
> intentionally not serialized to avoid leaking it.
> 
> 

Applied, thanks!

[1/9] subscription: add serverid field to node subscription info
      commit: 2bacd0218f0f4645a00230661f62446c9cd9b9f0


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] applied: [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:02 +0100, Dominik Csapak wrote:
> this is a different view for the global subscription status - instead of
> looking at the lowest level per remote, count all nodes.
> 
> 

Applied, thanks!

[2/9] api types: add new SubscriptionStatistics
      commit: 34da28404b074ea62bd6f76c38d443f6b8b7042f


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] applied: [PATCH datacenter-manager v2 3/9] api: add subscription endpoints
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 3/9] api: add subscription endpoints Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:03 +0100, Dominik Csapak wrote:
> for the PDM system itself, by proxy of how many of the remote nodes have valid
> subscriptions above a certain level.
> 
> 

Applied, thanks!

[3/9] api: add subscription endpoints
      commit: d7e8041d36b6ab95058d6f9b7782466e35ef6c7e


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] applied: [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:04 +0100, Dominik Csapak wrote:
> we have here a 'check_priv' that should return if the permission check
> was successful. So instead of wrongly check for 'is_err', rather check
> for 'is_ok'.
> 
> 

Applied, thanks!

[4/9] server: api: subscription: fix permission check
      commit: ab3a09a37faef1b7ded4cbc00650229da6434431


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] applied: [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:05 +0100, Dominik Csapak wrote:
> returns the subscription information per node
> 
> 

Applied, thanks!

[5/9] server: api: pve/pbs: node: add subscription api call
      commit: a7dfdf574f0d0de7ce4bb95abed5960b73c313d3


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] applied: [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url Dominik Csapak
@ 2025-12-01 23:01   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:01 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:06 +0100, Dominik Csapak wrote:
> so the 'Refresh' button does a subscription check.
> 
> 

Applied, thanks!

[6/9] ui: pve/pbs: updates: add subscription_url
      commit: 298590097e2be56855cdbaff0132e463f2b4a3c8


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] applied: [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check Dominik Csapak
@ 2025-12-01 23:02   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:02 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:07 +0100, Dominik Csapak wrote:
> show popup when the local subscription check fails
> 
> 

Applied, thanks!

[7/9] ui: login: enable subscription check
      commit: 3d543c93c797e679e669383a517c62ac4cf8754c


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] applied: [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib Dominik Csapak
@ 2025-12-01 23:02   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:02 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:08 +0100, Dominik Csapak wrote:
> so we can reuse the global subscription check logic elsewhere
> 
> 

Applied, thanks!

[8/9] ui: refactor check_subscription into lib
      commit: 18853280426a39f93b024c06f927525d274d189c


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [pdm-devel] applied: [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all'
  2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
@ 2025-12-01 23:02   ` Thomas Lamprecht
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Lamprecht @ 2025-12-01 23:02 UTC (permalink / raw)
  To: pdm-devel, Dominik Csapak

On Mon, 01 Dec 2025 14:53:09 +0100, Dominik Csapak wrote:
> in pve/pbs we do a check on refreshing too, so it's only fitting to do
> one here as well.
> 
> 

Applied, thanks!

[9/9] ui: remote updates: add subscription check on 'Refresh all'
      commit: 2ff678f65138f336d3eb88ee45aa8af2624280d9


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2025-12-01 23:02 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-01 13:52 [pdm-devel] [PATCH datacenter-manager/yew-comp v2 00/11] add subscription checks to apt repository updates & login Dominik Csapak
2025-12-01 13:52 ` [pdm-devel] [PATCH yew-comp v2 1/2] subscription: refactor api subscription check for showing the alert Dominik Csapak
2025-12-01 19:02   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH yew-comp v2 2/2] apt package manager: add optional subscription check on 'Refresh' button Dominik Csapak
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 1/9] subscription: add serverid field to node subscription info Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 2/9] api types: add new SubscriptionStatistics Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 3/9] api: add subscription endpoints Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 4/9] server: api: subscription: fix permission check Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 5/9] server: api: pve/pbs: node: add subscription api call Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 6/9] ui: pve/pbs: updates: add subscription_url Dominik Csapak
2025-12-01 23:01   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 7/9] ui: login: enable subscription check Dominik Csapak
2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 8/9] ui: refactor check_subscription into lib Dominik Csapak
2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht
2025-12-01 13:53 ` [pdm-devel] [PATCH datacenter-manager v2 9/9] ui: remote updates: add subscription check on 'Refresh all' Dominik Csapak
2025-12-01 23:02   ` [pdm-devel] applied: " Thomas Lamprecht

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal