updates from feedback

This commit is contained in:
Tanner Sommers 2024-11-25 21:54:39 -06:00
parent e9d54a83f5
commit 4d89ca3ca5
20 changed files with 487 additions and 59 deletions

1
Cargo.lock generated
View File

@ -2296,6 +2296,7 @@ dependencies = [
"dotenv",
"libloading",
"poise",
"rand",
"reqwest 0.12.9",
"serde",
"serde_json",

View File

@ -19,3 +19,4 @@ reqwest = "0.12.9"
serde_json = "1.0.133"
libloading = "0.8.5"
time = "0.3.36"
rand = "0.8.5"

View File

@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "UPDATE users SET actions_allowed = ?, about = ?, pronouns = ? WHERE id = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "2967f5a9c1de51c929ce5c2e4f8caab31e80b2c3425275cdb6f73de4d56c0464"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "INSERT INTO kv_store (`key`, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "29b2636e2637f315c99058df5316f77dbe966de004cd11b3ed0e567f05e15adf"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "INSERT INTO users (discord_id) VALUES (?)",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "46c83fa22dba08a9f016cf34411af5d5c37f8daa5afb9844daa5dbebf0555c98"
}

View File

@ -0,0 +1,64 @@
{
"db_name": "MySQL",
"query": "SELECT * FROM users WHERE discord_id = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": {
"type": "LongLong",
"flags": "NOT_NULL | PRIMARY_KEY | UNSIGNED | AUTO_INCREMENT",
"max_size": 20
}
},
{
"ordinal": 1,
"name": "discord_id",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | NO_DEFAULT_VALUE",
"max_size": 1020
}
},
{
"ordinal": 2,
"name": "actions_allowed",
"type_info": {
"type": "Tiny",
"flags": "",
"max_size": 4
}
},
{
"ordinal": 3,
"name": "about",
"type_info": {
"type": "Blob",
"flags": "BLOB",
"max_size": 262140
}
},
{
"ordinal": 4,
"name": "pronouns",
"type_info": {
"type": "VarString",
"flags": "",
"max_size": 1020
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
true,
true,
true
]
},
"hash": "470f9eb401d38f59e069814bfcc766716527c8ed539c9cc4b8f2646fdcfee83d"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "DELETE FROM users WHERE discord_id = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "73b6b72dc96792688162da874363e0a567dc55542daa99e2f91902497563b8d9"
}

View File

@ -0,0 +1,74 @@
{
"db_name": "MySQL",
"query": "SELECT * FROM quotes WHERE user_id = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "quote_id",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT",
"max_size": 11
}
},
{
"ordinal": 1,
"name": "user_id",
"type_info": {
"type": "LongLong",
"flags": "NOT_NULL | MULTIPLE_KEY | NO_DEFAULT_VALUE",
"max_size": 20
}
},
{
"ordinal": 2,
"name": "username",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | NO_DEFAULT_VALUE",
"max_size": 1020
}
},
{
"ordinal": 3,
"name": "quote",
"type_info": {
"type": "Blob",
"flags": "NOT_NULL | BLOB | NO_DEFAULT_VALUE",
"max_size": 262140
}
},
{
"ordinal": 4,
"name": "added_by",
"type_info": {
"type": "LongLong",
"flags": "NOT_NULL | MULTIPLE_KEY | NO_DEFAULT_VALUE",
"max_size": 20
}
},
{
"ordinal": 5,
"name": "added_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | UNSIGNED | BINARY | TIMESTAMP",
"max_size": 19
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
false,
false
]
},
"hash": "b4e2733da7f08dcfe9cdb932a746b6c9c4fe3a6205b857f0932d2c7ed2a9b172"
}

View File

@ -0,0 +1,34 @@
{
"db_name": "MySQL",
"query": "SELECT * FROM kv_store WHERE `key` = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "key",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | PRIMARY_KEY | NO_DEFAULT_VALUE",
"max_size": 1020
}
},
{
"ordinal": 1,
"name": "value",
"type_info": {
"type": "Blob",
"flags": "BLOB",
"max_size": 262140
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
true
]
},
"hash": "c7f221e5d730a3ba86ad4100a1303209852fe85c560657b0b165a45630f79bae"
}

