Skip to main content

unifly_api/command/requests/
network.rs

1use serde::{Deserialize, Serialize};
2
3use crate::model::{EntityId, NetworkManagement, NetworkPurpose, WifiSecurityMode};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6#[allow(clippy::struct_excessive_bools)]
7pub struct CreateNetworkRequest {
8    pub name: String,
9    #[serde(skip_serializing_if = "Option::is_none")]
10    pub vlan_id: Option<u16>,
11    #[serde(skip_serializing_if = "Option::is_none")]
12    pub subnet: Option<String>,
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub management: Option<NetworkManagement>,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub purpose: Option<NetworkPurpose>,
17    pub dhcp_enabled: bool,
18    pub enabled: bool,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub dhcp_range_start: Option<String>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub dhcp_range_stop: Option<String>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub dhcp_lease_time: Option<u32>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub dns_servers: Option<Vec<String>>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub firewall_zone_id: Option<String>,
29    pub isolation_enabled: bool,
30    pub internet_access_enabled: bool,
31}
32
33/// Optional DHCP overrides for network updates (from JSON files).
34#[derive(Debug, Clone, Default, Serialize, Deserialize)]
35pub struct DhcpUpdate {
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub dns_servers: Option<Vec<String>>,
38}
39
40#[derive(Debug, Clone, Default, Serialize, Deserialize)]
41#[allow(clippy::struct_excessive_bools)]
42pub struct UpdateNetworkRequest {
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub name: Option<String>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub vlan_id: Option<u16>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub subnet: Option<String>,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub dhcp_enabled: Option<bool>,
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub enabled: Option<bool>,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub isolation_enabled: Option<bool>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub internet_access_enabled: Option<bool>,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub mdns_forwarding_enabled: Option<bool>,
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub ipv6_enabled: Option<bool>,
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub dhcp: Option<DhcpUpdate>,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
66#[allow(clippy::struct_excessive_bools)]
67pub struct CreateWifiBroadcastRequest {
68    pub name: String,
69    #[serde(default)]
70    pub ssid: String,
71    pub security_mode: WifiSecurityMode,
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub passphrase: Option<String>,
74    #[serde(default = "default_enabled")]
75    pub enabled: bool,
76    #[serde(skip_serializing_if = "Option::is_none", alias = "network")]
77    pub network_id: Option<EntityId>,
78    #[serde(default, alias = "hideName", alias = "hidden")]
79    pub hide_ssid: bool,
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub broadcast_type: Option<String>,
82    #[serde(skip_serializing_if = "Option::is_none")]
83    #[serde(alias = "broadcastingFrequenciesGHz", alias = "frequencies")]
84    pub frequencies_ghz: Option<Vec<f32>>,
85    #[serde(default)]
86    #[serde(alias = "bandSteeringEnabled")]
87    pub band_steering: bool,
88    #[serde(
89        default,
90        alias = "bssTransitionEnabled",
91        skip_serializing_if = "Option::is_none"
92    )]
93    pub fast_roaming: Option<bool>,
94}
95
96fn default_enabled() -> bool {
97    true
98}
99
100#[derive(Debug, Clone, Default, Serialize, Deserialize)]
101pub struct UpdateWifiBroadcastRequest {
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub name: Option<String>,
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub ssid: Option<String>,
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub security_mode: Option<WifiSecurityMode>,
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub passphrase: Option<String>,
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub enabled: Option<bool>,
112    #[serde(skip_serializing_if = "Option::is_none")]
113    #[serde(alias = "hideName")]
114    pub hide_ssid: Option<bool>,
115}
116
117#[cfg(test)]
118mod tests {
119    use super::CreateWifiBroadcastRequest;
120
121    #[test]
122    fn create_wifi_broadcast_request_honors_alias_fields() {
123        let request: CreateWifiBroadcastRequest = serde_json::from_value(serde_json::json!({
124            "name": "Guest",
125            "ssid": "Guest",
126            "security_mode": "Open",
127            "enabled": true,
128            "hideName": true,
129            "bandSteeringEnabled": true,
130            "bssTransitionEnabled": true
131        }))
132        .expect("wifi broadcast request should deserialize");
133
134        assert!(request.hide_ssid);
135        assert!(request.band_steering);
136        assert_eq!(request.fast_roaming, Some(true));
137    }
138
139    #[test]
140    fn create_wifi_broadcast_request_honors_cli_style_aliases() {
141        let request: CreateWifiBroadcastRequest = serde_json::from_value(serde_json::json!({
142            "name": "Test",
143            "security_mode": "Wpa3Personal",
144            "passphrase": "test1234",
145            "hidden": true,
146            "fast_roaming": true,
147            "frequencies": [2.4]
148        }))
149        .expect("wifi broadcast request should deserialize with CLI-style aliases");
150
151        assert!(request.hide_ssid);
152        assert_eq!(request.fast_roaming, Some(true));
153        assert_eq!(request.frequencies_ghz, Some(vec![2.4]));
154    }
155}