#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use errors::*;
use regex::Regex;
pub use scaffolding_macros::*;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
pub use serde_derive::{Deserialize, Serialize};
pub use std::collections::BTreeMap;
use serde_json::Value;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ActivityItem {
pub created_dtm: i64,
pub action: String,
pub description: String,
}
impl ActivityItem {
pub fn new(name: String, descr: String) -> Self {
Self {
created_dtm: defaults::now(),
action: name,
description: descr,
}
}
pub fn deserialized(serialized: &[u8]) -> Result<ActivityItem, DeserializeError> {
match serde_json::from_slice(&serialized) {
Ok(item) => Ok(item),
Err(err) => {
println!("{}", err);
Err(DeserializeError)
}
}
}
pub fn serialize(&mut self) -> String {
serde_json::to_string(&self).unwrap()
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Address {
pub id: String,
pub created_dtm: i64,
pub modified_dtm: i64,
pub category: String,
pub line_1: String,
pub line_2: String,
pub line_3: String,
pub line_4: String,
pub country_code: String,
}
impl Address {
pub fn new(
category: String,
line_1: String,
line_2: String,
line_3: String,
line_4: String,
country_code: String,
) -> Self {
Self {
id: defaults::id(),
created_dtm: defaults::now(),
modified_dtm: defaults::now(),
category: category,
line_1: line_1,
line_2: line_2,
line_3: line_3,
line_4: line_4,
country_code: country_code,
}
}
pub fn deserialized(serialized: &[u8]) -> Result<Address, DeserializeError> {
match serde_json::from_slice(&serialized) {
Ok(item) => Ok(item),
Err(err) => {
println!("{}", err);
Err(DeserializeError)
}
}
}
pub fn serialize(&mut self) -> String {
serde_json::to_string(&self).unwrap()
}
pub fn update(
&mut self,
category: String,
line_1: String,
line_2: String,
line_3: String,
line_4: String,
country_code: String,
) {
self.category = category;
self.line_1 = line_1;
self.line_2 = line_2;
self.line_3 = line_3;
self.line_4 = line_4;
self.country_code = country_code;
self.modified_dtm = defaults::now();
}
}
pub struct Countries {
pub list: Vec<Country>,
}
impl Countries {
pub fn new() -> Self {
let data = include_str!("countries.json");
let array: Value = serde_json::from_str(data).unwrap();
let countries: Vec<Country> = array
.as_array()
.unwrap()
.iter()
.map(|c| {
Country::new(
c["country_name"].as_str().unwrap().to_string(),
c["phone_code"].as_str().unwrap().to_string(),
c["iso_2_code"].as_str().unwrap().to_string(),
c["iso_3_code"].as_str().unwrap().to_string(),
)
})
.collect();
Self { list: countries }
}
pub fn is_valid(&self, country: Country) -> bool {
let found = self.list.iter().filter(|c| {
c.name == country.name
&& c.phone_code == country.phone_code
&& c.iso_2_code == country.iso_2_code
&& c.iso_3_code == country.iso_3_code
});
match found.count() {
0 => return false,
_ => return true,
}
}
pub fn get_country_by_iso_2_code(&self, iso_2_code: String) -> Option<&Country> {
let found = self.list.iter().filter(|c| c.iso_2_code == iso_2_code);
return found.last();
}
pub fn get_country_by_iso_3_code(&self, iso_3_code: String) -> Option<&Country> {
let found = self.list.iter().filter(|c| c.iso_3_code == iso_3_code);
return found.last();
}
pub fn get_country_by_phone_code(&self, phone_code: String) -> Option<&Country> {
let found = self.list.iter().filter(|c| c.phone_code == phone_code);
return found.last();
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Country {
pub name: String,
pub phone_code: String,
pub iso_2_code: String,
pub iso_3_code: String,
}
impl Country {
pub fn new(name: String, phone_code: String, iso_2_code: String, iso_3_code: String) -> Self {
Self {
name: name,
phone_code: phone_code,
iso_2_code: iso_2_code,
iso_3_code: iso_3_code,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EmailAddress {
pub id: String,
pub created_dtm: i64,
pub modified_dtm: i64,
pub category: String,
pub address: String,
}
impl EmailAddress {
pub fn new(category: String, address: String) -> Self {
Self {
id: defaults::id(),
created_dtm: defaults::now(),
modified_dtm: defaults::now(),
category: category,
address: address,
}
}
pub fn deserialized(serialized: &[u8]) -> Result<EmailAddress, DeserializeError> {
match serde_json::from_slice(&serialized) {
Ok(item) => Ok(item),
Err(err) => {
println!("{}", err);
Err(DeserializeError)
}
}
}
pub fn is_valid(&self) -> bool {
let exp = r#"(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])"#;
let re = Regex::new(exp).unwrap();
re.is_match(&self.address)
}
pub fn serialize(&mut self) -> String {
serde_json::to_string(&self).unwrap()
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Note {
pub id: String,
pub created_dtm: i64,
pub modified_dtm: i64,
pub author: String,
pub access: String,
pub content: Vec<u8>,
}
impl Note {
pub fn new(auth: String, cont: Vec<u8>, acc: Option<String>) -> Self {
Self {
id: defaults::id(),
created_dtm: defaults::now(),
modified_dtm: defaults::now(),
author: auth,
access: match acc {
Some(a) => a,
None => defaults::access(),
},
content: cont,
}
}
pub fn content_as_string(&self) -> Result<String, String> {
String::from_utf8(self.content.clone())
.map_err(|non_utf8| String::from_utf8_lossy(non_utf8.as_bytes()).into_owned())
}
pub fn deserialized(serialized: &[u8]) -> Result<Note, DeserializeError> {
match serde_json::from_slice(&serialized) {
Ok(item) => Ok(item),
Err(err) => {
println!("{}", err);
Err(DeserializeError)
}
}
}
pub fn serialize(&mut self) -> String {
serde_json::to_string(&self).unwrap()
}
pub fn update(&mut self, auth: String, cont: Vec<u8>, acc: Option<String>) {
self.author = auth;
self.content = cont;
self.access = match acc {
Some(a) => a,
None => self.access.clone(),
};
self.modified_dtm = defaults::now();
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PhoneNumber {
pub id: String,
pub created_dtm: i64,
pub modified_dtm: i64,
pub category: String,
pub number: String,
pub country_code: String,
}
impl PhoneNumber {
pub fn new(category: String, number: String, country_code: String) -> Self {
Self {
id: defaults::id(),
created_dtm: defaults::now(),
modified_dtm: defaults::now(),
category: category,
number: number,
country_code: country_code,
}
}
pub fn deserialized(serialized: &[u8]) -> Result<PhoneNumber, DeserializeError> {
match serde_json::from_slice(&serialized) {
Ok(item) => Ok(item),
Err(err) => {
println!("{}", err);
Err(DeserializeError)
}
}
}
pub fn serialize(&mut self) -> String {
serde_json::to_string(&self).unwrap()
}
}
pub trait Scaffolding {
fn log_activity(&mut self, name: String, descr: String);
fn get_activity(&self, name: String) -> Vec<ActivityItem>;
fn deserialized(serialized: &[u8]) -> Result<Self, DeserializeError>
where
Self: DeserializeOwned,
{
match serde_json::from_slice::<Self>(&serialized) {
Ok(item) => Ok(item),
Err(err) => {
println!("{}", err);
Err(DeserializeError)
}
}
}
fn serialize(&mut self) -> String
where
Self: Serialize,
{
serde_json::to_string(&self).unwrap()
}
}
pub trait ScaffoldingAddresses {
fn get_address(&self, id: String) -> Option<&Address>;
fn insert_address(
&mut self,
category: String,
line_1: String,
line_2: String,
line_3: String,
line_4: String,
country_code: String,
) -> String;
fn modify_address(
&mut self,
id: String,
category: String,
line_1: String,
line_2: String,
line_3: String,
line_4: String,
country_code: String,
);
fn search_addresses_by_category(&self, category: String) -> Vec<Address>;
fn remove_address(&mut self, id: String);
}
pub trait ScaffoldingEmailAddresses {
fn get_email_address(&self, id: String) -> Option<&EmailAddress>;
fn insert_email_address(&mut self, category: String, address: String) -> String;
fn search_email_addresses_by_category(&self, category: String) -> Vec<EmailAddress>;
fn remove_email_address(&mut self, id: String);
}
pub trait ScaffoldingNotes {
fn get_note(&self, id: String) -> Option<&Note>;
fn insert_note(&mut self, auth: String, cont: Vec<u8>, acc: Option<String>) -> String;
fn modify_note(&mut self, id: String, auth: String, cont: Vec<u8>, acc: Option<String>);
fn search_notes(&mut self, search: String) -> Vec<Note>;
fn remove_note(&mut self, id: String);
}
pub trait ScaffoldingPhoneNumbers {
fn get_phone_number(&self, id: String) -> Option<&PhoneNumber>;
fn insert_phone_number(
&mut self,
category: String,
number: String,
country_code: String,
) -> String;
fn search_phone_numbers_by_category(&self, category: String) -> Vec<PhoneNumber>;
fn remove_phone_number(&mut self, id: String);
}
pub trait ScaffoldingTags {
fn add_tag(&mut self, tag: String);
fn has_tag(&self, tag: String) -> bool;
fn remove_tag(&mut self, tag: String);
}
pub mod defaults;
pub mod errors;
#[cfg(test)]
mod tests {
use crate::{defaults, ActivityItem};
fn get_actionitem() -> ActivityItem {
ActivityItem::new(
"updated".to_string(),
"The object has been updated.".to_string(),
)
}
#[test]
fn test_activityitem_new() {
let ai = get_actionitem();
assert_eq!(ai.created_dtm, defaults::now());
assert_eq!(ai.action, "updated".to_string());
assert_eq!(ai.description, "The object has been updated.".to_string());
}
#[test]
fn test_activityitem_serialization() {
let serialized = r#"{"created_dtm":1711760135,"action":"updated","description":"The object has been updated."}"#;
let mut ai = ActivityItem::deserialized(&serialized.as_bytes()).unwrap();
assert_eq!(ai.created_dtm, 1711760135);
assert_eq!(ai.action, "updated".to_string());
assert_eq!(ai.description, "The object has been updated.".to_string());
assert_eq!(ai.serialize(), serialized);
}
}