From 84588d84e938d9c0757df5b3f911fec65a0b7742 Mon Sep 17 00:00:00 2001 From: Bailey Townsend Date: Wed, 1 Nov 2023 22:44:16 -0500 Subject: [PATCH] Saving of clan mates and clogs --- .../src/controllers/chat_controller.rs | 2 + .../src/services/osrs_broadcast_handler.rs | 93 ++++++++++++++----- .../clan_mate_collection_log_totals.rs | 87 +++++++++++++++++ .../src/database/clan_mates.rs | 37 ++++++-- .../src/database/drop_logs_db.rs | 4 +- trackscape-discord-shared/src/database/mod.rs | 17 ++++ 6 files changed, 212 insertions(+), 28 deletions(-) create mode 100644 trackscape-discord-shared/src/database/clan_mate_collection_log_totals.rs diff --git a/trackscape-discord-api/src/controllers/chat_controller.rs b/trackscape-discord-api/src/controllers/chat_controller.rs index f06a496..82cf540 100644 --- a/trackscape-discord-api/src/controllers/chat_controller.rs +++ b/trackscape-discord-api/src/controllers/chat_controller.rs @@ -188,6 +188,8 @@ async fn new_clan_chats( quests_from_state, registered_guild.clone(), mongodb.drop_logs.clone(), + mongodb.clan_mate_collection_log_totals.clone(), + mongodb.clan_mates.clone(), ); let possible_broadcast = handler.extract_message().await; match possible_broadcast { diff --git a/trackscape-discord-api/src/services/osrs_broadcast_handler.rs b/trackscape-discord-api/src/services/osrs_broadcast_handler.rs index f99d8af..b993d63 100644 --- a/trackscape-discord-api/src/services/osrs_broadcast_handler.rs +++ b/trackscape-discord-api/src/services/osrs_broadcast_handler.rs @@ -1,5 +1,7 @@ use log::error; use num_format::{Locale, ToFormattedString}; +use trackscape_discord_shared::database::clan_mate_collection_log_totals::ClanMateCollectionLogTotals; +use trackscape_discord_shared::database::clan_mates::ClanMates; use trackscape_discord_shared::database::drop_logs_db::DropLogs; use trackscape_discord_shared::database::guilds_db::RegisteredGuildModel; use trackscape_discord_shared::ge_api::ge_api::{get_item_value_by_id, GeItemMapping}; @@ -25,21 +27,25 @@ pub struct BroadcastMessageToDiscord { } #[derive(Debug, Clone)] -pub struct OSRSBroadcastHandler { +pub struct OSRSBroadcastHandler { clan_message: ClanMessage, item_mapping: Option, quests: Option>, registered_guild: RegisteredGuildModel, - db: T, + drop_log_db: T, + collection_log_db: CL, + clan_mates_db: CM, } -impl OSRSBroadcastHandler { +impl OSRSBroadcastHandler { pub fn new( clan_message: ClanMessage, item_mapping_from_state: Result, quests_from_state: Result, ()>, register_guild: RegisteredGuildModel, - db: T, + drop_log_db: T, + collection_log_db: CL, + clan_mates_db: CM, ) -> Self { Self { clan_message, @@ -52,7 +58,9 @@ impl OSRSBroadcastHandler { Err(_) => None, }, registered_guild: register_guild, - db: db, + drop_log_db, + collection_log_db, + clan_mates_db, } } @@ -88,7 +96,7 @@ impl OSRSBroadcastHandler { } None => {} } - self.db + self.drop_log_db .new_drop_log(drop_item.clone(), self.registered_guild.guild_id) .await; let is_disallowed = self @@ -282,7 +290,7 @@ impl OSRSBroadcastHandler { } } } - BroadcastType::CollectionLog => self.collection_log_handler(), + BroadcastType::CollectionLog => self.collection_log_handler().await, _ => None, } } @@ -299,7 +307,7 @@ impl OSRSBroadcastHandler { None } Some(drop_item) => { - self.db + self.drop_log_db .new_drop_log(drop_item.clone(), self.registered_guild.guild_id) .await; let is_disallowed = self.check_if_allowed_broad_cast(BroadcastType::ItemDrop); @@ -521,7 +529,7 @@ impl OSRSBroadcastHandler { false } - fn collection_log_handler(&self) -> Option { + async fn collection_log_handler(&self) -> Option { let possible_collection_log = collection_log_broadcast_extractor(self.clan_message.message.clone()); match possible_collection_log { @@ -533,6 +541,29 @@ impl OSRSBroadcastHandler { None } Some(collection_log_broadcast) => { + let possible_clan_mate = self + .clan_mates_db + .find_or_create_clan_mate( + self.registered_guild.guild_id, + collection_log_broadcast.player_it_happened_to.clone(), + ) + .await; + let _ = match possible_clan_mate { + Ok(clan_mate) => { + self.collection_log_db + .update_or_create( + clan_mate.guild_id, + clan_mate.id, + collection_log_broadcast.log_slots, + ) + .await + } + Err(error) => { + error!("{:?}", error); + Err(error) + } + }; + let is_disallowed = self.check_if_allowed_broad_cast(BroadcastType::CollectionLog); if is_disallowed { return None; @@ -554,6 +585,8 @@ impl OSRSBroadcastHandler { mod tests { use super::*; use log::info; + use trackscape_discord_shared::database::clan_mate_collection_log_totals::MockClanMateCollectionLogTotals; + use trackscape_discord_shared::database::clan_mates::MockClanMates; use trackscape_discord_shared::database::drop_logs_db::MockDropLogs; use trackscape_discord_shared::ge_api::ge_api::GetItem; use trackscape_discord_shared::osrs_broadcast_extractor::osrs_broadcast_extractor::{ @@ -590,8 +623,8 @@ mod tests { let quests = Ok(Vec::new()); - let mut db_mock = MockDropLogs::new(); - db_mock.expect_new_drop_log().returning(|_, _| { + let mut drop_log_db_mock = MockDropLogs::new(); + drop_log_db_mock.expect_new_drop_log().returning(|_, _| { info!("Should not be calling this function"); }); let handler = OSRSBroadcastHandler::new( @@ -599,7 +632,9 @@ mod tests { get_item_mapping, quests, registered_guild, - db_mock, + drop_log_db_mock, + MockClanMateCollectionLogTotals::new(), + MockClanMates::new(), ); let extracted_message = handler.drop_item_handler().await; @@ -644,8 +679,8 @@ mod tests { } let quests = Ok(Vec::new()); - let mut db_mock = MockDropLogs::new(); - db_mock.expect_new_drop_log().returning(|_, _| { + let mut drop_log_db_mock = MockDropLogs::new(); + drop_log_db_mock.expect_new_drop_log().returning(|_, _| { info!("Should not be calling this function"); }); @@ -654,7 +689,9 @@ mod tests { get_item_mapping, quests, registered_guild, - db_mock, + drop_log_db_mock, + MockClanMateCollectionLogTotals::new(), + MockClanMates::new(), ); let extracted_message = handler.drop_item_handler().await; @@ -699,8 +736,8 @@ mod tests { } let quests = Ok(Vec::new()); - let mut db_mock = MockDropLogs::new(); - db_mock.expect_new_drop_log().returning(|_, _| { + let mut drop_log_db_mock = MockDropLogs::new(); + drop_log_db_mock.expect_new_drop_log().returning(|_, _| { info!("Should not be calling this function"); }); @@ -709,7 +746,9 @@ mod tests { get_item_mapping, quests, registered_guild, - db_mock, + drop_log_db_mock, + MockClanMateCollectionLogTotals::new(), + MockClanMates::new(), ); let extracted_message = handler.drop_item_handler().await; @@ -755,8 +794,8 @@ mod tests { } let quests = Ok(Vec::new()); - let mut db_mock = MockDropLogs::new(); - db_mock.expect_new_drop_log().returning(|_, _| { + let mut drop_log_db_mock = MockDropLogs::new(); + drop_log_db_mock.expect_new_drop_log().returning(|_, _| { info!("Should not be calling this function"); }); @@ -765,7 +804,9 @@ mod tests { get_item_mapping, quests, registered_guild, - db_mock, + drop_log_db_mock, + MockClanMateCollectionLogTotals::new(), + MockClanMates::new(), ); let extracted_message = handler.drop_item_handler().await; @@ -822,6 +863,8 @@ mod tests { quests, registered_guild, MockDropLogs::new(), + MockClanMateCollectionLogTotals::new(), + MockClanMates::new(), ); let extracted_message = handler.quest_handler(); @@ -876,6 +919,8 @@ mod tests { quests, registered_guild, MockDropLogs::new(), + MockClanMateCollectionLogTotals::new(), + MockClanMates::new(), ); let extracted_message = handler.quest_handler(); @@ -928,6 +973,8 @@ mod tests { quests, registered_guild, MockDropLogs::new(), + MockClanMateCollectionLogTotals::new(), + MockClanMates::new(), ); let extracted_message = handler.pk_handler(); @@ -980,6 +1027,8 @@ mod tests { quests, registered_guild, MockDropLogs::new(), + MockClanMateCollectionLogTotals::new(), + MockClanMates::new(), ); let extracted_message = handler.diary_handler(); @@ -1031,6 +1080,8 @@ mod tests { quests, registered_guild, MockDropLogs::new(), + MockClanMateCollectionLogTotals::new(), + MockClanMates::new(), ); let extracted_message = handler.diary_handler(); diff --git a/trackscape-discord-shared/src/database/clan_mate_collection_log_totals.rs b/trackscape-discord-shared/src/database/clan_mate_collection_log_totals.rs new file mode 100644 index 0000000..14d2dcb --- /dev/null +++ b/trackscape-discord-shared/src/database/clan_mate_collection_log_totals.rs @@ -0,0 +1,87 @@ +use crate::database::ClanMateCollectionLogTotalsDb; +use anyhow::Error; +use async_trait::async_trait; +use log::info; +use mockall::automock; +use mongodb::bson::{doc, DateTime}; +use mongodb::{bson, Database}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ClanMateCollectionLogTotalModel { + pub guild_id: u64, + pub player_id: bson::oid::ObjectId, + pub total: i64, + pub created_at: DateTime, +} + +impl ClanMateCollectionLogTotalModel { + pub const COLLECTION_NAME: &'static str = "clan_mate_collection_log_totals"; + + pub fn new(guild_id: u64, player_id: bson::oid::ObjectId, total: i64) -> Self { + Self { + guild_id, + player_id, + total, + created_at: DateTime::now(), + } + } +} + +#[automock] +#[async_trait] +pub trait ClanMateCollectionLogTotals { + fn new_instance(mongodb: Database) -> Self; + + async fn update_or_create( + &self, + guild_id: u64, + player_id: bson::oid::ObjectId, + total: i64, + ) -> Result<(), anyhow::Error>; +} + +#[async_trait] +impl ClanMateCollectionLogTotals for ClanMateCollectionLogTotalsDb { + fn new_instance(mongodb: Database) -> Self { + Self { db: mongodb } + } + + async fn update_or_create( + &self, + guild_id: u64, + player_id: bson::oid::ObjectId, + total: i64, + ) -> Result<(), Error> { + let collection = self.db.collection::( + ClanMateCollectionLogTotalModel::COLLECTION_NAME, + ); + + let filter = doc! { + "guild_id": bson::to_bson(&guild_id).unwrap(), + "player_id": player_id.clone(), + }; + + let update_result = collection + .update_one( + filter, + doc! { + "$set": { + "total": bson::to_bson(&total).unwrap() + } + }, + None, + ) + .await?; + info!("Update result: {:?}", update_result); + if update_result.matched_count > 0 { + return Ok(()); + } + let new_total = ClanMateCollectionLogTotalModel::new(guild_id, player_id, total); + let _ = collection + .insert_one(new_total, None) + .await + .expect("Error inserting new collection log total."); + Ok(()) + } +} diff --git a/trackscape-discord-shared/src/database/clan_mates.rs b/trackscape-discord-shared/src/database/clan_mates.rs index ec859c9..238e6cf 100644 --- a/trackscape-discord-shared/src/database/clan_mates.rs +++ b/trackscape-discord-shared/src/database/clan_mates.rs @@ -1,4 +1,5 @@ -use crate::database::DropLogsDb; +use crate::database::ClanMatesDb; +use anyhow::Error; use async_trait::async_trait; use mockall::predicate::*; use mockall::*; @@ -8,6 +9,8 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ClanMateModel { + #[serde(rename = "_id")] + pub id: bson::oid::ObjectId, pub guild_id: u64, pub player_name: String, pub wom_player_id: Option, @@ -20,6 +23,7 @@ impl ClanMateModel { pub fn new(guild_id: u64, player_name: String, wom_player_id: Option) -> Self { Self { + id: bson::oid::ObjectId::new(), guild_id, wom_player_id, previous_names: Vec::new(), @@ -34,12 +38,18 @@ impl ClanMateModel { pub trait ClanMates { fn new_instance(mongodb: Database) -> Self; + async fn find_or_create_clan_mate( + &self, + guild_id: u64, + player_name: String, + ) -> Result; + async fn create_new_clan_mate( &self, guild_id: u64, player_name: String, wom_player_id: Option, - ) -> Result<(), anyhow::Error>; + ) -> Result; async fn find_by_current_name( &self, @@ -53,23 +63,38 @@ pub trait ClanMates { } #[async_trait] -impl ClanMates for DropLogsDb { +impl ClanMates for ClanMatesDb { fn new_instance(mongodb: Database) -> Self { Self { db: mongodb } } + async fn find_or_create_clan_mate( + &self, + guild_id: u64, + player_name: String, + ) -> Result { + let possible_clan_mate = self.find_by_current_name(player_name.clone()).await?; + return Ok(match possible_clan_mate { + None => { + self.create_new_clan_mate(guild_id, player_name, None) + .await? + } + Some(clan_mate) => clan_mate, + }); + } + async fn create_new_clan_mate( &self, guild_id: u64, player_name: String, wom_player_id: Option, - ) -> Result<(), anyhow::Error> { + ) -> Result { let collection = self .db .collection::(ClanMateModel::COLLECTION_NAME); let clan_mate = ClanMateModel::new(guild_id, player_name, wom_player_id); - let _ = collection.insert_one(clan_mate, None).await?; - Ok(()) + let _ = collection.insert_one(clan_mate.clone(), None).await?; + Ok(clan_mate) } async fn find_by_current_name( diff --git a/trackscape-discord-shared/src/database/drop_logs_db.rs b/trackscape-discord-shared/src/database/drop_logs_db.rs index 936e35a..a0522cd 100644 --- a/trackscape-discord-shared/src/database/drop_logs_db.rs +++ b/trackscape-discord-shared/src/database/drop_logs_db.rs @@ -10,6 +10,8 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct DropLogModel { + #[serde(rename = "_id")] + id: bson::oid::ObjectId, pub guild_id: u64, pub drop_item: DropItemBroadcast, pub created_at: DateTime, @@ -20,6 +22,7 @@ impl DropLogModel { pub fn new(drop_item: DropItemBroadcast, guild_id: u64) -> Self { Self { + id: bson::oid::ObjectId::new(), guild_id, drop_item, created_at: DateTime::now(), @@ -31,7 +34,6 @@ impl DropLogModel { #[async_trait] pub trait DropLogs { fn new_instance(mongodb: Database) -> Self; - async fn new_drop_log(&self, drop_log: DropItemBroadcast, guild_id: u64); async fn get_drops_between_dates( &self, diff --git a/trackscape-discord-shared/src/database/mod.rs b/trackscape-discord-shared/src/database/mod.rs index 9b99b7e..ddc4fd5 100644 --- a/trackscape-discord-shared/src/database/mod.rs +++ b/trackscape-discord-shared/src/database/mod.rs @@ -1,10 +1,13 @@ use mongodb::bson::doc; use mongodb::options::ClientOptions; use mongodb::Database; +pub mod clan_mate_collection_log_totals; pub mod clan_mates; pub mod drop_logs_db; pub mod guilds_db; +use crate::database::clan_mate_collection_log_totals::ClanMateCollectionLogTotals; +use crate::database::clan_mates::ClanMates; use crate::database::drop_logs_db::DropLogs; use async_trait::async_trait; use mockall::automock; @@ -19,6 +22,8 @@ pub trait MongoDb { pub struct BotMongoDb { pub guilds: GuildsDb, pub drop_logs: DropLogsDb, + pub clan_mates: ClanMatesDb, + pub clan_mate_collection_log_totals: ClanMateCollectionLogTotalsDb, } #[derive(Clone)] @@ -31,6 +36,16 @@ pub struct DropLogsDb { db: Database, } +#[derive(Clone)] +pub struct ClanMatesDb { + db: Database, +} + +#[derive(Clone)] +pub struct ClanMateCollectionLogTotalsDb { + db: Database, +} + #[async_trait] impl MongoDb for BotMongoDb { async fn new_db_instance(db_url: String) -> Self { @@ -44,6 +59,8 @@ impl MongoDb for BotMongoDb { Self { guilds: GuildsDb::new(db.clone()), drop_logs: DropLogsDb::new_instance(db.clone()), + clan_mates: ClanMatesDb::new_instance(db.clone()), + clan_mate_collection_log_totals: ClanMateCollectionLogTotalsDb::new_instance(db), } } }