From 12873d98d360e3fdfadbb81a659d144a06147f4d Mon Sep 17 00:00:00 2001 From: washbin <76929116+washbin@users.noreply.github.com> Date: Sat, 15 Oct 2022 15:31:22 +0545 Subject: [PATCH] let's test --- src/api/hero.rs | 24 ++++++++++------ src/commands/hero.rs | 22 +++++++++++++- src/events.rs | 3 ++ src/fuzzy.rs | 68 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 106 insertions(+), 11 deletions(-) diff --git a/src/api/hero.rs b/src/api/hero.rs index 073c4c3..2ed7871 100644 --- a/src/api/hero.rs +++ b/src/api/hero.rs @@ -33,16 +33,22 @@ pub struct HeroResponse { pub list: Vec, } +pub async fn get_all_heros(database: &Database) -> Option> { + Some( + database + .request::( + "https://contributors.novu.co/contributors", + "heros", + database.config.cache_heros_ttl, + ) + .await + .ok()? + .list, + ) +} + pub async fn get_random_hero(database: &Database) -> Option { - let hero_list = database - .request::( - "https://contributors.novu.co/contributors", - "heros", - database.config.cache_heros_ttl, - ) - .await - .ok()? - .list; + let hero_list = get_all_heros(database).await?; Some( hero_list diff --git a/src/commands/hero.rs b/src/commands/hero.rs index b42d260..eac831d 100644 --- a/src/commands/hero.rs +++ b/src/commands/hero.rs @@ -4,7 +4,8 @@ use serenity::model::prelude::component::ButtonStyle; use serenity::model::prelude::interaction::application_command::{ ApplicationCommandInteraction, CommandDataOptionValue, }; -use serenity::model::prelude::interaction::InteractionResponseType; +use serenity::model::prelude::interaction::autocomplete::AutocompleteInteraction; +use serenity::model::prelude::interaction::{Interaction, InteractionResponseType}; use serenity::model::prelude::ReactionType; use serenity::model::Timestamp; use serenity::prelude::Context; @@ -12,6 +13,7 @@ use serenity::utils::Colour; use crate::api::hero::{get_hero, get_random_hero, Hero, Pulls}; use crate::database::Database; +use crate::fuzzy; use crate::utils::embeds::error_embed; fn link_button(name: &str, link: String, emoji: ReactionType) -> CreateButton { @@ -171,6 +173,23 @@ pub async fn hero(ctx: Context, command: ApplicationCommandInteraction) { } } +pub async fn handle_autocomplete( + ctx: Context, + command: &AutocompleteInteraction, + _interaction: Interaction, +) { + let ctx_cloned = ctx.clone(); + let data = ctx_cloned.data.read().await; + let database = data.get::().unwrap(); + + let search = fuzzy::search_hero(database, command.data.options[0].value.clone()).await; + + command + .create_autocomplete_response(ctx.http, |response| response.set_choices(search)) + .await + .unwrap(); +} + pub async fn random_hero(ctx: Context, command: ApplicationCommandInteraction) { let ctx_cloned = ctx.clone(); let data = ctx_cloned.data.read().await; @@ -190,6 +209,7 @@ pub fn register_hero(command: &mut CreateApplicationCommand) -> &mut CreateAppli .name("github_username") .description("The github username of the contributor to look for") .kind(CommandOptionType::String) + .set_autocomplete(true) .required(true) }) } diff --git a/src/events.rs b/src/events.rs index 870f5ce..49fe861 100644 --- a/src/events.rs +++ b/src/events.rs @@ -68,6 +68,9 @@ impl EventHandler for Handler { "team" => { commands::team::handle_autocomplete(ctx, command, interaction.to_owned()).await } + "hero" => { + commands::hero::handle_autocomplete(ctx, command, interaction.to_owned()).await + } other_commands => println!("No autocompletions for {}", other_commands), }, other_interactions => println!("Unhandled interaction {:?}", other_interactions), diff --git a/src/fuzzy.rs b/src/fuzzy.rs index 2a680a9..43191c4 100644 --- a/src/fuzzy.rs +++ b/src/fuzzy.rs @@ -3,7 +3,10 @@ use serde_json::{json, Value}; use simsearch::{SearchOptions, SimSearch}; use crate::{ - api::team::{get_leaderboard, Team}, + api::{ + hero::{get_all_heros, Hero}, + team::{get_leaderboard, Team}, + }, database::Database, }; @@ -75,3 +78,66 @@ pub async fn search_teams(database: &Database, query: Option) -> Value { json!({}) } } + +pub async fn search_hero(database: &Database, query: Option) -> Value { + if let Some(query) = query { + let hero_list = match get_all_heros(database).await { + Some(hero_list) => hero_list, + None => { + return json!({ + "error": "Failed to get hero list" + }) + } + }; + + let mut engine = + SimSearch::new_with(SearchOptions::new().case_sensitive(false).threshold(0.82)); + + for hero in &hero_list { + engine.insert(hero.github.clone(), &hero.github); + } + + let query: String = serde_json::from_value(query.clone()).unwrap(); + + let mut res = engine.search(&query); + + if res.is_empty() { + for hero in &hero_list { + res.push(hero.github.clone()) + } + + if query.is_empty() {} + + res.retain(|x| x.starts_with(&query)); + } + + res.truncate(10); + + let iter = res.iter_mut(); + + let mut suggestions: Vec = Vec::new(); + + for (_index, slug) in iter.enumerate() { + let hero = hero_list + .iter() + .find(|&p| p.github == slug.clone()) + .cloned(); + + if let Some(hero) = hero { + suggestions.push(hero); + } + } + + let suggestions: Vec = suggestions + .iter() + .map(|x| Suggestion { + value: x.github.clone(), + name: x.github.clone(), + }) + .collect(); + + json!(suggestions) + } else { + json!({}) + } +}