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