Compare commits

..

3 Commits

Author SHA1 Message Date
Xyon fa68df0a94 Merge pull request 'Fix formatting on mobile by refactoring the whole approach' (#17) from hotfix/fucking-field-limits-ffs into main
Badgey Deployment / build (push) Successful in 6m10s Details
Badgey Deployment / deploy (BADGEY) (push) Successful in 6s Details
Badgey Deployment / deploy (M5_COMPUTER) (push) Successful in 7s Details
Reviewed-on: #17
2024-10-20 15:17:39 +00:00
Xyon 7ee321f691 Merge branch 'main' into hotfix/fucking-field-limits-ffs 2024-10-20 15:17:35 +00:00
Xyon 6300b45368
Fix formatting on mobile by refactoring the whole approach 2024-10-20 16:17:17 +01:00
4 changed files with 67 additions and 32 deletions

10
Cargo.lock generated
View File

@ -179,6 +179,7 @@ dependencies = [
"rand 0.8.5",
"regex 1.11.0",
"rust-i18n",
"to_markdown_table",
"tokio",
"url",
]
@ -2594,6 +2595,15 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "to_markdown_table"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8450ade61b78735ed7811cc14639462723d87a6cd748a41e7bfde554ac5033dd"
dependencies = [
"thiserror",
]
[[package]]
name = "tokio"
version = "1.40.0"

View File

@ -21,6 +21,7 @@ poise = { version = "0.5.*", features = [ "cache" ] }
rand = { version = "0.8.5", features = [ "small_rng" ] }
regex = "1.9.5"
rust-i18n = "3.1.2"
to_markdown_table = "0.1.5"
tokio = { version = "1.16.1", features = ["sync", "macros", "rt-multi-thread"] }
url = "2.5.2"

View File

@ -2,7 +2,8 @@ use built::chrono;
use manifold::error::{ManifoldError, ManifoldResult};
use manifold::{ManifoldContext, ManifoldData};
use poise::serenity_prelude::{CreateEmbed, Mentionable, RoleId};
use crate::badgey::models::xp::{Rank, Track, Xp};
use to_markdown_table::MarkdownTable;
use crate::badgey::models::xp::{Leaderboard, Rank, Track, Xp};
#[poise::command(prefix_command, slash_command, user_cooldown = 86400)]
async fn switch_rank_track(ctx: ManifoldContext<'_>, #[description = "Track to switch to: officer or enlisted"] track: String) -> ManifoldResult<()> {
@ -125,47 +126,34 @@ async fn leaderboard(ctx: ManifoldContext<'_>) -> ManifoldResult<()> {
let reply_handle = ctx.reply("Retrieving leaderboard, please stand by...".to_string()).await?;
let entries_per_page = 20;
let mut pages = Vec::<CreateEmbed>::new();
let leaderboard = Xp::get_leaderboard(&ctx.data().database)?;
let total = leaderboard.len();
let leaderboard = Leaderboard::get_leaderboard(&ctx.data().database)?;
let userinfo = ctx.data().user_info.lock().await;
let total = leaderboard.rows.len();
let pages_needed = (total / entries_per_page) + 1;
for i in 0..pages_needed {
let mut page = CreateEmbed::default()
.title(format!("XP Leaderboard Page {page} of {total_pages}", page=(i + 1), total_pages=&pages_needed)).to_owned();
let mut fields = Vec::new();
let mut ranks = String::new();
let mut users = String::new();
let mut values = String::new();
let offset = i*entries_per_page;
let mut leaderboard_rows = Vec::new();
leaderboard.iter().skip(offset).enumerate().for_each(|(j, f)| {
leaderboard.rows.iter().skip(offset).enumerate().for_each(|(j, f)| {
// cap at per-page limit
if j >= entries_per_page {
return;
}
let new_rank = format!("{rank}\n", rank=(j+1+offset));
let new_user = format!("<@{user}>\n", user=f.user_id);
let new_value = format!("{xp}\n", xp=f.xp_value);
let mut row = f.to_owned();
row.rank = (j + 1 + offset) as i32;
row.user_name = userinfo.get(&(row.uid as u64)).unwrap().username.clone();
// field values are capped at 1024 characters
// so we have to check if what we're about to add will break that limit and bail out if so
if (ranks.len() + new_rank.len()) > 1024 || (users.len() + new_user.len()) > 1024 || (values.len() + new_value.len()) > 1024 {
return;
}
ranks.push_str(new_rank.as_str());
users.push_str(new_user.as_str());
values.push_str(new_value.as_str());
leaderboard_rows.push(row);
});
fields.push(("Rank", &ranks, true));
fields.push(("User", &users, true));
fields.push(("XP", &values, true));
let leaderboard_table = MarkdownTable::new(Some(vec!["Rank".to_string(), "User".to_string(), "XP".to_string()]), leaderboard_rows)?;
page.fields(fields);
page.description(format!("```{table}```", table=leaderboard_table));
pages.push(page);
}

View File

@ -3,13 +3,14 @@ use diesel::prelude::*;
use diesel::insert_into;
use rand::rngs::SmallRng;
use rand::{Rng, SeedableRng};
use to_markdown_table::{TableRow};
use manifold::{Db, ManifoldData};
use manifold::error::{ManifoldError, ManifoldResult};
use manifold::models::user::UserInfo;
use manifold::schema::userinfo;
use poise::FrameworkContext;
use poise::serenity_prelude::{Context, Mentionable, Message, RoleId};
use poise::serenity_prelude::{Context, Mention, Mentionable, Message, RoleId, UserId};
use crate::badgey::models::quarantine_channel::QuarantineChannel;
use crate::badgey::schema::xp as xp_table;
use crate::badgey::schema::*;
@ -49,6 +50,47 @@ pub struct Track {
pub xp_award_range_max: i32,
}
pub struct Leaderboard {
pub rows: Vec<LeaderboardRow>
}
#[derive(Clone)]
pub struct LeaderboardRow {
pub rank: i32,
pub uid: i64,
pub user_name: String,
pub value: i64,
}
impl Into<TableRow> for LeaderboardRow {
fn into(self) -> TableRow {
TableRow::new(vec![self.rank.to_string(), self.user_name, self.value.to_string()])
}
}
impl From<&Xp> for LeaderboardRow {
fn from(value: &Xp) -> Self {
LeaderboardRow {
rank: 0,
uid: value.user_id,
user_name: "".to_string(),
value: value.xp_value,
}
}
}
impl Leaderboard {
pub fn get_leaderboard(conn: &Db) -> ManifoldResult<Self> {
let xp_rows: Vec<LeaderboardRow> = xp_table::dsl::xp
.order_by(xp::xp_value.desc())
.load::<Xp>(&mut conn.get()?)?.iter().map(|x| {LeaderboardRow::from(x)}).collect();
Ok(Leaderboard {
rows: xp_rows
})
}
}
impl Xp {
pub fn new(user_id: &i64) -> Self {
Self {
@ -119,12 +161,6 @@ impl Xp {
Ok(())
}
pub fn get_leaderboard(conn: &Db) -> ManifoldResult<Vec<Self>> {
Ok(xp_table::dsl::xp
.order_by(xp::xp_value.desc())
.load::<Self>(&mut conn.get()?)?)
}
pub async fn award(ctx: &Context, fctx: &FrameworkContext<'_, ManifoldData, ManifoldError>, msg: &Message, db: &Db) -> ManifoldResult<()>{
if fctx.user_data().await.user_info.lock().await.get_mut(&msg.author.id.as_u64()).is_none() {
debug!("Tried to add XP to a user we don't know about, aborting.");