View File

@ -0,0 +1,74 @@
{
"db_name": "MySQL",
"query": "SELECT * FROM quotes ORDER BY RAND() LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "quote_id",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT",
"max_size": 11
}
},
{
"ordinal": 1,
"name": "user_id",
"type_info": {
"type": "LongLong",
"flags": "NOT_NULL | MULTIPLE_KEY | NO_DEFAULT_VALUE",
"max_size": 20
}
},
{
"ordinal": 2,
"name": "username",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | NO_DEFAULT_VALUE",
"max_size": 1020
}
},
{
"ordinal": 3,
"name": "quote",
"type_info": {
"type": "Blob",
"flags": "NOT_NULL | BLOB | NO_DEFAULT_VALUE",
"max_size": 262140
}
},
{
"ordinal": 4,
"name": "added_by",
"type_info": {
"type": "LongLong",
"flags": "NOT_NULL | MULTIPLE_KEY | NO_DEFAULT_VALUE",
"max_size": 20
}
},
{
"ordinal": 5,
"name": "added_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | UNSIGNED | BINARY | TIMESTAMP",
"max_size": 19
}
}
],
"parameters": {
"Right": 0
},
"nullable": [
false,
false,
false,
false,
false,
false
]
},
"hash": "d73179806cd00f9fcd07a40acfebed83dabca46bd3bf41478bc62243cfa03066"
}

View File

@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "INSERT INTO quotes (user_id, username, quote, added_by) VALUES (?, ?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "f42a8f42a7eafa58947402dfc4b597a09612da4d37059ef067233b5525b72ff6"
}

View File

