dialtone_common 0.1.0

Dialtone Common Code
Documentation
use crate::rest::sites::theme::Theme;
use crate::rest::users::web_user::UserStatus::PendingApproval;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_variant::to_variant_name;
use std::fmt;
use std::str::FromStr;

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
/// Represents a web users. Does not include authentication data.
pub struct WebUser {
    pub user_authz: UserAuthorization,
    pub preferences: Option<UserPrefs>,
    pub last_seen_data: Vec<LastSeenData>,
    pub last_login_data: Vec<LastLoginData>,
    pub status: UserStatus,
    pub created_at: DateTime<Utc>,
    pub modified_at: DateTime<Utc>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct UserAuthorization {
    /// An account is the unique identifier for a users
    /// principal. It is in the form "users@host" such as
    /// "bob@example.com"
    pub acct: String,
    pub system_permissions: Vec<SystemPermission>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct UserPrefs {
    pub theme: Theme,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct LastSeenData {
    pub from: String,
    pub at: DateTime<Utc>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct LastLoginData {
    pub from: String,
    pub at: DateTime<Utc>,
    pub success: bool,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub enum UserStatus {
    Active,
    Suspended,

    #[serde(rename = "Pending Approval")]
    PendingApproval,
}

impl Default for UserStatus {
    fn default() -> Self {
        PendingApproval
    }
}

impl fmt::Display for UserStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", to_variant_name(&self).unwrap())
    }
}

impl FromStr for UserStatus {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let s = s.to_lowercase();
        match s {
            a if a == UserStatus::Active.to_string().to_lowercase() => Ok(UserStatus::Active),
            a if a == UserStatus::Suspended.to_string().to_lowercase() => Ok(UserStatus::Suspended),
            a if a == UserStatus::PendingApproval.to_string().to_lowercase() => {
                Ok(UserStatus::PendingApproval)
            }
            _ => Err("no matching users status"),
        }
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub enum SystemRole {
    #[serde(rename = "User Administrator")]
    UserAdmin,

    #[serde(rename = "Actor Administrator")]
    ActorAdmin,

    #[serde(rename = "Content Administrator")]
    ContentAdmin,
}

impl fmt::Display for SystemRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SystemRole::UserAdmin => write!(f, "User Administrator"),
            SystemRole::ActorAdmin => write!(f, "Actor Administrator"),
            SystemRole::ContentAdmin => write!(f, "Content Administrator"),
        }
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct SystemPermission {
    pub role: SystemRole,
    pub host_name: String,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct UserSystemInfo {
    pub system_data: Option<UserSystemData>,
    pub created_at: DateTime<Utc>,
    pub modified_at: DateTime<Utc>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct UserSystemData {}

#[cfg(test)]
mod web_user_tests {
    use super::*;

    #[test]
    fn roundtrip_serde() {
        let w = super::UserAuthorization {
            acct: "bob@test.example".to_string(),
            system_permissions: vec![SystemPermission {
                role: SystemRole::ActorAdmin,
                host_name: "example.com".to_string(),
            }],
        };
        let j = serde_json::to_string(&w);
        let w2 = serde_json::from_str(&j.unwrap()).unwrap();
        assert_eq!(w, w2)
    }
}