cal_core/
account.rs

1use crate::core::*;
2use crate::device::{Connector, Device};
3use crate::utils::*;
4use phonenumber::country;
5use phonenumber::country::Id;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9
10
11#[derive(Serialize, Deserialize, Clone)]
12#[serde(rename_all = "camelCase")]
13pub struct RecordReference {
14    id: String,
15    name: String,
16}
17
18#[derive(Serialize, Deserialize, Clone)]
19#[serde(rename_all = "camelCase")]
20pub struct AccountLite {
21    pub id: String,
22    pub name: String,
23    pub mbn: String,
24    pub domain: String,
25    pub created: Option<String>,
26    pub organisation: RecordReference,
27    #[serde(default)]
28    pub ddis: Vec<DDI>,
29    #[serde(default)]
30    pub trunks: Vec<Trunk>,
31    #[serde(rename = "callbackURLS")]
32    pub hooks: Vec<Hook>,
33    #[serde(default)]
34    pub devices: Vec<Device>,
35    #[serde(default)]
36    pub environment: Environment,
37}
38
39impl AccountLite {
40    pub fn country_code(&self) -> &str {
41        self.environment.country_code.as_str()
42    }
43
44    pub fn country_code_parsed(&self) -> Id {
45        self.environment.country_code_parsed()
46    }
47
48    pub fn inbound_flow(&self, str: &str) -> Option<Device> {
49        match self.ddi(str) {
50            Some(ddi) => self.device(&ddi.id),
51            None => None,
52        }
53    }
54
55    pub fn outbound_flow(&self) -> Option<Device> {
56        self.devices
57            .iter()
58            .find(|d| d.match_outbound_flow())
59            .map(|d| d.clone())
60    }
61
62    pub fn device(&self, id: &str) -> Option<Device> {
63        self.devices
64            .iter()
65            .find(|d| d.match_device(id))
66            .map(|d| d.clone())
67    }
68
69    pub fn ddi(&self, str: &str) -> Option<DDI> {
70        let id = self.clean_str(str);
71        self.ddis
72            .iter()
73            .find(|ddi| ddi.id == id || ddi.name == id)
74            .map(|ddi| ddi.clone())
75    }
76
77    pub fn traverse(&self, state: &mut FlowState) -> Vec<FlowState> {
78        let mut states: Vec<FlowState> = Vec::new();
79        while state.device.is_some() {
80            match &state.device {
81                Some(d) => {
82                    let nd = d.clone().get_connect_to(state);
83                    states.push(nd);
84                }
85                None => {
86                    //do nothing
87                }
88            }
89        }
90        states
91    }
92
93    pub fn clean_str(&self, str: &str) -> String {
94        clean_str(self.environment.country_code_parsed(), str)
95    }
96}
97
98#[derive(Serialize, Deserialize, Clone)]
99#[serde(rename_all = "camelCase")]
100pub struct Account {
101    pub id: String,
102    pub name: String,
103    pub mbn: String,
104    pub domain: String,
105    // todo #[serde(with = "time::serde::rfc3339::option")]
106    pub created: Option<String>,
107    pub organisation: RecordReference,
108    #[serde(default)]
109    pub ddis: Vec<DDI>,
110    #[serde(default)]
111    pub trunks: Vec<Trunk>,
112    #[serde(default)]
113    #[serde(rename = "callbackURLS")]
114    pub hooks: Vec<Hook>,
115    #[serde(default)]
116    pub devices: Vec<Device>,
117    #[serde(default)]
118    pub settings: Vec<Setting>,
119    #[serde(default)]
120    pub assets: Vec<Asset>,
121    #[serde(default)]
122    pub address: Address,
123    #[serde(default)]
124    pub teams: TeamsAccount,
125    #[serde(default)]
126    pub environment: Environment,
127    #[serde(default)]
128    pub spend_cap: SpendCap,
129    pub concurrency: Concurrency,
130    #[serde(default)]
131    pub class_of_service: ClassOfService,
132    #[serde(default)]
133    pub api_keys: APIKeys,
134    pub cluster_settings: Cluster,
135    pub domain_settings: Domain,
136}
137
138#[derive(Serialize, Deserialize, Clone)]
139#[serde(rename_all = "camelCase")]
140pub struct Cluster {
141    id: String,
142    name: String,
143    router: RecordReference,
144}
145
146#[derive(Serialize, Deserialize, Clone)]
147#[serde(rename_all = "camelCase")]
148pub struct Domain {
149    #[serde(rename = "serverA")]
150    server_a: String,
151    #[serde(rename = "serverB")]
152    server_b: String,
153}
154
155#[derive(Serialize, Deserialize, Clone)]
156#[serde(rename_all = "camelCase")]
157pub struct APIKeys {
158    #[serde(default)]
159    keys: Vec<APIKey>,
160}
161
162impl Default for APIKeys {
163    fn default() -> Self {
164        Self { keys: Vec::new() }
165    }
166}
167
168#[derive(Serialize, Deserialize, Clone)]
169#[serde(rename_all = "camelCase")]
170pub struct APIKey {
171    key: String,
172}
173
174#[derive(Serialize, Deserialize, Clone)]
175#[serde(rename_all = "camelCase")]
176pub struct Environment {
177    #[serde(default = "build_logger")]
178    pub logger: LoggerLevel,
179    #[serde(rename = "dialTimeLimit")]
180    #[serde(default = "build_call_time")]
181    pub max_call_time: u16,
182    #[serde(rename = "dialTimeout")]
183    #[serde(default = "build_ring_time")]
184    pub ring_time: u8,
185    #[serde(default = "build_tts_vendor")]
186    pub tts_vendor: String,
187    #[serde(default = "build_tts_language")]
188    #[serde(rename = "ttsLanguageV2")]
189    pub tts_language: String,
190    #[serde(default = "build_tts_voice")]
191    pub tts_voice: String,
192    #[serde(default = "build_asr_vendor")]
193    pub asr_vendor: String,
194    #[serde(default = "build_asr_language")]
195    pub asr_language: String,
196    #[serde(default = "build_default_timezone")]
197    pub time_zone: String,
198    #[serde(default = "build_country_code")]
199    pub country_code: String,
200    #[serde(default = "build_record_retention")]
201    pub recording_retention: String,
202    pub ingress_script: Option<String>,
203}
204
205impl Environment {
206    pub fn country_code_parsed(&self) -> Id {
207        self.country_code.parse().unwrap_or_else(|_| country::GB)
208    }
209}
210impl Default for Environment {
211    fn default() -> Self {
212        Self {
213            logger: LoggerLevel::Warn,
214            max_call_time: DEFAULT_CALL_TIME,
215            ring_time: DEFAULT_RING_TIME,
216            tts_vendor: DEFAULT_TTS_VENDOR.to_string(),
217            tts_language: DEFAULT_TTS_LANGUAGE.to_string(),
218            tts_voice: DEFAULT_TTS_VOICE.to_string(),
219            asr_vendor: DEFAULT_ASR_VENDOR.to_string(),
220            asr_language: DEFAULT_ASR_LANGUAGE.to_string(),
221            time_zone: DEFAULT_TIMEZONE.to_string(),
222            country_code: DEFAULT_COUNTRY_CODE.to_string(),
223            recording_retention: DEFAULT_RECORDING_RETENTION.to_string(),
224            ingress_script: None,
225        }
226    }
227}
228
229#[derive(Serialize, Deserialize, Clone)]
230#[serde(rename_all = "camelCase")]
231pub struct SpendCap {
232    #[serde(default = "build_spend_cap_value")]
233    value: u16,
234    #[serde(default = "build_spend_cap_level")]
235    warn: u8,
236    #[serde(default = "build_spend_cap_action")]
237    action: RouteAction,
238    #[serde(default)]
239    email_recipients: Vec<String>,
240}
241
242impl Default for SpendCap {
243    fn default() -> Self {
244        Self {
245            value: 100,
246            warn: 80,
247            action: RouteAction::Warn,
248            email_recipients: Vec::new(),
249        }
250    }
251}
252
253#[derive(Serialize, Deserialize, Clone)]
254#[serde(rename_all = "camelCase")]
255pub struct Concurrency {
256    #[serde(rename = "type")]
257    #[serde(default = "build_license")]
258    license: Licence,
259    #[serde(default = "build_concurrency_action")]
260    action: RouteAction,
261    #[serde(default)]
262    email_recipients: Vec<String>,
263}
264
265#[derive(Serialize, Deserialize, Clone)]
266#[serde(rename_all = "camelCase")]
267pub struct ClassOfService {
268    #[serde(rename = "type")]
269    #[serde(default = "build_cos_action")]
270    license: COSAction,
271    #[serde(default)]
272    countries: Vec<String>,
273    #[serde(default)]
274    prefix_exceptions: String,
275    #[serde(rename = "maxPPM")]
276    #[serde(default = "build_cos_ppm")]
277    max_ppm: f32,
278    #[serde(rename = "maxPPC")]
279    #[serde(default = "build_cos_ppc")]
280    max_ppc: f32,
281}
282
283impl Default for ClassOfService {
284    fn default() -> Self {
285        Self {
286            license: COSAction::Allow,
287            countries: Vec::new(),
288            prefix_exceptions: String::from(""),
289            max_ppc: 10.00,
290            max_ppm: 10.00,
291        }
292    }
293}
294
295#[derive(Serialize, Deserialize, Clone)]
296pub enum LoggerLevel {
297    #[serde(rename = "info")]
298    Info,
299    #[serde(rename = "warn")]
300    Warn,
301    #[serde(rename = "error")]
302    Error,
303}
304
305#[derive(Serialize, Deserialize, Clone)]
306pub enum Licence {
307    #[serde(rename = "standard")]
308    Standard,
309    #[serde(rename = "professional")]
310    Professional,
311    #[serde(rename = "enterprise")]
312    Enterprise,
313}
314
315#[derive(Serialize, Deserialize, Clone)]
316pub enum COSAction {
317    #[serde(rename = "DENY")]
318    Deny,
319    #[serde(rename = "ALLOW")]
320    Allow,
321}
322
323#[derive(Serialize, Deserialize, Clone)]
324pub enum RouteAction {
325    #[serde(rename = "warn")]
326    Warn,
327    #[serde(rename = "restrict")]
328    Restrict,
329    #[serde(rename = "deny")]
330    Deny,
331}
332
333#[derive(Serialize, Deserialize, Clone)]
334#[serde(rename_all = "camelCase")]
335pub struct TeamsAccount {
336    #[serde(rename = "type")]
337    pub domain_type: String,
338    #[serde(default)]
339    pub domain: String,
340    pub txt: Option<String>,
341    #[serde(rename = "serverA")]
342    pub server_a: String,
343    #[serde(rename = "serverB")]
344    pub server_b: String,
345}
346
347impl Default for TeamsAccount {
348    fn default() -> Self {
349        Self {
350            domain_type: String::from("callable"),
351            domain: String::from(""),
352            server_a: String::from(""),
353            server_b: String::from(""),
354            txt: None,
355        }
356    }
357}
358
359#[derive(Serialize, Deserialize, Clone)]
360#[serde(rename_all = "camelCase")]
361pub struct Address {
362    #[serde(default)]
363    pub line1: String,
364    #[serde(default)]
365    pub line2: String,
366    #[serde(default)]
367    pub level1: String,
368    #[serde(default)]
369    pub level2: String,
370    #[serde(default)]
371    pub postal_code: String,
372    #[serde(default)]
373    pub country: String,
374}
375
376impl Default for Address {
377    fn default() -> Self {
378        Self {
379            line1: String::from(""),
380            line2: String::from(""),
381            level1: String::from(""),
382            level2: String::from(""),
383            postal_code: String::from(""),
384            country: String::from(""),
385        }
386    }
387}
388
389#[derive(Serialize, Deserialize, Clone)]
390#[serde(rename_all = "camelCase")]
391pub struct Asset {
392    id: String,
393    bucket: String,
394    key: String,
395    filename: String,
396    name: String,
397    mime_type: String,
398    size: u32,
399    created: String,
400    #[serde(default)]
401    meta: HashMap<String, String>,
402}
403
404#[derive(Serialize, Deserialize, Clone)]
405#[serde(rename_all = "camelCase")]
406pub struct Setting {
407    #[serde(default)]
408    pub id: String,
409    pub key: String,
410    #[serde(rename = "type")]
411    pub setting_type: String,
412    pub value: String,
413}
414
415#[derive(Serialize, Deserialize, Debug, Clone)]
416#[serde(rename_all = "camelCase")]
417pub struct DDI {
418    pub id: String,
419    pub name: String,
420    #[serde(default)]
421    pub meta: HashMap<String, String>,
422}
423
424#[derive(Serialize, Deserialize, Clone)]
425#[serde(rename_all = "camelCase")]
426pub struct Trunk {
427    pub id: String,
428    pub ip: String,
429    #[serde(default = "build_trunk_description")]
430    pub description: String,
431    #[serde(default = "build_trunk_port")]
432    pub port: u16,
433}
434
435#[derive(Serialize, Deserialize, Clone)]
436#[serde(rename_all = "camelCase")]
437pub struct Hook {
438    pub id: String,
439    pub app: String,
440    pub url: String,
441    #[serde(default = "AuthType::default_method")]
442    pub auth_type: AuthType,
443    #[serde(default = "HookMethod::default_method")]
444    pub method: HookMethod,
445    #[serde(default)]
446    pub meta: HashMap<String, String>,
447    #[serde(default)]
448    pub api_key_name: String,
449    #[serde(default)]
450    pub api_key_value: String,
451    #[serde(default)]
452    pub api_secret_name: String,
453    #[serde(default)]
454    pub api_secret_value: String,
455}
456
457#[derive(Serialize, Deserialize, Clone)]
458pub enum HookMethod {
459    #[serde(rename = "POST")]
460    Post,
461    #[serde(rename = "GET")]
462    Get,
463}
464
465#[derive(Serialize, Deserialize, Clone)]
466pub enum QueueItemType {
467    #[serde(rename = "play")]
468    Play,
469    #[serde(rename = "say")]
470    Say,
471    #[serde(rename = "pause")]
472    Pause,
473}
474
475impl HookMethod {
476    fn default_method() -> Self {
477        HookMethod::Post
478    }
479}
480
481#[derive(Serialize, Deserialize, Clone)]
482pub enum AuthType {
483    #[serde(rename = "DISABLED")]
484    Disabled,
485    #[serde(rename = "KEY")]
486    Key,
487    #[serde(rename = "KEY_SECRET")]
488    KeySecret,
489    #[serde(rename = "BASIC_AUTH")]
490    BasicAuth,
491}
492
493impl AuthType {
494    fn default_method() -> Self {
495        AuthType::Disabled
496    }
497}
498
499impl Connector for Device {
500    fn get_connect_to(&mut self, state: &mut FlowState) -> FlowState {
501        match self {
502            Device::InboundFlow(value) => value.get_connect_to(state),
503            Device::OutboundFlow(value) => value.get_connect_to(state),
504            Device::AppFlow(value) => value.get_connect_to(state),
505            Device::WhatsAppFlow(value) => value.get_connect_to(state),
506            Device::AniRouter(value) => value.get_connect_to(state),
507            Device::DnisRouter(value) => value.get_connect_to(state),
508            Device::DigitRouter(value) => value.get_connect_to(state),
509            Device::TimeRangeRouter(value) => value.get_connect_to(state),
510            Device::DayOfWeekRouter(value) => value.get_connect_to(state),
511            Device::DateRangeRouter(value) => value.get_connect_to(state),
512            Device::Play(value) => value.get_connect_to(state),
513            Device::Say(value) => value.get_connect_to(state),
514            Device::Voicemail(value) => value.get_connect_to(state),
515            Device::Script(value) => value.get_connect_to(state),
516            Device::Queue(value) => value.get_connect_to(state),
517            Device::Sms(value) => value.get_connect_to(state),
518            Device::Email(value) => value.get_connect_to(state),
519            Device::Tag(value) => value.get_connect_to(state),
520            Device::TagRouter(value) => value.get_connect_to(state),
521            Device::Service(value) => value.get_connect_to(state),
522            _ => state.clone(),
523        }
524    }
525}
526
527fn build_asr_vendor() -> String {
528    String::from(DEFAULT_ASR_VENDOR)
529}
530
531fn build_asr_language() -> String {
532    String::from(DEFAULT_ASR_LANGUAGE)
533}
534
535fn build_tts_vendor() -> String {
536    String::from(DEFAULT_TTS_VENDOR)
537}
538
539fn build_tts_language() -> String {
540    String::from(DEFAULT_TTS_LANGUAGE)
541}
542
543fn build_tts_voice() -> String {
544    String::from(DEFAULT_TTS_VOICE)
545}
546
547fn build_default_timezone() -> String {
548    String::from(DEFAULT_TIMEZONE)
549}
550
551fn build_trunk_description() -> String {
552    String::from(DEFAULT_TRUNK_DESCRIPTION)
553}
554
555fn build_trunk_port() -> u16 {
556    DEFAULT_TRUNK_PORT
557}
558
559fn build_country_code() -> String {
560    String::from(DEFAULT_COUNTRY_CODE)
561}
562
563fn build_logger() -> LoggerLevel {
564    LoggerLevel::Warn
565}
566
567fn build_call_time() -> u16 {
568    DEFAULT_CALL_TIME
569}
570
571fn build_ring_time() -> u8 {
572    DEFAULT_RING_TIME
573}
574
575fn build_spend_cap_value() -> u16 {
576    100
577}
578
579fn build_spend_cap_level() -> u8 {
580    80
581}
582
583fn build_spend_cap_action() -> RouteAction {
584    RouteAction::Warn
585}
586
587fn build_concurrency_action() -> RouteAction {
588    RouteAction::Warn
589}
590
591fn build_cos_action() -> COSAction {
592    COSAction::Allow
593}
594
595fn build_cos_ppm() -> f32 {
596    15.00
597}
598
599fn build_cos_ppc() -> f32 {
600    15.00
601}
602
603fn build_license() -> Licence {
604    Licence::Standard
605}
606
607fn build_record_retention() -> String {
608    String::from(DEFAULT_RECORDING_RETENTION)
609}
610// #[test]
611// fn account_json() {
612//     let file = File::open("./assets/account-data.json").expect("file should open read only");
613//
614//     let account: Account = serde_json::from_reader(file).expect("file should be proper JSON");
615//
616//     println!("{:#?}", account);
617//
618//     for dev in &account.devices {
619//         if dev.is_connector() {
620//             if dev.connect_to().ne("HANGUP") {
621//                 let device = dev.connect(&account);
622//                 assert_eq!(device.is_none(), false);
623//             }
624//         }
625//     }
626// }