renamed count commands and added tags commands

This commit is contained in:
2022-02-13 20:28:59 +05:30
parent 6461fa4b94
commit 5f8ceb94b2
7 changed files with 381 additions and 24 deletions

View File

@@ -17,3 +17,4 @@ features = ["cache", "framework", "standard_framework", "rustls_backend", "unsta
[dependencies.tokio]
version = "1.0"
features = ["macros", "signal", "rt-multi-thread"]

View File

@@ -30,7 +30,7 @@
nativeBuildInputs = with pkgs; [
rust-bin.nightly.latest.default
];
cargoSha256 = "sha256-K+WHOEo6reNfcs7pOZZmHZfZl4pUqlykfTdqgSyVURU=";
cargoSha256 = "sha256-0Apd8a9IdQJ8Mj5Xvm1/wM0PSc7PgciIptmz/KGx8XM=";
};
}
);

View File

@@ -3,3 +3,17 @@ CREATE TABLE IF NOT EXISTS words (
name varchar not null,
reg varchar not null,
owner varchar );
ALTER SEQUENCE words_id_seq RESTART;
UPDATE words SET id = DEFAULT;
CREATE TABLE IF NOT EXISTS tags (
id serial primary key,
name varchar unique not null,
value varchar not null,
owner varchar );
ALTER SEQUENCE tags_id_seq RESTART;
UPDATE tags SET id = DEFAULT;
CREATE EXTENSION IF NOT EXISTS fuzzystrmatch;

View File

