From c2ec87206d86e13f46ab684d06c1acdd477506ef Mon Sep 17 00:00:00 2001 From: Ivin Joel Abraham Date: Fri, 7 Mar 2025 19:16:23 +0530 Subject: [PATCH 1/4] fix formatting issues with the status update report --- src/tasks/status_update.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tasks/status_update.rs b/src/tasks/status_update.rs index 3b07459..7b22953 100644 --- a/src/tasks/status_update.rs +++ b/src/tasks/status_update.rs @@ -232,7 +232,7 @@ fn format_members(members: &[Member]) -> String { format!("{}\n", list) } else { - String::from("More than five members hold this record!") + String::from("More than five members hold this record!\n") } } @@ -242,7 +242,7 @@ fn format_defaulters(naughty_list: &GroupedMember) -> String { description.push_str(&format!("## Group {}\n", group)); for member in missed_members { let status = match member.streak[0].current_streak { - 0 => ":x", + 0 => ":x:", -1 => ":x::x:", _ => ":headstone:", }; From 3bc2812306f4c86d28b7203c864423880a213116 Mon Sep 17 00:00:00 2001 From: chimnayajith Date: Fri, 7 Mar 2025 10:15:29 +0530 Subject: [PATCH 2/4] fix: Remove incorrect field rename in AttendanceRecord struct --- src/graphql/models.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/graphql/models.rs b/src/graphql/models.rs index 2769aa5..476e814 100644 --- a/src/graphql/models.rs +++ b/src/graphql/models.rs @@ -50,7 +50,6 @@ pub struct Member { #[derive(Debug, Deserialize, Clone)] pub struct AttendanceRecord { - #[serde(rename = "memberId")] pub name: String, pub year: i32, #[serde(rename = "isPresent")] From 413cb6ba888e064b3e387347390e729c58729baa Mon Sep 17 00:00:00 2001 From: Harshith2208 Date: Mon, 10 Mar 2025 02:36:26 +0530 Subject: [PATCH 3/4] Build config-rs for configuration management --- Cargo.toml | 2 + config.toml | 24 ++++++++++++ src/config.rs | 58 ++++++++++++++++++++++++++++ src/ids.rs | 36 ----------------- src/main.rs | 4 ++ src/tasks/status_update.rs | 79 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 167 insertions(+), 36 deletions(-) create mode 100644 config.toml create mode 100644 src/config.rs delete mode 100644 src/ids.rs diff --git a/Cargo.toml b/Cargo.toml index ede679c..4bd93b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,5 @@ dotenv = "0.15.0" serenity = { version = "0.12.4", features = ["chrono"] } poise = "0.6.1" tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } +config = "0.13" +lazy_static = "1.4" \ No newline at end of file diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..7ce6a23 --- /dev/null +++ b/config.toml @@ -0,0 +1,24 @@ +[discord] +roles_message_id = 1298636092886749294 + +[roles] +archive = 1208457364274028574 +mobile = 1298553701094395936 +systems = 1298553801191718944 +ai = 1298553753523453952 +research = 1298553855474270219 +devops = 1298553883169132554 +web = 1298553910167994428 + +[channels] +group_one = 1225098248293716008 +group_two = 1225098298935738489 +group_three = 1225098353378070710 +group_four = 1225098407216156712 +status_update = 764575524127244318 + +[status_update] +title_url = "https://www.youtube.com/watch?v=epnuvyNj0FM" +image_url = "https://media1.tenor.com/m/zAHCPvoyjNIAAAAd/yay-kitty.gif" +author_url = "https://github.com/amfoss/amd" +icon_url = "https://cdn.discordapp.com/avatars/1245352445736128696/da3c6f833b688f5afa875c9df5d86f91.webp?size=160" diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..43aa913 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,58 @@ +use config::{Config, File}; +use serde::Deserialize; +use lazy_static::lazy_static; +use std::sync::Arc; + +#[derive(Debug, Deserialize)] +pub struct Discord { + pub roles_message_id: u64, +} + +#[derive(Debug, Deserialize)] +pub struct Roles { + pub archive: u64, + pub mobile: u64, + pub systems: u64, + pub ai: u64, + pub research: u64, + pub devops: u64, + pub web: u64, +} + +#[derive(Debug, Deserialize)] +pub struct Channels { + pub group_one: u64, + pub group_two: u64, + pub group_three: u64, + pub group_four: u64, + pub status_update: u64, +} + +#[derive(Debug, Deserialize)] +pub struct StatusUpdate { + pub title_url: String, + pub image_url: String, + pub author_url: String, + pub icon_url: String, +} + +#[derive(Debug, Deserialize)] +pub struct Settings { + pub discord: Discord, + pub roles: Roles, + pub channels: Channels, + pub status_update: StatusUpdate, +} + +lazy_static! { + pub static ref CONFIG: Arc = { + let config = Config::builder() + .add_source(File::with_name("config.toml")) + .build() + .expect("Failed to load configuration") + .try_deserialize() + .expect("Invalid configuration format"); + + Arc::new(config) + }; +} diff --git a/src/ids.rs b/src/ids.rs deleted file mode 100644 index af849a1..0000000 --- a/src/ids.rs +++ /dev/null @@ -1,36 +0,0 @@ -/* -amFOSS Daemon: A discord bot for the amFOSS Discord server. -Copyright (C) 2024 amFOSS - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -/// Points to the Embed in the #roles channel. -pub const ROLES_MESSAGE_ID: u64 = 1298636092886749294; - -// Role IDs -pub const ARCHIVE_ROLE_ID: u64 = 1208457364274028574; -pub const MOBILE_ROLE_ID: u64 = 1298553701094395936; -pub const SYSTEMS_ROLE_ID: u64 = 1298553801191718944; -pub const AI_ROLE_ID: u64 = 1298553753523453952; -pub const RESEARCH_ROLE_ID: u64 = 1298553855474270219; -pub const DEVOPS_ROLE_ID: u64 = 1298553883169132554; -pub const WEB_ROLE_ID: u64 = 1298553910167994428; - -// Channel IDs -pub const GROUP_ONE_CHANNEL_ID: u64 = 1225098248293716008; -pub const GROUP_TWO_CHANNEL_ID: u64 = 1225098298935738489; -pub const GROUP_THREE_CHANNEL_ID: u64 = 1225098353378070710; -pub const GROUP_FOUR_CHANNEL_ID: u64 = 1225098407216156712; -pub const STATUS_UPDATE_CHANNEL_ID: u64 = 764575524127244318; -pub const THE_LAB_CHANNEL_ID: u64 = 1208438766893670451; diff --git a/src/main.rs b/src/main.rs index e1faf4c..76ee751 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,10 @@ mod scheduler; mod tasks; mod utils; +mod config; + +use config::CONFIG; + use anyhow::Context as _; use poise::{Context as PoiseContext, Framework, FrameworkOptions, PrefixFrameworkOptions}; use reaction_roles::{handle_reaction, populate_data_with_reaction_roles}; diff --git a/src/tasks/status_update.rs b/src/tasks/status_update.rs index 7b22953..3387a87 100644 --- a/src/tasks/status_update.rs +++ b/src/tasks/status_update.rs @@ -24,15 +24,33 @@ use serenity::all::{ use serenity::async_trait; use super::Task; +<<<<<<< HEAD use crate::graphql::models::{Member, StreakWithMemberId}; use crate::graphql::queries::{fetch_members, fetch_streaks, increment_streak, reset_streak}; use crate::ids::{ GROUP_FOUR_CHANNEL_ID, GROUP_ONE_CHANNEL_ID, GROUP_THREE_CHANNEL_ID, GROUP_TWO_CHANNEL_ID, STATUS_UPDATE_CHANNEL_ID, +======= +use crate::utils::time::time_until; +use crate::{ + graphql::{ + models::Member, + queries::{fetch_members, increment_streak, reset_streak}, + }, +>>>>>>> 948e8e3 (It now uses config-rs for configuration management instead of hard coded values) }; use crate::utils::time::time_until; +<<<<<<< HEAD /// Checks for status updates daily at 5 AM. +======= +const TITLE_URL: &str = &CONFIG.status_update.title_url; +const IMAGE_URL: &str = &CONFIG.status_update.image_url; +const AUTHOR_URL: &str = &CONFIG.status_update.author_url; +const ICON_URL: &str = &CONFIG.status_update.icon_url; + +/// Checks for status updates daily at 9 AM. +>>>>>>> 948e8e3 (It now uses config-rs for configuration management instead of hard coded values) pub struct StatusUpdateCheck; #[async_trait] @@ -78,6 +96,7 @@ async fn status_update_check(ctx: Context) -> anyhow::Result<()> { Ok(()) } +<<<<<<< HEAD async fn get_updates(ctx: &Context) -> anyhow::Result> { let channel_ids = get_channel_ids(); let mut updates = Vec::new(); @@ -105,6 +124,36 @@ fn get_channel_ids() -> Vec { fn is_valid_status_update(msg: &Message) -> bool { let report_config = get_report_config(); let content = msg.content.to_lowercase(); +======= +// TOOD: Get IDs through ENV instead +fn get_channel_ids() -> anyhow::Result> { + Ok(vec![ + ChannelId::new(CONFIG.channels.group_one), + ChannelId::new(CONFIG.channels.group_two), + ChannelId::new(CONFIG.channels.group_three), + ChannelId::new(CONFIG.channels.group_four), + ]) +} + + +async fn send_and_save_limiting_messages( + channel_ids: &Vec, + ctx: &Context, +) -> anyhow::Result<()> { + trace!("Running send_and_save_limiting_messages()"); + let mut msg_ids: Vec = vec![]; + for channel_id in channel_ids { + debug!("Sending message in {}", channel_id); + let msg = channel_id + .say( + &ctx.http, + "Collecting messages for status update report. Please do not delete this message.", + ) + .await + .with_context(|| { + anyhow::anyhow!("Failed to send limiting message in channel {}", channel_id) + })?; +>>>>>>> 948e8e3 (It now uses config-rs for configuration management instead of hard coded values) let is_within_timeframe = DateTime::::from_timestamp(msg.timestamp.timestamp(), 0) .expect("Valid timestamp") @@ -214,10 +263,40 @@ async fn generate_embed( description.push_str(&format_defaulters(&naughty_list)); } +<<<<<<< HEAD let embed = CreateEmbed::new() .title("Status Update Report") .description(description) .color(serenity::all::Colour::new(0xeab308)); +======= + let description = build_description( + highest_streak, + all_time_high, + &highest_streak_members, + &all_time_high_members, + &record_breakers, + &naughty_list, + ); + let today = chrono::Local::now() + .with_timezone(&Asia::Kolkata) + .date_naive(); + + let mut embed = CreateEmbed::default() + .title(format!("Status Update Report - {}", today)) + .url(&CONFIG.status_update.title_url) + .description(description) + .color(serenity::all::Colour::new(0xeab308)) + .timestamp(Timestamp::now()) + .author( + CreateEmbedAuthor::new("amD") + .url(&CONFIG.status_update.author_url) + .icon_url(&CONFIG.status_update.icon_url), + ); + + if naughty_list.is_empty() { + embed = embed.image(&CONFIG.status_update.image_url); + } +>>>>>>> 948e8e3 (It now uses config-rs for configuration management instead of hard coded values) Ok(embed) } From 35e035dfbe94322352cad48a780ac84c8ce66cf1 Mon Sep 17 00:00:00 2001 From: Harshith2208 Date: Tue, 11 Mar 2025 18:10:40 +0530 Subject: [PATCH 4/4] updated configuration management --- src/tasks/status_update.rs | 68 ++++---------------------------------- 1 file changed, 7 insertions(+), 61 deletions(-) diff --git a/src/tasks/status_update.rs b/src/tasks/status_update.rs index 3387a87..d8bc5f4 100644 --- a/src/tasks/status_update.rs +++ b/src/tasks/status_update.rs @@ -24,33 +24,17 @@ use serenity::all::{ use serenity::async_trait; use super::Task; -<<<<<<< HEAD use crate::graphql::models::{Member, StreakWithMemberId}; use crate::graphql::queries::{fetch_members, fetch_streaks, increment_streak, reset_streak}; -use crate::ids::{ - GROUP_FOUR_CHANNEL_ID, GROUP_ONE_CHANNEL_ID, GROUP_THREE_CHANNEL_ID, GROUP_TWO_CHANNEL_ID, - STATUS_UPDATE_CHANNEL_ID, -======= -use crate::utils::time::time_until; -use crate::{ - graphql::{ - models::Member, - queries::{fetch_members, increment_streak, reset_streak}, - }, ->>>>>>> 948e8e3 (It now uses config-rs for configuration management instead of hard coded values) -}; use crate::utils::time::time_until; -<<<<<<< HEAD /// Checks for status updates daily at 5 AM. -======= const TITLE_URL: &str = &CONFIG.status_update.title_url; const IMAGE_URL: &str = &CONFIG.status_update.image_url; const AUTHOR_URL: &str = &CONFIG.status_update.author_url; const ICON_URL: &str = &CONFIG.status_update.icon_url; /// Checks for status updates daily at 9 AM. ->>>>>>> 948e8e3 (It now uses config-rs for configuration management instead of hard coded values) pub struct StatusUpdateCheck; #[async_trait] @@ -96,7 +80,6 @@ async fn status_update_check(ctx: Context) -> anyhow::Result<()> { Ok(()) } -<<<<<<< HEAD async fn get_updates(ctx: &Context) -> anyhow::Result> { let channel_ids = get_channel_ids(); let mut updates = Vec::new(); @@ -111,20 +94,6 @@ async fn get_updates(ctx: &Context) -> anyhow::Result> { Ok(updates) } -// TODO: Replace hardcoded set with configurable list -fn get_channel_ids() -> Vec { - vec![ - ChannelId::new(GROUP_ONE_CHANNEL_ID), - ChannelId::new(GROUP_TWO_CHANNEL_ID), - ChannelId::new(GROUP_THREE_CHANNEL_ID), - ChannelId::new(GROUP_FOUR_CHANNEL_ID), - ] -} - -fn is_valid_status_update(msg: &Message) -> bool { - let report_config = get_report_config(); - let content = msg.content.to_lowercase(); -======= // TOOD: Get IDs through ENV instead fn get_channel_ids() -> anyhow::Result> { Ok(vec![ @@ -135,25 +104,9 @@ fn get_channel_ids() -> anyhow::Result> { ]) } - -async fn send_and_save_limiting_messages( - channel_ids: &Vec, - ctx: &Context, -) -> anyhow::Result<()> { - trace!("Running send_and_save_limiting_messages()"); - let mut msg_ids: Vec = vec![]; - for channel_id in channel_ids { - debug!("Sending message in {}", channel_id); - let msg = channel_id - .say( - &ctx.http, - "Collecting messages for status update report. Please do not delete this message.", - ) - .await - .with_context(|| { - anyhow::anyhow!("Failed to send limiting message in channel {}", channel_id) - })?; ->>>>>>> 948e8e3 (It now uses config-rs for configuration management instead of hard coded values) +fn is_valid_status_update(msg: &Message) -> bool { + let report_config = get_report_config(); + let content = msg.content.to_lowercase(); let is_within_timeframe = DateTime::::from_timestamp(msg.timestamp.timestamp(), 0) .expect("Valid timestamp") @@ -263,12 +216,6 @@ async fn generate_embed( description.push_str(&format_defaulters(&naughty_list)); } -<<<<<<< HEAD - let embed = CreateEmbed::new() - .title("Status Update Report") - .description(description) - .color(serenity::all::Colour::new(0xeab308)); -======= let description = build_description( highest_streak, all_time_high, @@ -283,20 +230,19 @@ async fn generate_embed( let mut embed = CreateEmbed::default() .title(format!("Status Update Report - {}", today)) - .url(&CONFIG.status_update.title_url) + .url(TITLE_URL) .description(description) .color(serenity::all::Colour::new(0xeab308)) .timestamp(Timestamp::now()) .author( CreateEmbedAuthor::new("amD") - .url(&CONFIG.status_update.author_url) - .icon_url(&CONFIG.status_update.icon_url), + .url(AUTHOR_URL) + .icon_url(ICON_URL), ); if naughty_list.is_empty() { - embed = embed.image(&CONFIG.status_update.image_url); + embed = embed.image(IMAGE_URL); } ->>>>>>> 948e8e3 (It now uses config-rs for configuration management instead of hard coded values) Ok(embed) }