//! Emoji reactions: the fixed set a user can put on an issue, a pull request or a comment, and //! the summaries the pages show. Stored as the short name (`+1`, `heart`, ...). use crate::error::{Error, Result}; use crate::model::Id; /// The fixed reaction set, in the order the pages list them. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Reaction { PlusOne, MinusOne, Laugh, Hooray, Confused, Heart, Rocket, Eyes, } impl Reaction { /// Every reaction, in display order. pub const ALL: [Reaction; 8] = [ Reaction::PlusOne, Reaction::MinusOne, Reaction::Laugh, Reaction::Hooray, Reaction::Confused, Reaction::Heart, Reaction::Rocket, Reaction::Eyes, ]; /// The short name stored in the database and sent in forms. pub fn name(self) -> &'static str { match self { Reaction::PlusOne => "+1", Reaction::MinusOne => "-1", Reaction::Laugh => "laugh", Reaction::Hooray => "hooray", Reaction::Confused => "confused", Reaction::Heart => "heart", Reaction::Rocket => "rocket", Reaction::Eyes => "eyes", } } /// The glyph shown for the reaction. pub fn emoji(self) -> &'static str { match self { Reaction::PlusOne => "\u{1f44d}", Reaction::MinusOne => "\u{1f44e}", Reaction::Laugh => "\u{1f604}", Reaction::Hooray => "\u{1f389}", Reaction::Confused => "\u{1f615}", Reaction::Heart => "\u{2764}\u{fe0f}", Reaction::Rocket => "\u{1f680}", Reaction::Eyes => "\u{1f440}", } } /// The reaction with this short name, or `None` for anything outside the set. pub fn parse(name: &str) -> Option { Reaction::ALL.into_iter().find(|r| r.name() == name) } } impl std::str::FromStr for Reaction { type Err = Error; fn from_str(s: &str) -> Result { Reaction::parse(s).ok_or_else(|| Error::Invalid(format!("unknown reaction: {s}"))) } } /// What a reaction is attached to. Pull requests are issue rows, so they use `Issue`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ReactionTarget { Issue, Comment, /// A discussion (store/discussions.rs). Discussion, /// A discussion comment or reply. DiscussionComment, } impl ReactionTarget { /// The `target_kind` column value. pub fn as_str(self) -> &'static str { match self { ReactionTarget::Issue => "issue", ReactionTarget::Comment => "comment", ReactionTarget::Discussion => "discussion", ReactionTarget::DiscussionComment => "discussion_comment", } } } /// One reaction on one target: how many users chose it, whether the viewer did, and the first /// usernames (at most ten, earliest reaction first). #[derive(Debug, Clone, PartialEq, Eq)] pub struct ReactionSummary { pub reaction: Reaction, pub count: usize, pub reacted_by_viewer: bool, pub users: Vec, } /// Usernames kept per summary. pub const SUMMARY_USERS: usize = 10; /// Summaries of one target, keyed by the target id. pub type ReactionMap = std::collections::HashMap>;