@@ -14,7 +14,8 @@ use serenity::{
use tokio_postgres::Row;
#[command]
pub async fn kitna(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
#[aliases("kitna")]
pub async fn count(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
if query == "" {
msg.reply(ctx, "bruh kitna kya?").await?;
@@ -29,14 +30,14 @@ pub async fn kitna(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let id = msg.author.id.to_string();
let mut query_helper = db
.query(
format!("select name from words where '{}' ~ reg", query).as_str(),
format!("SELECT name FROM words WHERE '{}' ~ reg", query).as_str(),
&[],
)
.await?;
if query_helper.is_empty() {
query_helper = db
.query(
format!("select name from words where name='{}'", query).as_str(),
format!("SELECT name FROM words WHERE name='{}'", query).as_str(),
&[],
)
.await?;
@@ -44,7 +45,7 @@ pub async fn kitna(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
msg.reply(
ctx,
format!(
"No entry for '{}' found. If you want to add it, run ',count add {}&<regex>'",
"No entry for '{}' found. If you want to add it, run ',cadd {}&<regex>'",
query, query
),
)
@@ -61,7 +62,7 @@ pub async fn kitna(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let name: &str = row.get(0);
let query_result: i32 = db
.query_one(
format!("select count from user{} where name='{}'", id, name).as_str(),
format!("SELECT count FROM user{} WHERE name='{}'", id, name).as_str(),
&[],
)
.await?
@@ -73,11 +74,11 @@ pub async fn kitna(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
}
#[command]
pub async fn add(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
pub async fn cadd(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
let queries = query.splitn(2, "&").collect::<Vec<&str>>();
if queries.len() != 2 {
msg.reply(ctx, "Please use the proper syntax: `,count add <name>&<regex>`\nIf you don't know what regex is, just do: `,count add <name>&<name>`")
msg.reply(ctx, "Please use the proper syntax: `,cadd <name>&<regex>`\nIf you don't know what regex is, just do: `,cadd <name>&<name>`")
.await?;
return Ok(());
}
@@ -92,7 +93,7 @@ pub async fn add(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
.clone();
let check_existense = db
.query(
format!("select name, reg from words where name='{}'", queries[0]).as_str(),
format!("SELECT name, reg FROM words WHERE name='{}'", queries[0]).as_str(),
&[],
)
.await?;
@@ -107,7 +108,7 @@ pub async fn add(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
}
db.execute(
format!(
"insert into words(name, reg, owner) values('{}','(?i){}', '{}')",
"INSERT INTO words(name, reg, owner) VALUES('{}','(?i){}', '{}')",
queries[0],
queries[1],
msg.author.id.to_string()
@@ -121,7 +122,7 @@ pub async fn add(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
}
#[command]
pub async fn rm(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
pub async fn crm(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
if query == "" {
msg.reply(ctx, "remove what?").await?;
@@ -134,7 +135,7 @@ pub async fn rm(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
.clone();
let owner = db
.query(
format!("select owner from words where name = '{}'", query).as_str(),
format!("SELECT owner FROM words WHERE name = '{}'", query).as_str(),
&[],
)
.await?;
@@ -146,7 +147,7 @@ pub async fn rm(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
}
}
db.execute(
format!("delete from words where name='{}'", query,).as_str(),
format!("DELETE FROM words WHERE name='{}'", query,).as_str(),
&[],
)
.await?;
@@ -155,13 +156,13 @@ pub async fn rm(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
}
#[command]
pub async fn change(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
pub async fn cedit(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
let queries = query.splitn(2, "&").collect::<Vec<&str>>();
if queries.len() != 2 {
msg.reply(
ctx,
"Please use the proper syntax\n,count change <name>&<regex>",
"Please use the proper syntax\n,cedit <name>&<regex>",
)
.await?;
return Ok(());
@@ -177,7 +178,7 @@ pub async fn change(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
.clone();
let owner = db
.query(
format!("select owner from words where name = '{}'", queries[0]).as_str(),
format!("SELECT owner FROM words WHERE name = '{}'", queries[0]).as_str(),
&[],
)
.await?;
@@ -190,7 +191,7 @@ pub async fn change(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
}
db.execute(
format!(
"update words set reg='(?i){}' where name='{}'",
"UPDATE words SET reg='(?i){}' WHERE name='{}'",
queries[1], queries[0]
)
.as_str(),
@@ -237,18 +238,24 @@ macro_rules! make_terminal_components {
.custom_id("next")
.disabled($terminal == "last")
})
.create_button(|b| {
b.style(ButtonStyle::Danger)
.label("Delete")
.emoji(ReactionType::Unicode("\u{1F5D1}".to_string()))
.custom_id("delete")
})
})
}};
}
#[command]
pub async fn ls(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
pub async fn cls(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
let data_read = ctx.data.read().await;
let db = data_read
.get::<crate::Database>()
.expect("Expected Database in TypeMap.")
.clone();
let rows = db.query("select * from words", &[]).await?;
let rows = db.query("SELECT * FROM words", &[]).await?;
if rows.is_empty() {
msg.reply(ctx, "No words stored").await?;
return Ok(());
@@ -273,11 +280,11 @@ pub async fn ls(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
match component.custom_id.as_ref() {
"next" => {
if cur != groups.len() {
cur += 1;
let _ = interaction
.create_interaction_response(&ctx, |r| {
r.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|m| {
cur += 1;
m.create_embed(|mut e| make_embed!(e, cur, groups[cur - 1]))
.components(|c| {
make_terminal_components!(
@@ -296,11 +303,11 @@ pub async fn ls(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
}
"prev" => {
if cur != 1 {
cur -= 1;
let _ = interaction
.create_interaction_response(&ctx, |r| {
r.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|m| {
cur -= 1;
m.create_embed(|mut e| make_embed!(e, cur, groups[cur - 1]))
.components(|c| {
make_terminal_components!(
@@ -313,6 +320,10 @@ pub async fn ls(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
.await;
}
}
"delete" => {
message.delete(ctx).await?;
msg.delete(ctx).await?;
}
_ => {}
}
}

View File

@@ -1,3 +1,4 @@
pub mod general;
pub mod count;
pub mod general;
pub mod minigames;
pub mod tags;

325
src/commands/tags.rs Normal file
View File

@@ -0,0 +1,325 @@
use core::time::Duration;
use serenity::{
collector::component_interaction_collector::ComponentInteractionCollectorBuilder,
framework::standard::{macros::command, Args, CommandResult},
futures::StreamExt,
model::{
channel::ReactionType,
interactions::{ButtonStyle, InteractionData},
prelude::*,
},
prelude::*,
utils::Colour,
};
use tokio_postgres::Row;
#[command]
#[aliases("t")]
pub async fn tag(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let query: String = args.raw().collect::<Vec<&str>>().join("");
if query == "" {
msg.reply(ctx, "Mention the tag retard").await?;
return Ok(());
}
let data_read = ctx.data.read().await;
let db = data_read
.get::<crate::Database>()
.expect("Expected Database in TypeMap.")
.clone();
let query_helper = db
.query(
format!("SELECT name, value FROM tags WHERE name='{}'", query).as_str(),
&[],
)
.await?;
if query_helper.is_empty() {
let leven = db
.query(
format!(
"SELECT name FROM tags WHERE levenshtein(name, '{}') < 2",
query
)
.as_str(),
&[],
)
.await?;
let l = if leven.is_empty() {
"".to_string()
} else {
let leven_name: String = leven[0].get(0);
format!("\nDid you mean `{}`?", leven_name)
};
msg.reply(
ctx,
format!(
"No entry for '{}' found. If you want to add it, run `,tadd {} <value>`{}",
query, query, l
),
)
.await?;
return Ok(());
}
let value: String = query_helper[0].get(1);
msg.reply(ctx, value).await?;
Ok(())
}
#[command]
pub async fn tadd(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
let queries = query.splitn(2, " ").collect::<Vec<&str>>();
if queries.len() != 2 {
msg.reply(ctx, "Please use the proper syntax: `,tadd <name> <value>`")
.await?;
return Ok(());
}
let data_read = ctx.data.read().await;
let db = data_read
.get::<crate::Database>()
.expect("Expected Database in TypeMap.")
.clone();
let check_existense = db
.query(
format!("SELECT name FROM tags WHERE name='{}'", queries[0]).as_str(),
&[],
)
.await?;
if check_existense.len() != 0 {
msg.reply(ctx, format!("This tag already exists")).await?;
return Ok(());
}
db.execute(
format!(
"INSERT INTO tags(name, value, owner) VALUES('{}','{}', '{}')",
queries[0],
format!(
"{}\n{}",
queries[1],
msg.attachments
.iter()
.map(|x| x.url.clone())
.collect::<Vec<String>>()
.join("\n")
),
msg.author.id.to_string()
)
.as_str(),
&[],
)
.await?;
msg.reply(ctx, "Added").await?;
Ok(())
}
#[command]
pub async fn trm(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
if query == "" {
msg.reply(ctx, "remove what?").await?;
return Ok(());
}
let data_read = ctx.data.read().await;
let db = data_read
.get::<crate::Database>()
.expect("Expected Database in TypeMap.")
.clone();
let owner = db
.query(
format!("SELECT owner FROM tags WHERE name = '{}'", query).as_str(),
&[],
)
.await?;
if owner.len() == 1 {
let owner_id: String = owner[0].get(0);
if owner_id != msg.author.id.to_string() {
msg.reply(ctx, "You don't even own this tag").await?;
return Ok(());
}
}
db.execute(
format!("DELETE FROM tags WHERE name='{}'", query,).as_str(),
&[],
)
.await?;
msg.reply(ctx, "Deleted if it existed").await?;
Ok(())
}
#[command]
pub async fn tedit(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
let query: String = args.raw().collect::<Vec<&str>>().join(" ");
let queries = query.splitn(2, " ").collect::<Vec<&str>>();
if queries.len() != 2 {
msg.reply(ctx, "Please use the proper syntax\n`,tedit <name> <value>`")
.await?;
return Ok(());
}
let data_read = ctx.data.read().await;
let db = data_read
.get::<crate::Database>()
.expect("Expected Database in TypeMap.")
.clone();
let owner = db
.query(
format!("SELECT owner FROM tags WHERE name = '{}'", queries[0]).as_str(),
&[],
)
.await?;
if owner.len() == 1 {
let owner_id: String = owner[0].get(0);
if owner_id != msg.author.id.to_string() {
msg.reply(ctx, "You don't even own this tag").await?;
return Ok(());
}
}
db.execute(
format!(
"UPDATE tags SET value='{}' WHERE name='{}'",
format!(
"{}\n{}",
queries[1],
msg.attachments
.iter()
.map(|x| x.url.clone())
.collect::<Vec<String>>()
.join("\n")
),
queries[0]
)
.as_str(),
&[],
).await?;
msg.reply(ctx, "Changed the value if it existed").await?;
Ok(())
}
macro_rules! make_embed {
($e: expr, $cur: expr, $group: expr) => {{
$e = $e
.title(format!("List of tags: Page {}", $cur))
.color(Colour::FABLED_PINK);
for row in $group {
let idx: i32 = row.get(0);
let name: String = row.get(1);
let owner_id: String = row.get(3);
$e = $e.field(
format!("{}. {}", idx, name),
format!(" by <@{}>", owner_id),
true,
);
}
$e
}};
}
macro_rules! make_terminal_components {
($c: expr, $terminal: expr ) => {{
$c.create_action_row(|ar| {
ar.create_button(|b| {
b.style(ButtonStyle::Primary)
.label("Prev")
.emoji(ReactionType::Unicode("\u{2B05}".to_string()))
.custom_id("prev")
.disabled($terminal == "first")
})
.create_button(|b| {
b.style(ButtonStyle::Primary)
.label("Next")
.emoji(ReactionType::Unicode("\u{27A1}".to_string()))
.custom_id("next")
.disabled($terminal == "last")
})
.create_button(|b| {
b.style(ButtonStyle::Danger)
.label("Delete")
.emoji(ReactionType::Unicode("\u{1F5D1}".to_string()))
.custom_id("delete")
})
})
}};
}
#[command]
pub async fn tls(ctx: &Context, msg: &Message, _: Args) -> CommandResult {
let data_read = ctx.data.read().await;
let db = data_read
.get::<crate::Database>()
.expect("Expected Database in TypeMap.")
.clone();
let rows = db.query("SELECT * FROM tags", &[]).await?;
if rows.is_empty() {
msg.reply(ctx, "No tags stored").await?;
return Ok(());
}
let groups: Vec<&[Row]> = rows.chunks(5).collect();
let mut cur = 1;
let message = msg
.channel_id
.send_message(ctx, |m| {
m.embed(|mut e| make_embed!(e, cur, groups[cur - 1]))
.components(|c| make_terminal_components!(c, "first"))
})
.await?;
let mut collector = ComponentInteractionCollectorBuilder::new(&ctx)
.timeout(Duration::from_secs(90))
.author_id(msg.author.id)
.message_id(message.id)
.await;
while let Some(interaction) = collector.next().await {
if let InteractionData::MessageComponent(component) = interaction.data.as_ref().unwrap() {
match component.custom_id.as_ref() {
"next" => {
if cur != groups.len() {
cur += 1;
let _ = interaction
.create_interaction_response(&ctx, |r| {
r.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|m| {
m.create_embed(|mut e| make_embed!(e, cur, groups[cur - 1]))
.components(|c| {
make_terminal_components!(
c,
if cur == groups.len() {
"last"
} else {
"mid"
}
)
})
})
})
.await;
}
}
"prev" => {
if cur != 1 {
cur -= 1;
let _ = interaction
.create_interaction_response(&ctx, |r| {
r.kind(InteractionResponseType::UpdateMessage)
.interaction_response_data(|m| {
m.create_embed(|mut e| make_embed!(e, cur, groups[cur - 1]))
.components(|c| {
make_terminal_components!(
c,
if cur == 1 { "first" } else { "mid" }
)
})
})
})
.await;
}
}
"delete" => {
message.delete(ctx).await?;
msg.delete(ctx).await?;
}
_ => {}
}
}
}
Ok(())
}

View File

@@ -3,6 +3,7 @@ mod handler;
use commands::count::*;
use commands::general::*;
use commands::minigames::*;
use commands::tags::*;
use handler::Handler;
use serenity::{
client::bridge::gateway::ShardManager,
@@ -36,10 +37,13 @@ impl TypeMapKey for Database {
struct General;
#[group]
#[prefix = "count"]
#[commands(kitna, add, rm, change, ls)]
#[commands(count, cadd, crm, cedit, cls)]
struct Count;
#[group]
#[commands(tag, tadd, trm, tedit, tls)]
pub struct Tags;
#[group]
#[commands(challenge)]
struct Minigames;
@@ -82,6 +86,7 @@ async fn main() {
.help(&MY_HELP)
.group(&GENERAL_GROUP)
.group(&COUNT_GROUP)
.group(&TAGS_GROUP)
.group(&MINIGAMES_GROUP);
let mut client = Client::builder(&token)