From 17fa355ecbe9fd1597e6f05a9b83d4ee71e2690c Mon Sep 17 00:00:00 2001 From: liyunze <50455574+liyunze-coding@users.noreply.github.com> Date: Sat, 3 Jan 2026 19:54:11 +0800 Subject: [PATCH] added FAQ --- .gitignore | 3 +- Cargo.lock | 13 +++++ Cargo.toml | 3 +- README.md | 7 ++- bot_data.sqlite | Bin 12288 -> 0 bytes src/commands/faq.rs | 112 ++++++++++++++++++++++++++++++++++++++++---- src/main.rs | 4 +- 7 files changed, 128 insertions(+), 14 deletions(-) delete mode 100644 bot_data.sqlite diff --git a/.gitignore b/.gitignore index 0b745e2..94f81a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target -.env \ No newline at end of file +.env +*.sqlite \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 63df3e3..5e109e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -453,6 +453,7 @@ checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -475,6 +476,17 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -1185,6 +1197,7 @@ name = "portfolio-roast-bot" version = "0.1.0" dependencies = [ "dotenv", + "futures", "poise", "reqwest", "rusqlite", diff --git a/Cargo.toml b/Cargo.toml index ee1ccf0..7dbd410 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ serde_json = "1.0.145" serenity = "0.12.5" tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] } serde = "1.0.228" -rusqlite = { version = "0.37.0", features = ["bundled"] } \ No newline at end of file +rusqlite = { version = "0.37.0", features = ["bundled"] } +futures = "0.3.31" diff --git a/README.md b/README.md index 9f1ba7a..d451906 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,9 @@ To do: - [ ] Database - [ ] FAQs - [ ] Slash commands -- [ ] Portfolio Roast Forum: One tag only \ No newline at end of file +- [ ] Portfolio Roast Forum: One tag only + +FAQ table +- ID: Primary Key +- title: string +- description: string \ No newline at end of file diff --git a/bot_data.sqlite b/bot_data.sqlite deleted file mode 100644 index 041a60e29778b328573655ffbff63e6a7f81ef65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI#%}T>S5C`zxR1^w+Ae3I`*wW&~s|TYj5=_$?w_r{Z+bsmr)HLe@=&_ILQ#dR3 z(B#mQm+~K&gjr@5^2=$SpTf)%*lQe15= zPr1uG`xfUn{6Ihe0uX=z1Rwwb2tWV=5P$##{#9V&9d`!+Kck(hPaB|LMzL$}~Y zmwp5UAOHafKmY;|fB*y_009U<00IXrfc^h~e=a@^0uX=z1Rwwb2tWV=5P$##An+&f E15( + ctx: Context<'_>, + partial: &'a str, +) -> impl Stream + 'a { + let data = ctx.data(); + + let fetch_faqs = data + .execute_db(|conn| { + let mut stmt = conn.prepare("SELECT ID, title, description FROM faqs")?; + + let faqs: Vec = stmt + .query_map([], |row| { + Ok(Faq { + title: row.get(1)?, + description: row.get(2)?, + }) + })? + .collect::, _>>()?; + + Ok(faqs) + }) + .await; + + let faqs: Vec = fetch_faqs.unwrap_or(vec![]); + + // Now you can use the faqs Vec + // ctx.say(format!("Found {} FAQs", faqs.len())).await?; + + futures::stream::iter(faqs) + .filter(move |faq| futures::future::ready(faq.title.starts_with(partial))) + .map(|faq| faq.title) +} + +#[poise::command(slash_command, subcommands("view", "add"))] pub async fn faq(_ctx: Context<'_>) -> Result<(), Error> { Ok(()) } +/// View messages +#[poise::command(prefix_command, slash_command)] +pub async fn view( + ctx: Context<'_>, + #[description = "FAQ Title"] + #[autocomplete = "autocomplete_faq_titles"] + faq_title: String, +) -> Result<(), Error> { + let data = ctx.data(); + + let faqs = data + .execute_db(move |conn| { + let mut stmt = conn.prepare(&format!("SELECT ID, title, description FROM faqs WHERE title='{}'", &faq_title))?; + + let faqs: Vec = stmt + .query_map([], |row| { + Ok(Faq { + // id: row.get(0)?, + title: row.get(1)?, + description: row.get(2)?, + }) + })? + .collect::, _>>()?; + + Ok(faqs) + }) + .await?; + + let faq = faqs.first().unwrap(); + + // Now you can use the faqs Vec + // ctx.say(format!("# {}\n{}", faqs[0].title, faqs[0].description )).await?; + + // #131416 19,20,22 + let embed = CreateEmbed::new().title(&faq.title).description(&faq.description); + + ctx.send(CreateReply::default().embed(embed)).await?; + + Ok(()) +} + /// A subcommand of `parent` #[poise::command( prefix_command, slash_command, required_permissions = "MANAGE_MESSAGES" // mod only )] -pub async fn add(ctx: Context<'_>) -> Result<(), Error> { - ctx.say("You invoked the first child command!").await?; - Ok(()) -} +pub async fn add( + ctx: Context<'_>, + #[description = "FAQ title"] title: String, + #[description = "FAQ description"] description: String, +) -> Result<(), Error> { + let data = ctx.data(); + + let result = data + .execute_db(|conn| { + conn.execute( + "INSERT INTO faqs (title, description) VALUES (?1, ?2)", + [title, description], + ) + }) + .await?; + + // Now you can use the faqs Vec + ctx.say(format!("{} rows affected", result)).await?; -/// Another subcommand of `parent` -#[poise::command(prefix_command, slash_command)] -pub async fn child2(ctx: Context<'_>) -> Result<(), Error> { - ctx.say("You invoked the second child command!").await?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index a47b7a4..43db73e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ pub struct Data { } impl Data { - // Helper method to safely execute database operations + // helper method to safely execute database operations pub async fn execute_db(&self, f: F) -> Result where F: FnOnce(&Connection) -> Result + Send + 'static, @@ -80,7 +80,7 @@ async fn main() { let framework = poise::Framework::builder() .options(poise::FrameworkOptions { - commands: vec![commands::info::help()], + commands: vec![commands::info::help(), commands::faq::faq()], event_handler: |ctx, event, framework, data| { Box::pin(event_handler(ctx, event, framework, data)) },