use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IWProperties {
pub database_id: String,
pub lang: String,
pub version: String,
pub encryption_count: u32,
pub sync_timestamp: Option<DateTime<Utc>>,
pub update_timestamp: Option<DateTime<Utc>>,
}
impl Default for IWProperties {
fn default() -> Self {
Self {
database_id: String::new(),
lang: "en".to_string(),
version: crate::DB_VERSION.to_string(),
encryption_count: crate::ENCRYPTION_COUNT_DEFAULT,
sync_timestamp: None,
update_timestamp: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IWItem {
pub item_id: String,
pub parent_id: Option<String>,
pub name: String,
pub icon: String,
pub folder: bool,
pub create_timestamp: DateTime<Utc>,
pub change_timestamp: DateTime<Utc>,
pub deleted: bool,
}
impl IWItem {
pub fn is_root(&self) -> bool {
self.item_id == crate::ROOT_ID
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IWField {
pub item_id: String,
pub field_id: String,
pub field_type: String,
pub value: String,
pub label: String,
pub icon: String,
pub value_type: String,
pub sort_weight: i32,
pub change_timestamp: DateTime<Utc>,
pub deleted: bool,
pub expired: bool,
pub expiring: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IWLabel {
pub field_type: String,
pub name: String,
pub value_type: String,
pub icon: String,
pub system: bool,
pub change_timestamp: DateTime<Utc>,
pub deleted: bool,
pub usage: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IWIcon {
pub icon_id: String,
pub name: String,
pub group_id: i32,
pub is_circle: bool,
pub deleted: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IWGroup {
pub group_id: i32,
pub name: String,
pub deleted: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchResult {
pub item: IWItem,
pub matching_fields: Vec<IWField>,
pub match_type: SearchMatchType,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum SearchMatchType {
Name,
Field,
Both,
}
pub const SYSTEM_FIELD_TYPES: &[(&str, &str, &str, &str)] = &[
("MAIL", "mail", "icon_mail", "label_email"),
("PASS", "pass", "icon_pass", "label_password"),
("NOTE", "text", "icon_note", "label_note"),
("LINK", "link", "icon_link", "label_link"),
("ACNT", "text", "icon_account", "label_account"),
("CARD", "text", "icon_card", "label_card"),
("NAME", "text", "icon_name", "label_name"),
("PHON", "phon", "icon_phone", "label_phone"),
("PINC", "pass", "icon_pin", "label_pin"),
("USER", "text", "icon_user", "label_username"),
("OLDP", "pass", "icon_oldpass", "label_old_password"),
("DATE", "date", "icon_date", "label_date"),
("TIME", "time", "icon_time", "label_time"),
("EXPD", "date", "icon_expiry", "label_expiry_date"),
("SNUM", "text", "icon_serial", "label_serial_number"),
("ADDR", "text", "icon_address", "label_address"),
("SQUE", "text", "icon_question", "label_secret_question"),
("SANS", "pass", "icon_answer", "label_secret_answer"),
("2FAC", "pass", "icon_2fa", "label_2fa"),
("SEED", "text", "icon_seed", "label_seed"),
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_properties_default() {
let props = IWProperties::default();
assert_eq!(props.lang, "en");
assert_eq!(props.version, crate::DB_VERSION);
assert_eq!(props.encryption_count, crate::ENCRYPTION_COUNT_DEFAULT);
assert!(props.database_id.is_empty());
assert!(props.sync_timestamp.is_none());
assert!(props.update_timestamp.is_none());
}
#[test]
fn test_item_is_root() {
let root_item = IWItem {
item_id: crate::ROOT_ID.to_string(),
parent_id: None,
name: "Root".to_string(),
icon: "folder".to_string(),
folder: true,
create_timestamp: Utc::now(),
change_timestamp: Utc::now(),
deleted: false,
};
assert!(root_item.is_root());
let regular_item = IWItem {
item_id: "abc12345".to_string(),
parent_id: Some(crate::ROOT_ID.to_string()),
name: "Test".to_string(),
icon: "document".to_string(),
folder: false,
create_timestamp: Utc::now(),
change_timestamp: Utc::now(),
deleted: false,
};
assert!(!regular_item.is_root());
}
#[test]
fn test_search_match_type() {
assert_eq!(SearchMatchType::Name, SearchMatchType::Name);
assert_eq!(SearchMatchType::Field, SearchMatchType::Field);
assert_eq!(SearchMatchType::Both, SearchMatchType::Both);
assert_ne!(SearchMatchType::Name, SearchMatchType::Field);
}
#[test]
fn test_system_field_types_count() {
assert_eq!(SYSTEM_FIELD_TYPES.len(), 20);
}
}