From c00d64cd9ad5d4dac48598981ac7b9a7fc6622a3 Mon Sep 17 00:00:00 2001
From: Stephen D <webmaster@scd31.com>
Date: Sun, 27 Nov 2022 18:54:57 -0400
Subject: [PATCH] refactor and add counts in new messages

---
 src/handlers/starboard.rs | 164 ++++++++++++++++++++++++--------------
 src/models.rs             |   2 +-
 src/schema.rs             |  42 +++++-----
 3 files changed, 126 insertions(+), 82 deletions(-)

diff --git a/src/handlers/starboard.rs b/src/handlers/starboard.rs
index b119f31..25bb92b 100644
--- a/src/handlers/starboard.rs
+++ b/src/handlers/starboard.rs
@@ -7,35 +7,43 @@ use anyhow::Context as AnyhowContext;
 use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive};
 use diesel::{ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl};
 use serenity::async_trait;
-use serenity::model::prelude::{ChannelId, EmojiId, GuildId, Message, Reaction, ReactionType};
+use serenity::builder::CreateEmbed;
+use serenity::model::prelude::{ChannelId, Emoji, EmojiId, Message, Reaction, ReactionType};
 use serenity::prelude::*;
 use std::sync::Arc;
 use tokio::sync::Mutex;
 