@ -1,12 +1,14 @@
use crate::{Context, Error};
use poise::CreateReply;
use serenity::{all::CreateEmbed, model::colour};
use reqwest::Client;
use serde_json::Value;
use crate::{Context, Error};
use serenity::all::CreateAttachment;
/// Returns a random cat image, along with a random cat fact.
#[poise::command(slash_command)]
pub async fn cta(ctx: Context<'_>) -> Result<(), Error> {
ctx.defer().await?;
let cat_fact_res = Client::new()
.get("https://catfact.ninja/fact")
.send()
@ -23,12 +25,11 @@ pub async fn cta(ctx: Context<'_>) -> Result<(), Error> {
let cat_image: Value = serde_json::from_str(&cat_image_res.text().await?)?;
let cat_image = cat_image[0]["url"].as_str().unwrap();
let embed = CreateEmbed::default()
.title("Random Cat")
.description(cat_fact)
.image(cat_image)
.color(colour::Colour::from_rgb(0, 255, 255));
ctx.send(CreateReply::default().embed(embed)).await?;
ctx.send(
CreateReply::default()
.content(format!("*{}*", cat_fact))
.attachment(CreateAttachment::url(ctx.http(), cat_image).await?),
)
.await?;
Ok(())
}

56
src/commands/cuteness.rs Normal file
View File

@ -0,0 +1,56 @@
use poise::CreateReply;
use rand::Rng;
use serenity::all::{CreateAllowedMentions, User};
use crate::{Context, Error};
/// Determine a user's cuteness
#[poise::command(slash_command)]
pub async fn cutenesss(
ctx: Context<'_>,
#[description = "The user to check"] user: User,
) -> Result<(), Error> {
let thinking_messages = [
":thinking: Thinking super hard...",
":gear: Calculating...",
":bar_chart: Crunching the numbers...",
":bulb: Looking at the data...",
":mag: Investigating...",
":clipboard: Finalizing the report...",
];
let current_thinking_index = 0;
let thinking_message = ctx.say(thinking_messages[current_thinking_index]).await?;
// Wait between .5 and 1.5 seconds for each message, then edit the message with the next thinking message
// On the last message, edit the message with the final message and wait 1.5 second
for i in 1..thinking_messages.len() {
let wait_time = rand::thread_rng().gen_range(500..1501);
// Are we on the last message?
if i == thinking_messages.len() - 1 {
tokio::time::sleep(std::time::Duration::from_millis(1500)).await;
} else {
tokio::time::sleep(std::time::Duration::from_millis(wait_time)).await;
}
thinking_message
.edit(ctx, CreateReply::default().content(thinking_messages[i]))
.await?;
}
thinking_message
.edit(
ctx,
CreateReply::default()
.content(format!(
"I have determined that {} is {}% cute!",
user.name,
rand::thread_rng().gen_range(0..101)
))
.allowed_mentions(CreateAllowedMentions::default().users(vec![user.id])),
)
.await?;
Ok(())
}

View File

@ -2,11 +2,13 @@ use crate::{Context, Error};
use poise::CreateReply;
use reqwest::Client;
use serde_json::Value;
use serenity::{all::CreateEmbed, model::colour};
use serenity::all::CreateAttachment;
/// Returns a random dog image.
#[poise::command(slash_command)]
pub async fn dog(ctx: Context<'_>) -> Result<(), Error> {
ctx.defer().await?;
let dog_res = Client::new()
.get("https://dog.ceo/api/breeds/image/random")
.send()
@ -15,11 +17,11 @@ pub async fn dog(ctx: Context<'_>) -> Result<(), Error> {
let dog: Value = serde_json::from_str(&dog_res.text().await?)?;
let dog = dog["message"].as_str().unwrap();
let embed = CreateEmbed::default()
.title("Random Dog")
.image(dog)
.color(colour::Colour::from_rgb(0, 255, 255));
ctx.send(CreateReply::default().embed(embed)).await?;
ctx.send(
CreateReply::default()
.content("Here's a random dog image:")
.attachment(CreateAttachment::url(ctx.http(), dog).await?),
)
.await?;
Ok(())
}

View File

@ -4,6 +4,10 @@ use std::{
time::{SystemTime, UNIX_EPOCH},
};
use poise::CreateReply;
use serenity::all::GetMessages;
use tracing::{info, warn};
use crate::{Context, Error};
/// Evaluate rust code
@ -16,13 +20,36 @@ pub async fn eval(
// Check if the user is an owner
if !authed_users.contains(&ctx.author().id.into()) {
ctx.say(":x: You are not authorized to run this command")
let channel_id = ctx.channel_id();
// Get messages in the channel (up to 100)
let messages = channel_id
.messages(&ctx, GetMessages::new().limit(100))
.await?;
// Find the most recent message that is not a bot message, and starts with ~eval
let last_eval = messages.iter().find(|msg| {
!msg.author.bot && msg.content.starts_with("~eval") && msg.author.id == ctx.author().id
});
// If the user has already run an eval command, delete the message
if last_eval.is_some() {
let _ = last_eval.unwrap().delete(&ctx).await;
info!(
"User {} tried to run eval without permission, and I deleted the message",
ctx.author().id,
);
} else {
warn!(
"User {} tried to run eval without permission, but I couldn't delete the message",
ctx.author().id
);
}
return Ok(());
}
ctx.say(":gear: Processing...").await?;
let org_msg = ctx.say(":gear: Processing...").await?;
// Create a temporary directory for the file
let temp_dir = env::temp_dir();
@ -35,7 +62,14 @@ pub async fn eval(
// Write the code to a temporary file
if let Err(err) = fs::write(&file_path, code.code) {
ctx.say(format!("Error writing to temporary file: {}", err))
org_msg
.edit(
ctx,
CreateReply::default().content(format!(
"<:error:1310650177056538655> Error writing to file: {}",
err
)),
)
.await?;
return Ok(());
}
@ -50,10 +84,12 @@ pub async fn eval(
match compile_output {
Ok(output) if output.status.success() => {
ctx.say(
"<:success:1310650176037453834> Compilation successful. Running the executable...",
)
.await?;
org_msg
.edit(
ctx,
CreateReply::default().content("<:success:1310650176037453834> Compilation successful. Running the executable..."),
)
.await?;
// Run the compiled executable
let output = Command::new(&executable_path).output();
@ -62,45 +98,61 @@ pub async fn eval(
Ok(output) => {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
ctx.say(format!(
"**Output:**\n```\n{}\n```\n**Errors:**\n```\n{}\n```",
if stdout.trim().is_empty() {
"<no output>"
} else {
stdout.trim()
},
if stderr.trim().is_empty() {
"<no errors>"
} else {
stderr.trim()
}
))
.await?;
// Only show stdout/stderr if they are not empty, edit original message
let msg = "<:success:1310650176037453834> Exection successful";
let msg = if !stdout.is_empty() {
format!("{}\n\n**stdout**:\n```\n{}\n```", msg, stdout)
} else {
msg.to_string()
};
let msg = if !stderr.is_empty() {
format!("{}\n\n**stderr**:\n```\n{}\n```", msg, stderr)
} else {
msg.to_string()
};
org_msg
.edit(ctx, CreateReply::default().content(msg))
.await?;
}
Err(err) => {
ctx.say(format!(
"<:error:1310650177056538655> Error running the executable: {}",
err
))
.await?;
org_msg
.edit(
ctx,
CreateReply::default().content(format!(
"<:error:1310650177056538655> Error running executable: {}",
err
)),
)
.await?;
}
}
}
Ok(output) => {
// If compilation failed, display the compiler error output
let stderr = String::from_utf8_lossy(&output.stderr);
ctx.say(format!(
"<:error:1310650177056538655> Compilation failed:\n```\n{}\n```",
stderr
))
.await?;
org_msg
.edit(
ctx,
CreateReply::default().content(format!(
"<:error:1310650177056538655> Compilation failed:\n```\n{}\n```",
stderr
)),
)
.await?;
}
Err(err) => {
ctx.say(format!(
"<:error:1310650177056538655> Error invoking rustc: {}",
err
))
.await?;
org_msg
.edit(
ctx,
CreateReply::default().content(format!(
"<:error:1310650177056538655> Error invoking rustc: {}",
err
)),
)
.await?;
}
}

View File

@ -5,4 +5,5 @@ pub mod dog;
pub mod profile;
pub mod action;
pub mod eval;
pub mod quote;
pub mod quote;
pub mod cuteness;

View File

@ -9,7 +9,6 @@ pub async fn quote_action(
#[description = "The target message to quote"] message: Message,
) -> Result<(), Error> {
let quote = crate::structs::quote::Quote {
quote_id: 0,
user_id: message.author.id.into(),
username: message.author.name.clone(),
quote: message.content.clone(),
@ -22,6 +21,12 @@ pub async fn quote_action(
return Ok(());
}
// Cant quote the bot
if message.author.bot {
ctx.say(":x: You can't quote a bot").await?;
return Ok(());
}
ctx.data().database_controller.quote_create(quote).await?;
ctx.say(":white_check_mark: Okay, I've immortalized that message for you :)")
.await?;

View File

@ -117,7 +117,6 @@ impl DatabaseController {
match quote.await {
Ok(q) => Ok(Some(Quote {
quote_id: q.quote_id,
user_id: q.user_id,
username: q.username,
quote: q.quote,
@ -137,7 +136,6 @@ impl DatabaseController {
let mut quotes = Vec::new();
for q in quote {
quotes.push(Quote {
quote_id: q.quote_id,
user_id: q.user_id,
username: q.username,
quote: q.quote,

View File

@ -182,6 +182,7 @@ async fn main() {
commands::quote::quote_action(),
commands::quote::random_quote(),
commands::quote::user_quotes(),
commands::cuteness::cutenesss(),
],
event_handler: |ctx, event, framework, data| {
Box::pin(event_handler(ctx, event, framework, data))
@ -205,8 +206,13 @@ async fn main() {
uptime: std::time::Instant::now(),
config,
vouch_store: Mutex::new(Vec::new()),
// Sticks, Emi, Katie
owners: vec![1017196087276220447, 272871217256726531, 1033331958291369984],
// Sticks, Emi, Katie, Eva
owners: vec![
1017196087276220447,
272871217256726531,
1033331958291369984,
1138865297101705347,
],
})
})
})

View File

@ -2,7 +2,6 @@ use time::OffsetDateTime;
#[derive(Debug)]
pub struct Quote {
pub quote_id: i32,
pub user_id: i64,
pub username: String,
pub quote: String,