forge
ExploreLog in

Tahinli/forge

public
0 watching
★ 0
3.3 KiB
1//! Emoji reactions: the fixed set a user can put on an issue, a pull request or a comment, and
2//! the summaries the pages show. Stored as the short name (`+1`, `heart`, ...).
3
4use crate::error::{Error, Result};
5use crate::model::Id;
6
7/// The fixed reaction set, in the order the pages list them.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub enum Reaction {
10 PlusOne,
11 MinusOne,
12 Laugh,
13 Hooray,
14 Confused,
15 Heart,
16 Rocket,
17 Eyes,
18}
19
20impl Reaction {
21 /// Every reaction, in display order.
22 pub const ALL: [Reaction; 8] = [
23 Reaction::PlusOne,
24 Reaction::MinusOne,
25 Reaction::Laugh,
26 Reaction::Hooray,
27 Reaction::Confused,
28 Reaction::Heart,
29 Reaction::Rocket,
30 Reaction::Eyes,
31 ];
32
33 /// The short name stored in the database and sent in forms.
34 pub fn name(self) -> &'static str {
35 match self {
36 Reaction::PlusOne => "+1",
37 Reaction::MinusOne => "-1",
38 Reaction::Laugh => "laugh",
39 Reaction::Hooray => "hooray",
40 Reaction::Confused => "confused",
41 Reaction::Heart => "heart",
42 Reaction::Rocket => "rocket",
43 Reaction::Eyes => "eyes",
44 }
45 }
46
47 /// The glyph shown for the reaction.
48 pub fn emoji(self) -> &'static str {
49 match self {
50 Reaction::PlusOne => "\u{1f44d}",
51 Reaction::MinusOne => "\u{1f44e}",
52 Reaction::Laugh => "\u{1f604}",
53 Reaction::Hooray => "\u{1f389}",
54 Reaction::Confused => "\u{1f615}",
55 Reaction::Heart => "\u{2764}\u{fe0f}",
56 Reaction::Rocket => "\u{1f680}",
57 Reaction::Eyes => "\u{1f440}",
58 }
59 }
60
61 /// The reaction with this short name, or `None` for anything outside the set.
62 pub fn parse(name: &str) -> Option<Reaction> {
63 Reaction::ALL.into_iter().find(|r| r.name() == name)
64 }
65}
66
67impl std::str::FromStr for Reaction {
68 type Err = Error;
69
70 fn from_str(s: &str) -> Result<Self> {
71 Reaction::parse(s).ok_or_else(|| Error::Invalid(format!("unknown reaction: {s}")))
72 }
73}
74
75/// What a reaction is attached to. Pull requests are issue rows, so they use `Issue`.
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub enum ReactionTarget {
78 Issue,
79 Comment,
80 /// A discussion (store/discussions.rs).
81 Discussion,
82 /// A discussion comment or reply.
83 DiscussionComment,
84}
85
86impl ReactionTarget {
87 /// The `target_kind` column value.
88 pub fn as_str(self) -> &'static str {
89 match self {
90 ReactionTarget::Issue => "issue",
91 ReactionTarget::Comment => "comment",
92 ReactionTarget::Discussion => "discussion",
93 ReactionTarget::DiscussionComment => "discussion_comment",
94 }
95 }
96}
97
98/// One reaction on one target: how many users chose it, whether the viewer did, and the first
99/// usernames (at most ten, earliest reaction first).
100#[derive(Debug, Clone, PartialEq, Eq)]
101pub struct ReactionSummary {
102 pub reaction: Reaction,
103 pub count: usize,
104 pub reacted_by_viewer: bool,
105 pub users: Vec<String>,
106}
107
108/// Usernames kept per summary.
109pub const SUMMARY_USERS: usize = 10;
110
111/// Summaries of one target, keyed by the target id.
112pub type ReactionMap = std::collections::HashMap<Id, Vec<ReactionSummary>>;