From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id A60E51FF187 for ; Mon, 22 Sep 2025 17:05:29 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 32CA91F70A; Mon, 22 Sep 2025 17:05:59 +0200 (CEST) From: Shannon Sterz To: pdm-devel@lists.proxmox.com Date: Mon, 22 Sep 2025 17:05:12 +0200 Message-ID: <20250922150519.399573-7-s.sterz@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20250922150519.399573-1-s.sterz@proxmox.com> References: <20250922150519.399573-1-s.sterz@proxmox.com> MIME-Version: 1.0 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1758553511029 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.058 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 Subject: [pdm-devel] [PATCH yew-comp v2 5/6] auth_view: implement syncing ldap and ad realms X-BeenThere: pdm-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Datacenter Manager development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Datacenter Manager development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pdm-devel-bounces@lists.proxmox.com Sender: "pdm-devel" by adding an EditWindow that allows specifying the sync options and then calling the specified sync endpoint. Signed-off-by: Shannon Sterz --- src/auth_view.rs | 155 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 151 insertions(+), 4 deletions(-) diff --git a/src/auth_view.rs b/src/auth_view.rs index a70e80b..f957e65 100644 --- a/src/auth_view.rs +++ b/src/auth_view.rs @@ -4,6 +4,9 @@ use std::rc::Rc; use anyhow::Error; +use proxmox_client::ApiResponseData; +use pwt::widget::form::{Checkbox, FormContext, TristateBoolean}; +use serde_json::Value; use yew::html::IntoPropValue; use yew::virtual_dom::{VComp, VNode}; @@ -12,13 +15,13 @@ use pwt::state::{Selection, Store}; use pwt::widget::data_table::{DataTable, DataTableColumn, DataTableHeader}; use pwt::widget::menu::{Menu, MenuButton, MenuItem}; -use pwt::widget::{Button, Fa, Toolbar}; +use pwt::widget::{Button, Container, Fa, InputPanel, Toolbar}; use pwt_macros::builder; use crate::{ - AuthEditLDAP, AuthEditOpenID, LoadableComponent, LoadableComponentContext, - LoadableComponentMaster, + AuthEditLDAP, AuthEditOpenID, EditWindow, LoadableComponent, LoadableComponentContext, + LoadableComponentLink, LoadableComponentMaster, }; use crate::common_api_types::BasicRealmInfo; @@ -69,6 +72,7 @@ pub enum ViewState { EditOpenID(AttrValue), EditLDAP(AttrValue), EditAd(AttrValue), + Sync(BasicRealmInfo), } pub enum Msg { @@ -89,6 +93,73 @@ async fn delete_item(base_url: AttrValue, realm: AttrValue) -> Result<(), Error> Ok(()) } +async fn sync_realm( + form_ctx: FormContext, + link: LoadableComponentLink, + url: impl Into, +) -> Result<(), Error> { + let mut data = form_ctx.get_submit_data(); + + let mut remove_vanished = Vec::new(); + + for prop in ["acl", "entry", "properties"] { + let prop_name = format!("remove-vanished-{prop}"); + if data[&prop_name] == Value::Bool(true) { + remove_vanished.push(prop); + } + + data[&prop_name] = Value::Null; + } + + if !remove_vanished.is_empty() { + data["remove-vanished"] = Value::String(remove_vanished.join(";")); + } + + let mut new = serde_json::json!({}); + + for (param, v) in data.as_object().unwrap().iter() { + if !v.is_null() { + new[param] = v.clone(); + } + } + + match crate::http_post::(url, Some(new)).await { + Ok(upid) => link.show_task_log(upid, None), + Err(err) => link.show_error(tr!("Sync Failed"), err, true), + }; + + Ok(()) +} + +async fn load_realm(url: impl Into) -> Result, Error> { + let mut response: ApiResponseData = crate::http_get_full(url, None).await?; + + if let Value::String(sync_default_options) = response.data["sync-defaults-options"].take() { + let split = sync_default_options.split(","); + + for part in split { + let mut part = part.split("="); + + match part.next() { + Some("enable-new") => { + response.data["enable-new"] = Value::Bool(part.next() == Some("true")) + } + Some("remove-vanished") => { + if let Some(part) = part.next() { + for vanished_opt in part.split(";") { + response.data[&format!("remove-vanished-{vanished_opt}")] = + Value::Bool(true) + } + } + } + _ => {} + } + } + } + + Ok(response) +} + impl ProxmoxAuthView { fn get_selected_record(&self) -> Option { let selected_key = self.selection.selected_key(); @@ -171,7 +242,12 @@ impl LoadableComponent for ProxmoxAuthView { true } Msg::Sync => { - // fixme: do something + let info = match self.get_selected_record() { + Some(info) => info, + None => return true, + }; + + ctx.link().change_view(Some(ViewState::Sync(info))); true } } @@ -312,6 +388,77 @@ impl LoadableComponent for ProxmoxAuthView { .on_close(ctx.link().change_view_callback(|_| None)) .into(), ), + ViewState::Sync(realm) => { + let link = ctx.link(); + let url = format!( + "{}/{}/sync", + ctx.props().base_url, + percent_encode_component(&realm.realm) + ); + + let base_url = match realm.ty.as_str() { + // unwraps here are safe as the guards ensure the Option is a Some + "ldap" if props.ldap_base_url.is_some() => { + props.ldap_base_url.as_ref().unwrap() + } + "ad" if props.ad_base_url.is_some() => props.ad_base_url.as_ref().unwrap(), + _ => return None, + }; + + Some( + EditWindow::new(tr!("Realm Sync")) + .renderer(|_form_ctx| { + InputPanel::new() + .padding(4) + .with_field(tr!("Preview Only"), Checkbox::new().name("dry-run")) + .with_field( + tr!("Enable new users"), + TristateBoolean::new() + .name("enable-new") + .null_text(tr!("Default") + " (" + &tr!("Yes") + ")"), + ) + .with_large_custom_child( + Container::new() + .key("remove-vanished-options") + .class("pwt-font-title-medium") + .padding_top(2) + .with_child(tr!("Remove Vanished Options")), + ) + .with_large_field( + tr!("ACLs"), + Checkbox::new() + .name("remove-vanished-acl") + .box_label(tr!("Remove ACLs of vanished users.")), + ) + .with_large_field( + tr!("Entries"), + Checkbox::new() + .name("remove-vanished-entry") + .box_label(tr!("Remove vanished user")), + ) + .with_large_field( + tr!("Properties"), + Checkbox::new() + .name("remove-vanished-properties") + .box_label(tr!("Remove vanished properties")), + ) + .into() + }) + .loader({ + let url = + format!("{base_url}/{}", percent_encode_component(&realm.realm)); + move || load_realm(url.clone()) + }) + .submit_digest(false) + .on_close(link.change_view_callback(|_| None)) + .on_submit(move |form_context| { + let link = link.clone(); + let url = url.clone(); + sync_realm(form_context, link, url) + }) + .into(), + ) + } } } } -- 2.47.3 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel