comment_app_frontend 0.1.3

A Comment App Front End Server
Documentation
// reply.rs
// reply functions are implemented here

use serde_derive::{Serialize, Deserialize};

use crate::models::user::User;


#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Reply {
    // attributes from server are:
    pub message: String,

    #[serde(default = "default_anonym")]
    pub anonymous: bool,

    #[serde(default = "String::new")]
    pub unique_id: String,

    #[serde(default = "String::new")]
    pub parent_id: String,

    #[serde(default = "String::new")]
    pub comment_id: String,

    pub level: u32, // hierarchy level; first reply is at level 0, reply of reply is 1, so on

    #[serde(default = "String::new")]
    pub user_id: String,

    #[serde(default = "String::new")]
    pub created_on: String,

    // derived attributes for UI are:
    #[serde(default = "default_user")]
    pub user: User,

    #[serde(default = "default_session_user")]
    pub session_user: User,

    #[serde(default = "Vec::new")]
    pub replies: Vec<Reply>,

    #[serde(default = "default_enable")]
    pub enabled: bool,  // is the comments enabled to add replies

    #[serde(default = "default_editability")]
    pub editable: bool, // is the reply editable (by the commenter or original author or creator)

    #[serde(default = "default_trashability")]
    pub trashable: bool, // is the reply trashable (by the commenter or original author or creator)

    #[serde(default = "String::new")]
    pub more_message: String, // remaining message text

    #[serde(default = "default_has_more_message")]
    pub has_more_message: bool, // enable to show 'more' on the web page

    #[serde(default = "default_replies_count")]
    pub replies_count: usize, // initially show replies count only

    #[serde(default = "default_has_replies")]
    pub has_replies: bool, // enable to show replies on the web page

    #[serde(default = "default_upvotes_count")]
    pub upvotes_count: usize, 

    #[serde(default = "default_downvotes_count")]
    pub downvotes_count: usize, 

    #[serde(default = "String::new")]
    pub time_ago: String, 

    #[serde(default = "default_show_dropdown")]
    pub show_dropdown: bool, // enable to show replies on the web page

}

fn default_anonym() -> bool {
    false
}
fn default_user() -> User {
    User::default()
}
fn default_session_user() -> User {
    User::default()
}
fn default_enable() -> bool {
    true
}
fn default_editability() -> bool {
    false
}
fn default_trashability() -> bool {
    false
}
fn default_has_more_message() -> bool {
    false
}
fn default_replies_count() -> usize {
    0usize
}
fn default_has_replies() -> bool {
    false
}
fn default_upvotes_count() -> usize {
    0usize
}
fn default_downvotes_count() -> usize {
    0usize
}
fn default_show_dropdown() -> bool {
    false
}

impl Reply {
    pub fn from(message: &str, is_anonymous: bool, parent_id: &str, comment_id: &str, level: u32, user_id: &str) -> Reply {
        Reply {
            message: message.to_string(),
            anonymous: is_anonymous,
            unique_id: String::new(),
            parent_id: parent_id.to_string(),
            comment_id: comment_id.to_string(),
            level: level,
            user_id: user_id.to_string(),
            created_on: String::new(),
            user: User::default(), // owner/creator of the reply
            session_user: User::default(), // viewer of the comment; may add reply to this comment
            replies: Vec::new(),
            enabled: true,
            editable: false,
            trashable: false,
            more_message: String::new(), // remaining message text
            has_more_message: false, // if false, more_message field is empty
            replies_count: 0, // default value is 0
            has_replies: false, 
            upvotes_count: 0, // default upvote count is 0 
            downvotes_count: 0, // default downvote count is 0             
            time_ago: String::new(), // Difference in time between Local::now() and created_on
            show_dropdown: false,
        }
    }

    pub fn tree_from(replies: Vec<Reply>, max_replies: usize) -> Vec<Reply> {
        let mut result = Vec::new();
        let root_replies: Vec<Reply> = replies.clone().into_iter().filter(|each| each.level == 0).collect();
        let non_root_replies: Vec<Reply> = replies.clone().into_iter().filter(|each| each.level > 0).collect();
        for mut reply in root_replies.clone() {
            reply.replies = Self::get_children_for(reply.clone(), non_root_replies.clone(), max_replies.clone());
            reply.replies_count = reply.replies.len();
            reply.has_replies = reply.replies.len() > 0;
            let repliable = reply.replies.len() < max_replies;
            reply.enabled = reply.enabled && repliable;
            result.push(reply);
        }
        result
    }

    fn get_children_for(reply: Reply, replies: Vec<Reply>, max_replies: usize) -> Vec<Reply> {
        let children: Vec<Reply> = replies.clone().into_iter()
            .filter( |each_child| each_child.parent_id == reply.unique_id ).collect();
        let mut result = Vec::new();
        for mut child in children.clone() {
            child.replies = Self::get_children_for(child.clone(), replies.clone(), max_replies.clone());
            child.replies_count = child.replies.len();
            child.has_replies = child.replies.len() > 0;
            let repliable = child.replies.len() < max_replies;
            child.enabled = child.enabled && repliable;
            result.push(child);
        }
        result
    }

}