Implement Codeforces announcer

This commit is contained in:
Natsu Kagami 2020-02-10 15:18:22 -05:00
parent 3998617f97
commit 3a14c401cd
Signed by: nki
GPG key ID: 73376E117CD20735
4 changed files with 111 additions and 5 deletions

View file

@ -0,0 +1,96 @@
use crate::db::{CfSavedUsers, CfUser};
use announcer::MemberToChannels;
use chrono::{DateTime, Utc};
use codeforces::{RatingChange, User};
use serenity::{
framework::standard::{CommandError, CommandResult},
http::CacheHttp,
model::id::{ChannelId, UserId},
CacheAndHttp,
};
use std::sync::Arc;
use youmubot_prelude::*;
type Reqwest = <HTTPClient as TypeMapKey>::Value;
/// Updates the rating and rating changes of the users.
pub fn updates(
http: Arc<CacheAndHttp>,
data: AppData,
channels: MemberToChannels,
) -> CommandResult {
let mut users = CfSavedUsers::open(&*data.read()).borrow()?.clone();
let reqwest = data.get_cloned::<HTTPClient>();
for (user_id, cfu) in users.iter_mut() {
if let Err(e) = update_user(http.clone(), &channels, &reqwest, *user_id, cfu) {
dbg!((*user_id, e));
}
}
*CfSavedUsers::open(&*data.read()).borrow_mut()? = users;
Ok(())
}
fn update_user(
http: Arc<CacheAndHttp>,
channels: &MemberToChannels,
reqwest: &Reqwest,
user_id: UserId,
cfu: &mut CfUser,
) -> CommandResult {
let info = User::info(reqwest, &[cfu.handle.as_str()])?
.into_iter()
.next()
.ok_or(CommandError::from("Not found"))?;
let rating_changes = {
let mut v = info.rating_changes(reqwest)?;
v.reverse();
v
};
let mut channels_list: Option<Vec<ChannelId>> = None;
let last_update = std::mem::replace(&mut cfu.last_update, Utc::now());
// Update the rating
cfu.rating = info.rating;
let mut send_message = |rc: RatingChange| -> CommandResult {
let (contest, _, _) =
codeforces::Contest::standings(reqwest, rc.contest_id, |f| f.limit(1, 1))?;
let channels =
channels_list.get_or_insert_with(|| channels.channels_of(http.clone(), user_id));
for channel in channels {
if let Err(e) = channel.send_message(http.http(), |e| {
e.content(format!("Rating change for {}!", user_id.mention()))
.embed(|c| {
crate::embed::rating_change_embed(
&rc,
&info,
&contest,
&user_id.mention(),
c,
)
})
}) {
dbg!(e);
}
}
Ok(())
};
// Check for any good announcements to make
for rc in rating_changes {
let date: DateTime<Utc> = DateTime::from_utc(
chrono::NaiveDateTime::from_timestamp(rc.rating_update_time_seconds as i64, 0),
Utc,
);
if &date > &last_update {
if let Err(v) = send_message(rc) {
dbg!(v);
}
}
}
Ok(())
}

View file

@ -64,7 +64,7 @@ pub fn rating_change_embed<'a>(
) -> &'a mut CreateEmbed { ) -> &'a mut CreateEmbed {
let delta = (rating_change.new_rating as i64) - (rating_change.old_rating as i64); let delta = (rating_change.new_rating as i64) - (rating_change.old_rating as i64);
let color = if delta < 0 { 0xff0000 } else { 0x00ff00 }; let color = if delta < 0 { 0xff0000 } else { 0x00ff00 };
let message = if delta < 0 { let message = if delta > 0 {
MessageBuilder::new() MessageBuilder::new()
.push(tag) .push(tag)
.push(" competed in ") .push(" competed in ")
@ -89,11 +89,19 @@ pub fn rating_change_embed<'a>(
}; };
e.author(|a| { e.author(|a| {
a.icon_url(&user.avatar) a.icon_url(format!("http:{}", &user.avatar))
.url(user.profile_url()) .url(user.profile_url())
.name(&user.handle) .name(&user.handle)
}) })
.color(color) .color(color)
.description(message) .description(message)
.field("Contest Link", contest.url(), true) .field("Contest Link", contest.url(), true)
.field(
"Rating Change",
format!(
"from **{}** to **{}**",
rating_change.old_rating, rating_change.new_rating
),
false,
)
} }

View file

@ -8,6 +8,7 @@ use serenity::{
}; };
use youmubot_prelude::*; use youmubot_prelude::*;
mod announcer;
mod db; mod db;
mod embed; mod embed;
mod hook; mod hook;
@ -20,9 +21,10 @@ use db::CfSavedUsers;
pub use hook::codeforces_info_hook; pub use hook::codeforces_info_hook;
/// Sets up the CF databases. /// Sets up the CF databases.
pub fn setup(path: &std::path::Path, data: &mut ShareMap) { pub fn setup(path: &std::path::Path, data: &mut ShareMap, announcers: &mut AnnouncerHandler) {
CfSavedUsers::insert_into(data, path.join("cf_saved_users.yaml")) CfSavedUsers::insert_into(data, path.join("cf_saved_users.yaml"))
.expect("Must be able to set up DB") .expect("Must be able to set up DB");
announcers.add("codeforces", announcer::updates);
} }
#[group] #[group]

View file

@ -87,7 +87,7 @@ fn main() {
.expect("osu! is initialized"); .expect("osu! is initialized");
// codeforces // codeforces
#[cfg(feature = "codeforces")] #[cfg(feature = "codeforces")]
youmubot_cf::setup(&db_path, &mut data); youmubot_cf::setup(&db_path, &mut data, &mut announcers);
} }
#[cfg(feature = "core")] #[cfg(feature = "core")]