-pub struct StarboardHandler {
+#[derive(Clone)]
+pub struct SingleMessageHandler {
 	conn: Arc<Mutex<PgConnection>>,
+	server_settings: ServerSetting,
+	reaction_count: u64,
+	msg: Message,
+	emoji: Emoji,
+	name: String,
+	image: Option<String>,
 }
 
-impl StarboardHandler {
-	pub fn new(conn: Arc<Mutex<PgConnection>>) -> Self {
-		Self { conn }
-	}
-
-	async fn handle_reaction(&self, ctx: &Context, reaction: &Reaction) -> anyhow::Result<()> {
+impl SingleMessageHandler {
+	pub async fn handle_reaction(
+		conn: Arc<Mutex<PgConnection>>,
+		ctx: &Context,
+		reaction: &Reaction,
+	) -> anyhow::Result<()> {
 		let guild = match reaction.channel_id.to_channel(ctx).await?.guild() {
 			Some(x) => x,
 			None => return Ok(()),
 		};
 
 		// get corresponding guild settings
-		let gs: Vec<ServerSetting> = server_settings::dsl::server_settings
+		let mut gs: Vec<ServerSetting> = server_settings::dsl::server_settings
 			.filter(
 				schema::server_settings::columns::guild_id
 					.eq(BigDecimal::from_u64(guild.guild_id.0).unwrap()),
 			)
 			.limit(1)
-			.get_results(&*self.conn.lock().await)?;
-		let gs = match gs.first() {
+			.get_results(&*conn.lock().await)?;
+		let gs = match gs.pop() {
 			Some(x) => x,
 			None => return Ok(()),
 		};
@@ -49,8 +57,38 @@ impl StarboardHandler {
 			let msg = reaction.message(ctx).await?;
 			for mr in &msg.reactions {
 				if Self::emoji_match(&mr.reaction_type, emoji) {
-					self.handle_matching_reaction(ctx, gs, mr.count, &msg, &guild.guild_id)
-						.await?;
+					let guild_id = guild.guild_id;
+
+					let emoji = guild_id
+						.emoji(ctx, emoji)
+						.await
+						.context("Could not get emoji from guild")?;
+
+					let name = msg
+						.author
+						.nick_in(ctx, guild_id)
+						.await
+						.unwrap_or_else(|| msg.author.tag());
+
+					let image = msg
+						.attachments
+						.iter()
+						.filter(|a| a.width.is_some())
+						.map(|a| &a.url)
+						.next()
+						.cloned();
+
+					let handler = Self {
+						conn,
+						server_settings: gs,
+						reaction_count: mr.count,
+						msg,
+						emoji,
+						name,
+						image,
+					};
+
+					handler.process_match(ctx).await?;
 					break;
 				}
 			}
@@ -59,16 +97,9 @@ impl StarboardHandler {
 		Ok(())
 	}
 
-	async fn handle_matching_reaction(
-		&self,
-		ctx: &Context,
-		gs: &ServerSetting,
-		count: u64,
-		msg: &Message,
-		guild: &GuildId,
-	) -> anyhow::Result<()> {
-		if count >= gs.starboard_threshold as u64 {
-			let original_id = BigDecimal::from(msg.id.0);
+	async fn process_match(&self, ctx: &Context) -> anyhow::Result<()> {
+		if self.reaction_count >= self.server_settings.starboard_threshold as u64 {
+			let original_id = BigDecimal::from(self.msg.id.0);
 			diesel::insert_into(starboard_mappings::dsl::starboard_mappings)
 				.values(starboard_mappings::columns::original_id.eq(&original_id))
 				.returning(starboard_mappings::columns::repost_id)
@@ -85,47 +116,11 @@ impl StarboardHandler {
 				repost_id.get(0).context("Insert of mapping failed")?;
 
 			if repost_id.is_none() {
-				// post to repost channel
-				let name = msg
-					.author
-					.nick_in(&ctx, guild)
-					.await
-					.unwrap_or_else(|| msg.author.tag());
-
-				let image = msg
-					.attachments
-					.iter()
-					.filter(|a| a.width.is_some())
-					.map(|a| &a.url)
-					.next();
-
-				let repost = ChannelId(
-					gs.starboard_channel
-						.to_u64()
-						.context("Could not convert starboard channel to a u64")?,
-				)
-				.send_message(ctx, |m| {
-					m.embed(|e| {
-						let mut e = e
-							.description(format!(
-								"[Jump to source]({})\n{}",
-								msg.link(),
-								msg.content
-							))
-							.author(|a| a.name(&name).icon_url(msg.author.face()))
-							.timestamp(&msg.timestamp);
-
-						if let Some(url) = image {
-							e = e.image(url);
-						}
-
-						e
-					})
-				})
-				.await?;
+				// post to repost
+				let repost = self.post_new_starboard_message(ctx).await?;
 
 				// update the DB
-				let repost_id = BigDecimal::from_u64(repost.id.0);
+				let repost_id = BigDecimal::from_u64(repost);
 				diesel::update(
 					starboard_mappings::dsl::starboard_mappings
 						.filter(starboard_mappings::columns::original_id.eq(original_id)),
@@ -138,11 +133,56 @@ impl StarboardHandler {
 		Ok(())
 	}
 
+	async fn post_new_starboard_message(&self, ctx: &Context) -> anyhow::Result<u64> {
+		let repost = ChannelId(
+			self.server_settings
+				.starboard_channel
+				.to_u64()
+				.context("Could not convert starboard channel to a u64")?,
+		)
+		.send_message(ctx, |m| m.embed(|e| self.clone().starboard_message(e)))
+		.await?;
+
+		Ok(repost.id.0)
+	}
+
+	fn starboard_message(self, e: &mut CreateEmbed) -> &mut CreateEmbed {
+		let mut e = e
+			.description(format!(
+				"[Jump to source]({})\n{}",
+				self.msg.link(),
+				self.msg.content
+			))
+			.title(format!("{} {}", self.reaction_count, self.emoji))
+			.author(|a| a.name(&self.name).icon_url(self.msg.author.face()))
+			.timestamp(&self.msg.timestamp);
+
+		if let Some(url) = self.image {
+			e = e.image(url);
+		}
+
+		e
+	}
+
 	fn emoji_match(rt: &ReactionType, em: EmojiId) -> bool {
 		matches!(rt, ReactionType::Custom { id, .. } if *id == em)
 	}
 }
 
+pub struct StarboardHandler {
+	conn: Arc<Mutex<PgConnection>>,
+}
+
+impl StarboardHandler {
+	pub fn new(conn: Arc<Mutex<PgConnection>>) -> Self {
+		Self { conn }
+	}
+
+	async fn handle_reaction(&self, ctx: &Context, reaction: &Reaction) -> anyhow::Result<()> {
+		SingleMessageHandler::handle_reaction(self.conn.clone(), ctx, reaction).await
+	}
+}
+
 #[async_trait]
 impl ReactionHandler for StarboardHandler {
 	async fn reaction(&self, ctx: &Context, reaction: &Reaction) {
diff --git a/src/models.rs b/src/models.rs
index 10d32fe..bae06f4 100644
--- a/src/models.rs
+++ b/src/models.rs
@@ -17,7 +17,7 @@ pub struct NewUserProgram<'a> {
 	pub code: &'a str,
 }
 
-#[derive(Queryable)]
+#[derive(Clone, Queryable)]
 pub struct ServerSetting {
 	pub id: i32,
 	pub guild_id: BigDecimal,
diff --git a/src/schema.rs b/src/schema.rs
index 9253787..4a883c6 100644
--- a/src/schema.rs
+++ b/src/schema.rs
@@ -1,28 +1,32 @@
 table! {
-	server_settings (id) {
-		id -> Int4,
-		guild_id -> Numeric,
-		starboard_threshold -> Int4,
-		starboard_emoji_id -> Numeric,
-		starboard_channel -> Numeric,
-	}
+    server_settings (id) {
+        id -> Int4,
+        guild_id -> Numeric,
+        starboard_threshold -> Int4,
+        starboard_emoji_id -> Numeric,
+        starboard_channel -> Numeric,
+    }
 }
 
 table! {
-	starboard_mappings (original_id) {
-		original_id -> Numeric,
-		repost_id -> Nullable<Numeric>,
-	}
+    starboard_mappings (original_id) {
+        original_id -> Numeric,
+        repost_id -> Nullable<Numeric>,
+    }
 }
 
 table! {
-	user_programs (id) {
-		id -> Int4,
-		discord_user_id -> Numeric,
-		name -> Varchar,
-		code -> Text,
-		published -> Int4,
-	}
+    user_programs (id) {
+        id -> Int4,
+        discord_user_id -> Numeric,
+        name -> Varchar,
+        code -> Text,
+        published -> Int4,
+    }
 }
 
-allow_tables_to_appear_in_same_query!(server_settings, starboard_mappings, user_programs,);
+allow_tables_to_appear_in_same_query!(
+    server_settings,
+    starboard_mappings,
+    user_programs,
+);
-- 
GitLab