<commit_before>use chrono::NaiveDateTime;
use diesel::PgConnection;
use std::collections::HashMap;
use url::Url;

use crate::github;
use crate::models::{
    Badge, Category, Crate, CrateOwnerInvitation, CreatedApiToken, Dependency, DependencyKind,
    Keyword, Owner, ReverseDependency, Team, TopVersions, User, Version, VersionDownload,
    VersionOwnerAction,
};
use crate::util::rfc3339;

/// Hosts in this list are known to not be hosting documentation,
/// and are possibly of malicious intent e.g. ad tracking networks, etc.
const DOCUMENTATION_BLOCKLIST: &[&str] = &["rust-ci.org", "rustless.org", "ironframework.io"];

#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct EncodableBadge {
    pub badge_type: String,
    pub attributes: HashMap<String, Option<String>>,
}

impl From<Badge> for EncodableBadge {
    fn from(badge: Badge) -> Self {
        // The serde attributes on Badge ensure it can be deserialized to EncodableBadge
        serde_json::from_value(serde_json::to_value(badge).unwrap()).unwrap()
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCategory {
    pub id: String,
    pub category: String,
    pub slug: String,
    pub description: String,
    #[serde(with = "rfc3339")]
    pub created_at: NaiveDateTime,
    pub crates_cnt: i32,
}

impl From<Category> for EncodableCategory {
    fn from(category: Category) -> Self {
        let Category {
            crates_cnt,
            category,
            slug,
            description,
            created_at,
            ..
        } = category;
        Self {
            id: slug.clone(),
            slug,
            description,
            created_at,
            crates_cnt,
            category: category.rsplit("::").collect::<Vec<_>>()[0].to_string(),
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCategoryWithSubcategories {
    pub id: String,
    pub category: String,
    pub slug: String,
    pub description: String,
    #[serde(with = "rfc3339")]
    pub created_at: NaiveDateTime,
    pub crates_cnt: i32,
    pub subcategories: Vec<EncodableCategory>,
    pub parent_categories: Vec<EncodableCategory>,
}

/// The serialization format for the `CrateOwnerInvitation` model.
#[derive(Deserialize, Serialize, Debug)]
pub struct EncodableCrateOwnerInvitation {
    pub invitee_id: i32,
    pub inviter_id: i32,
    pub invited_by_username: String,
    pub crate_name: String,
    pub crate_id: i32,
    #[serde(with = "rfc3339")]
    pub created_at: NaiveDateTime,
}

impl EncodableCrateOwnerInvitation {
    pub fn from_basic(
        invitation: CrateOwnerInvitation,
        inviter_name: String,
        crate_name: String,
    ) -> Self {
        Self {
            invitee_id: invitation.invited_user_id,
            inviter_id: invitation.invited_by_user_id,
            invited_by_username: inviter_name,
            crate_name,
            crate_id: invitation.crate_id,
            created_at: invitation.created_at,
        }
    }

    pub fn from(invitation: CrateOwnerInvitation, conn: &PgConnection) -> Self {
        let inviter_name = invitation.invited_by_username(conn);
        let crate_name = invitation.crate_name(conn);
        Self::from_basic(invitation, inviter_name, crate_name)
    }
}

#[derive(Deserialize, Serialize, Debug, Copy, Clone)]
pub struct InvitationResponse {<commit_msg>EncodableCrateOwnerInvitation: Remove obsolete `from()` factory function<commit_after>use chrono::NaiveDateTime;
use std::collections::HashMap;
use url::Url;

use crate::github;
use crate::models::{
    Badge, Category, Crate, CrateOwnerInvitation, CreatedApiToken, Dependency, DependencyKind,
    Keyword, Owner, ReverseDependency, Team, TopVersions, User, Version, VersionDownload,
    VersionOwnerAction,
};
use crate::util::rfc3339;

/// Hosts in this list are known to not be hosting documentation,
/// and are possibly of malicious intent e.g. ad tracking networks, etc.
const DOCUMENTATION_BLOCKLIST: &[&str] = &["rust-ci.org", "rustless.org", "ironframework.io"];

#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct EncodableBadge {
    pub badge_type: String,
    pub attributes: HashMap<String, Option<String>>,
}

impl From<Badge> for EncodableBadge {
    fn from(badge: Badge) -> Self {
        // The serde attributes on Badge ensure it can be deserialized to EncodableBadge
        serde_json::from_value(serde_json::to_value(badge).unwrap()).unwrap()
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCategory {
    pub id: String,
    pub category: String,
    pub slug: String,
    pub description: String,
    #[serde(with = "rfc3339")]
    pub created_at: NaiveDateTime,
    pub crates_cnt: i32,
}

impl From<Category> for EncodableCategory {
    fn from(category: Category) -> Self {
        let Category {
            crates_cnt,
            category,
            slug,
            description,
            created_at,
            ..
        } = category;
        Self {
            id: slug.clone(),
            slug,
            description,
            created_at,
            crates_cnt,
            category: category.rsplit("::").collect::<Vec<_>>()[0].to_string(),
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCategoryWithSubcategories {
    pub id: String,
    pub category: String,
    pub slug: String,
    pub description: String,
    #[serde(with = "rfc3339")]
    pub created_at: NaiveDateTime,
    pub crates_cnt: i32,
    pub subcategories: Vec<EncodableCategory>,
    pub parent_categories: Vec<EncodableCategory>,
}

/// The serialization format for the `CrateOwnerInvitation` model.
#[derive(Deserialize, Serialize, Debug)]
pub struct EncodableCrateOwnerInvitation {
    pub invitee_id: i32,
    pub inviter_id: i32,
    pub invited_by_username: String,
    pub crate_name: String,
    pub crate_id: i32,
    #[serde(with = "rfc3339")]
    pub created_at: NaiveDateTime,
}

impl EncodableCrateOwnerInvitation {
    pub fn from_basic(
        invitation: CrateOwnerInvitation,
        inviter_name: String,
        crate_name: String,
    ) -> Self {
        Self {
            invitee_id: invitation.invited_user_id,
            inviter_id: invitation.invited_by_user_id,
            invited_by_username: inviter_name,
            crate_name,
            crate_id: invitation.crate_id,
            created_at: invitation.created_at,
        }
    }
}

#[derive(Deserialize, Serialize, Debug, Copy, Clone)]
pub struct InvitationResponse {
{'fraction_non_alphanumeric': 0.10393990495170934, 'fraction_numerical': 0.008278399509428177, 'mean_word_length': 3.074953154278576, 'pattern_counts': {'":': 2, '<': 19, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4280985', 'n_tokens_mistral': 2022, 'n_tokens_neox': 2034, 'n_words': 501}