use super::FontAwesomeIcon;
use crate::{prelude::*, util::*};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
pub struct ContactLink {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fontawesome_icon: Option<FontAwesomeIcon>,
#[serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_string_or_number_to_u64",
default
)]
pub id: Option<u64>,
}
impl CreateFromJson for ContactLink {}
impl ConfigObject for ContactLink {
type Builder = ContactLinkBuilder;
fn builder() -> Self::Builder {
ContactLinkBuilder::new()
}
fn config_path() -> Option<String> {
None
}
fn unique_name(&self) -> String {
if self.url.as_ref().is_some_and(|u| u.len() < 5) {
return format!("{}_{}", self.name, self.url.as_ref().unwrap());
} else if self.url.as_ref().is_some() {
return format!(
"{}_{}",
self.name,
&self.url.as_ref().unwrap()[self.url.as_ref().unwrap().len() - 5..]
);
}
self.name.clone()
}
fn minimal(name: &str) -> Result<Self, OpsviewConfigError> {
Ok(Self {
name: validate_and_trim_contactlink_name(name)?,
..Default::default()
})
}
}
#[derive(Clone, Debug, Default)]
pub struct ContactLinkBuilder {
name: Option<String>,
url: Option<String>,
fontawesome_icon: Option<FontAwesomeIcon>,
}
impl Builder for ContactLinkBuilder {
type ConfigObject = ContactLink;
fn new() -> Self {
Self::default()
}
fn name(mut self, name: &str) -> Self {
self.name = Some(name.to_string());
self
}
fn build(self) -> Result<Self::ConfigObject, OpsviewConfigError> {
let name = require_field(&self.name, "name")?;
let url = require_field(&self.url, "url")?;
Ok(ContactLink {
name: validate_and_trim_contactlink_name(&name)?,
url: Some(validate_and_trim_contactlink_url(&url)?),
fontawesome_icon: self.fontawesome_icon,
id: None,
})
}
}
impl ContactLinkBuilder {
pub fn clear_name(mut self) -> Self {
self.name = None;
self
}
pub fn clear_url(mut self) -> Self {
self.url = None;
self
}
pub fn clear_fontawesome_icon(mut self) -> Self {
self.fontawesome_icon = None;
self
}
pub fn url(mut self, url: &str) -> Self {
self.url = Some(url.to_string());
self
}
pub fn fontawesome_icon(mut self, fontawesome_icon: FontAwesomeIcon) -> Self {
self.fontawesome_icon = Some(fontawesome_icon);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default() {
let contactlink = ContactLink::default();
assert!(contactlink.name.is_empty());
}
#[test]
fn test_minimal() {
let contactlink = ContactLink::minimal("My Contact Link")
.expect("Failed to create a minimal ContactLink");
assert_eq!(contactlink.name, "My Contact Link".to_string());
}
#[test]
fn test_minimal_fails_with_invalid_names() {
let valid_contact_link = ContactLink::minimal("My Contact Link 1");
assert!(
valid_contact_link.is_ok(),
"Valid contact link should be OK"
);
let invalid_characters = ["!", "#", "$", "%", "&"];
for &char in invalid_characters.iter() {
let contact_link_name = format!("My Contact Link 1{}", char);
let contact_link = ContactLink::minimal(&contact_link_name);
assert!(
contact_link.is_err(),
"Contact link with '{}' should be Err",
char
);
}
}
#[test]
fn test_build_fails_with_invalid_name() {
let valid_url = "/monitoring/#!/allproblems?cid=mxUQoVgjyu273hJ8".to_string();
let base_name = "My Contact Link 1";
let invalid_characters = ["!", "#", "$", "%", "&"];
let build_and_assert = |name: &str, should_succeed: bool| {
let result = ContactLink::builder().name(name).url(&valid_url).build();
match should_succeed {
true => assert!(result.is_ok(), "Expected OK for valid name: {}", name),
false => assert!(result.is_err(), "Expected Err for invalid name: {}", name),
}
};
build_and_assert(base_name, true);
for invalid_char in invalid_characters.iter() {
let invalid_name = format!("{}{}", base_name, invalid_char);
build_and_assert(&invalid_name, false);
}
}
}