use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::client::GuacamoleClient;
use crate::error::Result;
use crate::validation::validate_sharing_profile_id;
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SharingProfile {
#[serde(skip_serializing_if = "Option::is_none")]
pub identifier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub primary_connection_identifier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attributes: Option<HashMap<String, String>>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SharingProfileSummary {
#[serde(skip_serializing_if = "Option::is_none")]
pub identifier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub primary_connection_identifier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}
impl GuacamoleClient {
pub async fn list_sharing_profiles(
&self,
data_source: Option<&str>,
) -> Result<HashMap<String, SharingProfile>> {
let ds = self.resolve_data_source(data_source)?;
let url = self.url(&format!(
"/api/session/data/{ds}/sharingProfiles"
))?;
let response = self.http.get(&url).send().await?;
Self::parse_response(response, "sharing profiles").await
}
pub async fn get_sharing_profile(
&self,
data_source: Option<&str>,
sharing_profile_id: &str,
) -> Result<SharingProfile> {
validate_sharing_profile_id(sharing_profile_id)?;
let ds = self.resolve_data_source(data_source)?;
let url = self.url(&format!(
"/api/session/data/{ds}/sharingProfiles/{sharing_profile_id}"
))?;
let response = self.http.get(&url).send().await?;
Self::parse_response(response, &format!("sharing profile {sharing_profile_id}"))
.await
}
pub async fn get_sharing_profile_parameters(
&self,
data_source: Option<&str>,
sharing_profile_id: &str,
) -> Result<HashMap<String, String>> {
validate_sharing_profile_id(sharing_profile_id)?;
let ds = self.resolve_data_source(data_source)?;
let url = self.url(&format!(
"/api/session/data/{ds}/sharingProfiles/{sharing_profile_id}/parameters"
))?;
let response = self.http.get(&url).send().await?;
Self::parse_response(
response,
&format!("sharing profile {sharing_profile_id} parameters"),
)
.await
}
pub async fn create_sharing_profile(
&self,
data_source: Option<&str>,
sharing_profile: &SharingProfile,
) -> Result<SharingProfile> {
let ds = self.resolve_data_source(data_source)?;
let url = self.url(&format!(
"/api/session/data/{ds}/sharingProfiles"
))?;
let response = self
.http
.post(&url)
.json(sharing_profile)
.send()
.await?;
Self::parse_response(response, "create sharing profile").await
}
pub async fn update_sharing_profile(
&self,
data_source: Option<&str>,
sharing_profile_id: &str,
sharing_profile: &SharingProfile,
) -> Result<()> {
validate_sharing_profile_id(sharing_profile_id)?;
let ds = self.resolve_data_source(data_source)?;
let url = self.url(&format!(
"/api/session/data/{ds}/sharingProfiles/{sharing_profile_id}"
))?;
let response = self.http.put(&url).json(sharing_profile).send().await?;
Self::handle_error(response, &format!("sharing profile {sharing_profile_id}"))
.await?;
Ok(())
}
pub async fn delete_sharing_profile(
&self,
data_source: Option<&str>,
sharing_profile_id: &str,
) -> Result<()> {
validate_sharing_profile_id(sharing_profile_id)?;
let ds = self.resolve_data_source(data_source)?;
let url = self.url(&format!(
"/api/session/data/{ds}/sharingProfiles/{sharing_profile_id}"
))?;
let response = self.http.delete(&url).send().await?;
Self::handle_error(
response,
&format!("sharing profile {sharing_profile_id}"),
)
.await?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sharing_profile_serde_roundtrip() {
let sp = SharingProfile {
identifier: Some("3".to_string()),
primary_connection_identifier: Some("1".to_string()),
name: Some("read-only-view".to_string()),
parameters: Some(HashMap::new()),
attributes: Some(HashMap::new()),
};
let json = serde_json::to_string(&sp).unwrap();
let deserialized: SharingProfile = serde_json::from_str(&json).unwrap();
assert_eq!(sp, deserialized);
}
#[test]
fn sharing_profile_camel_case_keys() {
let sp = SharingProfile {
primary_connection_identifier: Some("1".to_string()),
..Default::default()
};
let json = serde_json::to_value(&sp).unwrap();
assert!(json.get("primaryConnectionIdentifier").is_some());
}
#[test]
fn sharing_profile_skip_none_fields() {
let sp = SharingProfile::default();
let json = serde_json::to_value(&sp).unwrap();
let obj = json.as_object().unwrap();
assert!(obj.is_empty());
}
#[test]
fn deserialize_sharing_profile_from_api_json() {
let json = r#"{
"identifier": "3",
"primaryConnectionIdentifier": "1",
"name": "read-only-view",
"parameters": {},
"attributes": {}
}"#;
let sp: SharingProfile = serde_json::from_str(json).unwrap();
assert_eq!(sp.identifier.as_deref(), Some("3"));
assert_eq!(sp.primary_connection_identifier.as_deref(), Some("1"));
assert_eq!(sp.name.as_deref(), Some("read-only-view"));
}
#[test]
fn sharing_profile_summary_serde_roundtrip() {
let summary = SharingProfileSummary {
identifier: Some("3".to_string()),
primary_connection_identifier: Some("1".to_string()),
name: Some("read-only".to_string()),
};
let json = serde_json::to_string(&summary).unwrap();
let deserialized: SharingProfileSummary = serde_json::from_str(&json).unwrap();
assert_eq!(summary, deserialized);
}
#[test]
fn deserialize_sharing_profile_unknown_fields_ignored() {
let json = r#"{"identifier": "3", "unknownField": true}"#;
let sp: SharingProfile = serde_json::from_str(json).unwrap();
assert_eq!(sp.identifier.as_deref(), Some("3"));
}
#[test]
fn summary_camel_case_keys() {
let summary = SharingProfileSummary {
primary_connection_identifier: Some("1".to_string()),
..Default::default()
};
let json = serde_json::to_value(&summary).unwrap();
assert!(json.get("primaryConnectionIdentifier").is_some());
assert!(json.get("primary_connection_identifier").is_none());
}
#[test]
fn summary_skip_none_fields() {
let summary = SharingProfileSummary::default();
let json = serde_json::to_value(&summary).unwrap();
let obj = json.as_object().unwrap();
assert!(obj.is_empty());
}
#[test]
fn summary_unknown_fields_ignored() {
let json = r#"{"identifier": "5", "unknownField": "value"}"#;
let summary: SharingProfileSummary = serde_json::from_str(json).unwrap();
assert_eq!(summary.identifier.as_deref(), Some("5"));
}
}