added lock commands

This commit is contained in:
liyunze 2026-09-25 12:59:15 +08:00
parent 46c92f5a59
commit bb4707ad59
7 changed files with 331 additions and 23 deletions

View file

@ -1,3 +1,4 @@
pub mod faq;
pub mod forum;
pub mod info;
pub mod lock;

View file

@ -1,3 +1,4 @@
use crate::utils::format::format_embed_description;
use crate::{Context, Error};
use futures::{Stream, StreamExt};
use poise::CreateReply;
@ -10,11 +11,6 @@ struct Faq {
description: String,
}
fn format_embed_description<S: Into<String>>(description: S) -> Result<String, Error> {
let string_val = description.into();
Ok(str::replace(&string_val, "\\n", "\n"))
}
fn faq_exists(conn: &Connection, faq: &str, guild_id: &u64) -> Result<bool, Error> {
let guild_id = guild_id.to_string();
let exists: bool = conn.query_row(
@ -93,26 +89,33 @@ pub async fn view(
let guild_id = server_guild_id.to_string();
move |conn| {
let mut stmt = conn.prepare(
"SELECT id, guild_id, title, description FROM faqs WHERE title = ?1 AND guild_id = ?2"
)?;
let mut stmt = conn.prepare(
"SELECT title, description FROM faqs WHERE title = ?1 AND guild_id = ?2",
)?;
let faqs: Vec<Faq> = stmt
.query_map([&faq_title, &guild_id], |row| {
Ok(Faq {
// id: row.get(0)?,
// guild_id: row.get(1)?,
title: row.get(2)?,
description: row.get(3)?,
})
})?
.collect::<Result<Vec<_>, _>>()?;
let faqs: Vec<Faq> = stmt
.query_map([&faq_title, &guild_id], |row| {
Ok(Faq {
title: row.get(0)?,
description: row.get(1)?,
})
})?
.collect::<Result<Vec<_>, _>>()?;
Ok(faqs)
}})
Ok(faqs)
}
})
.await?;
let faq = faqs.first().unwrap();
let Some(faq) = faqs.first() else {
let embed = CreateEmbed::new()
.title("Error 404")
.description("FAQ not found");
ctx.send(CreateReply::default().ephemeral(true).embed(embed))
.await?;
return Ok(());
};
let embed_description = format_embed_description(&faq.description).expect("Format error");
let embed = CreateEmbed::new()
@ -143,6 +146,7 @@ pub async fn preview(
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
let guild_id = server_guild_id.to_string();
move |conn| {
let mut stmt = conn.prepare(
"SELECT id, guild_id, title, description FROM faqs WHERE title = ?1 AND guild_id = ?2"
@ -163,9 +167,8 @@ pub async fn preview(
}})
.await?;
let faq = faqs.first().unwrap();
let faq = faqs.first().expect("FAQ not found");
// let embed_description = format_embed_description(&faq.description).expect("Format error");
let embed = CreateEmbed::new().title(&faq.title).description(format!(
"```
{}

281
src/commands/lock.rs Normal file
View file

@ -0,0 +1,281 @@
use crate::utils::format::format_embed_description;
use crate::{Context, Error};
use poise::CreateReply;
use rusqlite::Connection;
use serenity::all::CreateEmbed;
use serenity::builder::EditThread;
struct LockEmbed {
title: String,
description: String,
}
fn lock_message_exists(conn: &Connection, guild_id: &u64) -> Result<bool, Error> {
let guild_id = guild_id.to_string();
let exists: bool = conn.query_row(
"SELECT EXISTS(SELECT 1 FROM lock WHERE guild_id = ?1)",
[&guild_id],
|row| row.get(0),
)?;
Ok(exists)
}
#[poise::command(
slash_command,
subcommands("vibecoded", "preview", "add", "edit", "delete"),
guild_only
)]
pub async fn lock(_ctx: Context<'_>) -> Result<(), Error> {
Ok(())
}
/// Post the vibe coded slop embed message
#[poise::command(
prefix_command,
slash_command,
required_permissions = "MANAGE_MESSAGES" // mod only
)]
pub async fn vibecoded(
ctx: Context<'_>,
#[description = "additional comment"] comment_option: Option<String>,
) -> Result<(), Error> {
let data = ctx.data();
// lock thread, if it's a thread in a forum
// let thread_lock = EditThread::new().locked(true);
let mut channel = ctx.guild_channel().await.expect("Not a thread");
channel
.edit_thread(ctx, EditThread::new().locked(true))
.await
.expect("Failed to lock thread, check permissions");
let lock_messages = data
.execute_db({
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
let guild_id = server_guild_id.to_string();
move |conn| {
let mut stmt =
conn.prepare("SELECT title, description FROM lock WHERE guild_id = ?1")?;
let lock_messages: Vec<LockEmbed> = stmt
.query_map([&guild_id], |row| {
Ok(LockEmbed {
title: row.get(0)?,
description: row.get(1)?,
})
})?
.collect::<Result<Vec<_>, _>>()?;
Ok(lock_messages)
}
})
.await?;
let Some(lock_message) = lock_messages.first() else {
let embed = CreateEmbed::new()
.title("Error 404")
.description("Lock message not found");
ctx.send(CreateReply::default().embed(embed).ephemeral(true))
.await?;
return Ok(());
};
let mut embed_description =
format_embed_description(&lock_message.description).expect("Format error");
if !comment_option.is_none() {
let comment = comment_option.expect("Comment error");
let new_description = format!(
"{}\n\n**Additional Comment(s)**\n{}",
&lock_message.description, comment
);
embed_description = format_embed_description(new_description).expect("Format error");
}
let embed = CreateEmbed::new()
.title(&lock_message.title)
.description(embed_description)
.color(0xff0000);
ctx.send(CreateReply::default().embed(embed)).await?;
Ok(())
}
/// Add vibe coded slop embed message
#[poise::command(
prefix_command,
slash_command,
required_permissions = "MANAGE_MESSAGES" // mod only
)]
pub async fn add(
ctx: Context<'_>,
#[description = "Lock message title"] title: String,
#[description = "Lock message description"] description: String,
) -> Result<(), Error> {
let data: &crate::Data = ctx.data();
let result = data
.execute_db({
let title = title.clone();
let description = description.clone();
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
let guild_id = server_guild_id.get();
move |conn| {
let exists = lock_message_exists(conn, &guild_id).unwrap_or(false);
if !exists {
conn.execute(
"INSERT INTO lock (guild_id, title, description) VALUES (?1, ?2, ?3)",
[guild_id.to_string(), title, description],
)
} else {
Ok(0)
}
}
})
.await?;
if result == 1 {
let embed_description = format_embed_description(description).expect("Format error");
let embed = CreateEmbed::new()
.title(format!("Added Lock Message: {}", &title))
.description(embed_description);
ctx.send(CreateReply::default().embed(embed)).await?;
} else {
let embed = CreateEmbed::new()
.title(format!("Error adding lock message: {}", &title))
.description("Lock message already exists!");
ctx.send(CreateReply::default().embed(embed)).await?;
}
Ok(())
}
/// Preview lock message
#[poise::command(
prefix_command,
slash_command,
required_permissions = "MANAGE_MESSAGES" // mod only
)]
pub async fn preview(ctx: Context<'_>) -> Result<(), Error> {
let data = ctx.data();
let lock_messages = data
.execute_db({
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
let guild_id = server_guild_id.to_string();
move |conn| {
let mut stmt =
conn.prepare("SELECT title, description FROM lock WHERE guild_id = ?1")?;
let lock_messages: Vec<LockEmbed> = stmt
.query_map([&guild_id], |row| {
Ok(LockEmbed {
title: row.get(0)?,
description: row.get(1)?,
})
})?
.collect::<Result<Vec<_>, _>>()?;
Ok(lock_messages)
}
})
.await?;
let lock_message = lock_messages.first().expect("Lock message not found");
let embed = CreateEmbed::new()
.title(&lock_message.title)
.description(format!(
"```
{}
```",
&lock_message.description
));
ctx.send(CreateReply::default().embed(embed)).await?;
Ok(())
}
/// Edit lock message
#[poise::command(
prefix_command,
slash_command,
required_permissions = "MANAGE_MESSAGES"
)]
pub async fn edit(
ctx: Context<'_>,
#[description = "Title"] title: String,
#[description = "Description"] description: String,
) -> Result<(), Error> {
let data = ctx.data();
let result = data
.execute_db({
let title = title.clone();
let description = description.clone();
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
let guild_id = server_guild_id.get();
move |conn| {
conn.execute(
"UPDATE lock SET description = ?3, title = ?2 WHERE guild_id = ?1",
[guild_id.to_string(), title, description],
)
}
})
.await?;
let embed_description = format_embed_description(description).expect("Format error");
if result == 1 {
let embed = CreateEmbed::new()
.title(format!("Edited lock message: {}", &title))
.description(&embed_description);
ctx.send(CreateReply::default().embed(embed)).await?;
} else {
let embed = CreateEmbed::new()
.title(format!("Error editing lock message: {}", &title))
.description(format!("{} rows were affected", result));
ctx.send(CreateReply::default().embed(embed)).await?;
}
Ok(())
}
/// Delete lock message
#[poise::command(
prefix_command,
slash_command,
required_permissions = "MANAGE_MESSAGES"
)]
pub async fn delete(ctx: Context<'_>) -> Result<(), Error> {
let data = ctx.data();
let server_guild_id = ctx.guild_id().expect("Guild ID not found");
let guild_id = server_guild_id.to_string();
let result = data
.execute_db({
move |conn| conn.execute("DELETE FROM lock WHERE guild_id = ?1", [guild_id])
})
.await?;
if result == 1 {
let embed = CreateEmbed::new().title(format!("Deleted lock message for this server"));
ctx.send(CreateReply::default().embed(embed)).await?;
} else {
let embed = CreateEmbed::new()
.title(format!("Error deleting lock message, ask Ryan"))
.description(format!("{} rows were affected", result));
ctx.send(CreateReply::default().embed(embed)).await?;
}
Ok(())
}

View file

@ -62,6 +62,20 @@ pub fn init_tables(conn: &Connection) -> Result<()> {
.expect("Forum Channels Table Creation error");
}
let lock_table_exists = table_exists(conn, "lock").expect("Lock table exists error");
if !lock_table_exists {
conn.execute(
"CREATE TABLE lock (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT NOT NULL UNIQUE,
title TEXT NOT NULL,
description TEXT NOT NULL
)",
(),
)
.expect("Lock Table Creation error");
}
// if we need to create more tables we'll use this function
Ok(())
}

View file

@ -6,6 +6,7 @@ use tokio::sync::Mutex;
mod commands;
mod database;
mod events;
mod utils;
use crate::database::database::{init_db, init_tables};
// Types used by all command functions
@ -89,6 +90,7 @@ async fn main() {
commands::info::help(),
commands::faq::faq(),
commands::forum::forum(),
commands::lock::lock(),
],
event_handler: |ctx, event, framework, data| {
Box::pin(event_handler(ctx, event, framework, data))

1
src/utils.rs Normal file
View file

@ -0,0 +1 @@
pub mod format;

6
src/utils/format.rs Normal file
View file

@ -0,0 +1,6 @@
use crate::Error;
pub fn format_embed_description<S: Into<String>>(description: S) -> Result<String, Error> {
let string_val = description.into();
Ok(str::replace(&string_val, "\\n", "\n"))
}