Skip to main content

unifly_api/convert/
supporting.rs

1use serde_json::Value;
2
3use crate::integration_types;
4use crate::model::common::DataSource;
5use crate::model::entity_id::EntityId;
6use crate::model::hotspot::Voucher;
7use crate::model::supporting::TrafficMatchingList;
8
9use super::helpers::parse_iso;
10
11fn traffic_matching_item_to_string(item: &Value) -> Option<String> {
12    match item {
13        Value::String(value) => Some(value.clone()),
14        Value::Object(map) => {
15            if let Some(value) = map
16                .get("value")
17                .and_then(Value::as_str)
18                .map(str::to_owned)
19                .or_else(|| {
20                    map.get("value")
21                        .and_then(Value::as_i64)
22                        .map(|value| value.to_string())
23                })
24            {
25                return Some(value);
26            }
27
28            let start = map.get("start").or_else(|| map.get("startPort"));
29            let stop = map.get("stop").or_else(|| map.get("endPort"));
30            match (start, stop) {
31                (Some(start), Some(stop)) => {
32                    let start = start
33                        .as_str()
34                        .map(str::to_owned)
35                        .or_else(|| start.as_i64().map(|value| value.to_string()));
36                    let stop = stop
37                        .as_str()
38                        .map(str::to_owned)
39                        .or_else(|| stop.as_i64().map(|value| value.to_string()));
40                    match (start, stop) {
41                        (Some(start), Some(stop)) => Some(format!("{start}-{stop}")),
42                        _ => None,
43                    }
44                }
45                _ => None,
46            }
47        }
48        _ => None,
49    }
50}
51
52impl From<integration_types::TrafficMatchingListResponse> for TrafficMatchingList {
53    fn from(t: integration_types::TrafficMatchingListResponse) -> Self {
54        let items = t
55            .extra
56            .get("items")
57            .and_then(|v| v.as_array())
58            .map(|arr| {
59                arr.iter()
60                    .filter_map(traffic_matching_item_to_string)
61                    .collect()
62            })
63            .unwrap_or_default();
64
65        TrafficMatchingList {
66            id: EntityId::Uuid(t.id),
67            name: t.name,
68            list_type: t.list_type,
69            items,
70            origin: None,
71        }
72    }
73}
74
75impl From<integration_types::VoucherResponse> for Voucher {
76    fn from(v: integration_types::VoucherResponse) -> Self {
77        #[allow(
78            clippy::as_conversions,
79            clippy::cast_possible_truncation,
80            clippy::cast_sign_loss
81        )]
82        Voucher {
83            id: EntityId::Uuid(v.id),
84            code: v.code,
85            name: Some(v.name),
86            created_at: parse_iso(&v.created_at),
87            activated_at: v.activated_at.as_deref().and_then(parse_iso),
88            expires_at: v.expires_at.as_deref().and_then(parse_iso),
89            expired: v.expired,
90            time_limit_minutes: Some(v.time_limit_minutes as u32),
91            data_usage_limit_mb: v.data_usage_limit_m_bytes.map(|b| b as u64),
92            authorized_guest_limit: v.authorized_guest_limit.map(|l| l as u32),
93            authorized_guest_count: Some(v.authorized_guest_count as u32),
94            rx_rate_limit_kbps: v.rx_rate_limit_kbps.map(|r| r as u64),
95            tx_rate_limit_kbps: v.tx_rate_limit_kbps.map(|r| r as u64),
96            source: DataSource::IntegrationApi,
97        }
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use std::collections::HashMap;
104
105    use super::*;
106    use serde_json::json;
107
108    #[test]
109    fn integration_traffic_matching_list_formats_structured_items() {
110        let response = integration_types::TrafficMatchingListResponse {
111            id: uuid::Uuid::nil(),
112            name: "Ports".into(),
113            list_type: "PORT".into(),
114            extra: HashMap::from([(
115                "items".into(),
116                json!([
117                    {"type": "PORT_NUMBER", "value": 443},
118                    {"type": "PORT_RANGE", "start": 1000, "stop": 2000}
119                ]),
120            )]),
121        };
122
123        let list = TrafficMatchingList::from(response);
124        assert_eq!(list.items, vec!["443".to_owned(), "1000-2000".to_owned()]);
125    }
126}