Merge pull request #2 from ByteDice/experimental_new_commands
Experimental new commands
This commit is contained in:
+1
-1
@@ -12,7 +12,7 @@ flate2 = "1.1.2"
|
||||
formatx = "0.2.3"
|
||||
futures = "0.3.31"
|
||||
poise = "0.6.1"
|
||||
pyo3 = "0.23.4"
|
||||
pyo3 = "0.28.2"
|
||||
rand = "0.9.0"
|
||||
regex = "1.11.1"
|
||||
serde = "1.0.217"
|
||||
|
||||
@@ -58,10 +58,11 @@ It is required to install all used Python modules. You can find those in [req.tx
|
||||
|
||||
### Required permissions:
|
||||
**These are automatically set if you use the [official invite link](https://discord.com/oauth2/authorize?client_id=1212127255795335208&permissions=84992&integration_type=0&scope=bot) or an invite link with the permissions integer set to `84992`.** (The permission integer is this part of the URL `&permissions=84992`)
|
||||
* Send Messages
|
||||
* Read Message History
|
||||
* View Channels
|
||||
* Create Invites
|
||||
* Embed Links
|
||||
* Read Message History
|
||||
* Send Messages
|
||||
* View Channels
|
||||
|
||||
### Configuration:
|
||||
You can find config files in the [cfg/](cfg/) folder. You can also find the default configs in the [data/defaults/cfg_default.toml](data/defaults/cfg_default.toml) file.\
|
||||
|
||||
@@ -6,6 +6,13 @@ lang = "en"
|
||||
# The discord bots status text
|
||||
status = "🎲 https://bytedice.net"
|
||||
|
||||
# Adds "(Commit #123)" at the end of the status
|
||||
statusCommitNumber = true
|
||||
|
||||
# Changes "(Commit #123)" into "(Experimental #123)"
|
||||
# Requires statusCommitNumber to be true
|
||||
statusExperimentalCommit = false
|
||||
|
||||
[reddit]
|
||||
# Which subreddits the bot will scan when executing "re"-category commands.
|
||||
# Is automatically disabled when `disabled_categories` includes "re".
|
||||
@@ -31,6 +38,7 @@ disabled_categories = [
|
||||
# "fun",
|
||||
# "help"
|
||||
# "re"
|
||||
# "debug"
|
||||
]
|
||||
|
||||
# The chance (between 0..1) for the `/8_ball` command to output a "quirky" answer.
|
||||
|
||||
+4
-1
@@ -19,6 +19,8 @@
|
||||
"dc_msg_err_trace": "Unknown error!\nError trace: {0}",
|
||||
"dc_msg_failed_shorturl_conversion": "Couldn't convert to shortURL: Invalid Reddit URL format.",
|
||||
"dc_msg_mandatory_response": "Mandatory response message, please ignore.",
|
||||
"dc_msg_no_perms": "Missing permission in that server: {0}",
|
||||
"dc_msg_not_in_guild": "I am not a part of that guild.",
|
||||
"dc_msg_owner_data_save_complete": "Saving data... Done!\nShutting down...",
|
||||
"dc_msg_owner_data_save": "Saving data...",
|
||||
"dc_msg_owner_shutdown_failed_confirmation": "Failed to shut down: Invalid confirmation.",
|
||||
@@ -62,5 +64,6 @@
|
||||
"py_re_response_weekly_add": "Successfully added your post to the weekly art submissions! Thank you for participating!",
|
||||
"py_re_response_weekly_exists": "Couldn't add this post to the submissions! Luckily, it's already there! Thank you for participating!",
|
||||
"py_re_response_weekly_mod_add": "[MOD ACTION] Successfully added this post to the weekly art submissions!",
|
||||
"py_re_response_weekly_mod_unremove": "[MOD ACTION] Successfully un-removed this post from the weekly art submissions!"
|
||||
"py_re_response_weekly_mod_unremove": "[MOD ACTION] Successfully un-removed this post from the weekly art submissions!",
|
||||
"success": "Success!"
|
||||
}
|
||||
@@ -19,6 +19,8 @@
|
||||
"dc_msg_err_trace": "Erreur inconnue !\nTrace de l’erreur : {0}",
|
||||
"dc_msg_failed_shorturl_conversion": "Échec de la conversion en shortURL : format d’URL Reddit invalide.",
|
||||
"dc_msg_mandatory_response": "Message de réponse obligatoire, merci d’ignorer.",
|
||||
"dc_msg_no_perms": "Permission manquante sur ce serveur : {0}",
|
||||
"dc_msg_not_in_guild": "Je ne fais pas partie de ce serveur.",
|
||||
"dc_msg_owner_data_save_complete": "Sauvegarde des données... Terminé !\nFermeture...",
|
||||
"dc_msg_owner_data_save": "Sauvegarde des données...",
|
||||
"dc_msg_owner_shutdown_failed_confirmation": "Échec de l’arrêt : confirmation invalide.",
|
||||
@@ -62,5 +64,6 @@
|
||||
"py_re_response_weekly_add": "Post ajouté avec succès aux soumissions hebdomadaires d'art ! Merci pour votre participation !",
|
||||
"py_re_response_weekly_exists": "Impossible d’ajouter ce post, il est déjà présent ! Merci pour votre participation !",
|
||||
"py_re_response_weekly_mod_add": "[ACTION MOD] Post ajouté avec succès aux soumissions hebdomadaires d’art !",
|
||||
"py_re_response_weekly_mod_unremove": "[ACTION MOD] Post restauré avec succès dans les soumissions hebdomadaires d’art !"
|
||||
"py_re_response_weekly_mod_unremove": "[ACTION MOD] Post restauré avec succès dans les soumissions hebdomadaires d’art !",
|
||||
"dc_msg_success": "succès !"
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
use crate::{messages::send_msg, Context, Error};
|
||||
|
||||
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
rename = "ping",
|
||||
category = "fun",
|
||||
required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL"
|
||||
)]
|
||||
/// Check if you have connection to the bot.
|
||||
pub async fn cmd(
|
||||
ctx: Context<'_>,
|
||||
#[description = "The text to echo back."] text: Option<String>,
|
||||
) -> Result<(), Error>
|
||||
{
|
||||
send_msg(ctx, text.unwrap_or_else(|| "Pong".to_string()), true, true).await;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
use poise::serenity_prelude::{CreateInvite, GuildId};
|
||||
|
||||
use crate::{Context, Error, lang, messages::send_msg};
|
||||
|
||||
|
||||
pub async fn cmd(ctx: Context<'_>, guild_id: u64) -> Result<(), Error> {
|
||||
let id = GuildId::from(guild_id);
|
||||
let guild = id.to_partial_guild(ctx.http()).await?;
|
||||
|
||||
if !ctx.serenity_context().cache.guilds().contains(&id) {
|
||||
send_msg(ctx, lang!("dc_msg_not_in_guild"), true, true).await;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let ch = guild.channels(ctx.http()).await?
|
||||
.values()
|
||||
.find(|c| c.is_text_based())
|
||||
.cloned();
|
||||
|
||||
if let Some(channel) = ch {
|
||||
let bot_member = &guild.member(ctx.http(), ctx.framework().bot_id).await?;
|
||||
let perms = guild.user_permissions_in(&channel, bot_member);
|
||||
|
||||
if !perms.create_instant_invite() {
|
||||
send_msg(ctx, lang!("dc_msg_no_perms", "CreateInvite"), true, true).await;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let inv_builder = CreateInvite::new().max_age(0).max_uses(0);
|
||||
let inv = channel.id.create_invite(ctx.http(), inv_builder).await?;
|
||||
send_msg(ctx, inv.url(), true, true).await;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use poise::serenity_prelude::GuildId;
|
||||
|
||||
use crate::{Context, Error, lang, messages::send_msg};
|
||||
|
||||
|
||||
pub async fn cmd(ctx: Context<'_>, guild_id: u64) -> Result<(), Error> {
|
||||
let id = GuildId::from(guild_id);
|
||||
let guild = id.to_partial_guild(ctx.http()).await?;
|
||||
|
||||
if !ctx.serenity_context().cache.guilds().contains(&id) {
|
||||
send_msg(ctx, lang!("dc_msg_not_in_guild"), true, true).await;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
guild.leave(ctx.http()).await?;
|
||||
send_msg(ctx, lang!("success"), true, true).await;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
use crate::{Context, Error, debug_cmds::{guild_invite, leave_guild, ping, reload_cfg, stop, view_guilds, whoami}};
|
||||
|
||||
|
||||
#[derive(poise::ChoiceParameter, PartialEq)]
|
||||
pub enum Subcommands {
|
||||
GuildInvite,
|
||||
LeaveGuild,
|
||||
Ping,
|
||||
ReloadCfg,
|
||||
Stop,
|
||||
ViewGuilds,
|
||||
WhoAmI
|
||||
}
|
||||
|
||||
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
category = "owner",
|
||||
rename = "debug",
|
||||
required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL"
|
||||
)]
|
||||
/// Various debug utilities
|
||||
pub async fn cmd(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Subcommand"] subcommand: Subcommands,
|
||||
string_arg: Option<String>,
|
||||
u64_arg: Option<String>
|
||||
) -> Result<(), Error>
|
||||
{
|
||||
let u64_arg_u: u64 = u64_arg.unwrap_or("0".to_string()).as_str().parse()?;
|
||||
|
||||
match subcommand {
|
||||
Subcommands::GuildInvite => guild_invite::cmd(ctx, u64_arg_u).await?,
|
||||
Subcommands::LeaveGuild => leave_guild::cmd(ctx, u64_arg_u).await?,
|
||||
Subcommands::Ping => ping::cmd(ctx).await?,
|
||||
Subcommands::ReloadCfg => reload_cfg::cmd(ctx).await?,
|
||||
Subcommands::Stop => stop::cmd(ctx, string_arg).await?,
|
||||
Subcommands::ViewGuilds => view_guilds::cmd(ctx).await?,
|
||||
Subcommands::WhoAmI => whoami::cmd(ctx).await?,
|
||||
//_ => return Ok(())
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
use crate::{messages::send_msg, Context, Error};
|
||||
|
||||
|
||||
pub async fn cmd(ctx: Context<'_>) -> Result<(), Error> {
|
||||
send_msg(ctx, "Pong".to_string(), true, true).await;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@@ -1,19 +1,7 @@
|
||||
use crate::{data::{self, get_toml_mutex, read_cfg_data}, lang, messages::send_msg, Context, Error};
|
||||
|
||||
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
rename = "reload_cfg",
|
||||
category = "owner",
|
||||
owners_only,
|
||||
required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL"
|
||||
)]
|
||||
/// Reloads the entire config file.
|
||||
pub async fn cmd(
|
||||
ctx: Context<'_>
|
||||
) -> Result<(), Error>
|
||||
{
|
||||
pub async fn cmd(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let r = read_cfg_data(ctx.data(), false).await;
|
||||
let d = get_toml_mutex(&ctx.data().cfg).await.unwrap();
|
||||
|
||||
@@ -4,21 +4,7 @@ use poise::serenity_prelude::OnlineStatus;
|
||||
|
||||
use crate::{data, lang, messages::{edit_reply, send_msg}, websocket::send_cmd_json, Context, Error};
|
||||
|
||||
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
rename = "stop",
|
||||
category = "owner",
|
||||
owners_only,
|
||||
required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL"
|
||||
)]
|
||||
/// I have security measures, even in developer mode. You wont access this without being a bot "owner".
|
||||
pub async fn cmd(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Type \"i want to stop the bot now\" to confirm."] confirmation: Option<String>,
|
||||
) -> Result<(), Error>
|
||||
{
|
||||
pub async fn cmd(ctx: Context<'_>, confirmation: Option<String>) -> Result<(), Error>{
|
||||
let stop_confirm = "i want to stop the bot now".replace(" ", "");
|
||||
let confirm_formatted = confirmation.unwrap_or_default().to_lowercase().replace(" ", "");
|
||||
let should_stop = ctx.data().args.dev || confirm_formatted == stop_confirm;
|
||||
@@ -0,0 +1,29 @@
|
||||
use crate::{Context, Error, messages::send_msg};
|
||||
|
||||
|
||||
pub async fn cmd(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let guilds = ctx.cache().guilds();
|
||||
let mut msgs: Vec<Vec<String>> = vec![vec![]];
|
||||
let mut char_count: usize = 0;
|
||||
let mut msg_idx: usize = 0;
|
||||
|
||||
for g in guilds {
|
||||
let name = g.name(ctx.cache()).unwrap_or("[unnamed]".to_string());
|
||||
let id = g.get();
|
||||
|
||||
let msg = format!("**[{}]** {}", id, name);
|
||||
char_count += msg.len();
|
||||
|
||||
if char_count >= 2000 {
|
||||
msgs.push(Vec::new());
|
||||
msg_idx += 1;
|
||||
}
|
||||
|
||||
msgs[msg_idx].push(msg);
|
||||
}
|
||||
|
||||
for msg in msgs
|
||||
{ send_msg(ctx, msg.join("\n"), true, true).await; }
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@@ -1,12 +1,5 @@
|
||||
use crate::{lang, messages::send_msg, Context, Error};
|
||||
|
||||
#[poise::command(
|
||||
slash_command,
|
||||
prefix_command,
|
||||
rename = "whoami",
|
||||
category = "help",
|
||||
required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL"
|
||||
)]
|
||||
pub async fn cmd(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let data = ctx.data();
|
||||
let uid: u64 = ctx.author().id.into();
|
||||
+25
-1
@@ -9,6 +9,7 @@ use serde_json::{json, Value};
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::process;
|
||||
|
||||
pub fn event_handler<'a>(
|
||||
ctx: &'a serenity::Context,
|
||||
@@ -35,10 +36,33 @@ async fn on_ready(ctx: &serenity::Context, data_about_bot: &Ready, data: &Data)
|
||||
);
|
||||
|
||||
let m_data = get_toml_mutex(&data.cfg).await.unwrap();
|
||||
let custom_activity = ActivityData::custom(m_data["general"]["status"].as_str().unwrap());
|
||||
let status_str: String;
|
||||
|
||||
let status = m_data["general"]["status"].as_str().unwrap();
|
||||
let status_c = m_data["general"]["statusCommitNumber"].as_bool().unwrap();
|
||||
let status_ec = m_data["general"]["statusExperimentalCommit"].as_bool().unwrap();
|
||||
|
||||
if status_c {
|
||||
let commit_num_r = process::Command::new("git")
|
||||
.args(["rev-list", "--count", "HEAD"])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
let commit_num = format!(
|
||||
"({} #{})",
|
||||
if status_ec { "Experimental" }
|
||||
else { "Commit" },
|
||||
String::from_utf8(commit_num_r.stdout).unwrap()
|
||||
).replace("\n", "");
|
||||
|
||||
status_str = [status, " ", commit_num.as_str().trim()].concat();
|
||||
}
|
||||
else { status_str = status.to_string(); }
|
||||
|
||||
let custom_activity = ActivityData::custom(status_str.clone());
|
||||
ctx.online();
|
||||
ctx.set_activity(Some(custom_activity));
|
||||
rs_println!("Set bot status as: \"{}\"", status_str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+9
-7
@@ -4,7 +4,7 @@ use poise::serenity_prelude::UserId;
|
||||
use poise::serenity_prelude as serenity;
|
||||
use poise::serenity_prelude::Client;
|
||||
|
||||
use crate::{cmds, data::{self, get_toml_mutex}, events, re_cmds, rs_println, Args, Cmd, Data};
|
||||
use crate::{Args, Cmd, Data, cmds, data::{self, get_toml_mutex}, debug_cmds, events, re_cmds, rs_println};
|
||||
|
||||
|
||||
pub async fn gen_data(args: Args, owners: Vec<u64>) -> Data {
|
||||
@@ -51,7 +51,11 @@ pub async fn gen_bot(data: Data, args: Args) -> Client {
|
||||
let token_end_len = token[peek_len..].len();
|
||||
rs_println!("Token: {}{}", token_peek, "*".repeat(token_end_len));
|
||||
|
||||
let own: HashSet<UserId> = data.owners.clone().into_iter().map(UserId::from).collect();
|
||||
let own: HashSet<UserId> = data.owners
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter_map(|i| if i == 0 { None } else { Some(UserId::from(i))})
|
||||
.collect();
|
||||
|
||||
let framework = poise::Framework::builder()
|
||||
.options(poise::FrameworkOptions {
|
||||
@@ -79,8 +83,6 @@ async fn make_cmd_vec(data: &Data) -> Vec<Cmd> {
|
||||
let mut cmds = vec![
|
||||
// GENERIC
|
||||
cmds::help::cmd(),
|
||||
cmds::whoami::cmd(),
|
||||
cmds::ping::cmd(),
|
||||
cmds::eight_ball::cmd(),
|
||||
// REDDIT
|
||||
re_cmds::add::cmd(),
|
||||
@@ -94,11 +96,11 @@ async fn make_cmd_vec(data: &Data) -> Vec<Cmd> {
|
||||
// [ADMIN / OWNER]
|
||||
cmds::embed::cmd(),
|
||||
cmds::send::cmd(),
|
||||
cmds::stop::cmd(),
|
||||
cmds::add_server::cmd(),
|
||||
cmds::reload_cfg::cmd(),
|
||||
// REDDIT [ADMIN / OWNER]
|
||||
re_cmds::admin_bind::cmd()
|
||||
re_cmds::admin_bind::cmd(),
|
||||
// DEBUG
|
||||
debug_cmds::main_cmd::cmd()
|
||||
];
|
||||
let cfg = get_toml_mutex(&data.cfg).await.unwrap();
|
||||
|
||||
|
||||
+11
-4
@@ -1,16 +1,13 @@
|
||||
#![warn(unused_extern_crates)]
|
||||
#![allow(clippy::needless_return)]
|
||||
#![allow(static_mut_refs)]
|
||||
|
||||
mod cmds {
|
||||
pub mod add_server;
|
||||
pub mod eight_ball;
|
||||
pub mod embed;
|
||||
pub mod help;
|
||||
pub mod ping;
|
||||
pub mod reload_cfg;
|
||||
pub mod send;
|
||||
pub mod stop;
|
||||
pub mod whoami;
|
||||
}
|
||||
mod re_cmds {
|
||||
pub mod add;
|
||||
@@ -24,6 +21,16 @@ mod re_cmds {
|
||||
pub mod update;
|
||||
pub mod vote;
|
||||
}
|
||||
mod debug_cmds {
|
||||
pub mod guild_invite;
|
||||
pub mod leave_guild;
|
||||
pub mod main_cmd;
|
||||
pub mod stop;
|
||||
pub mod ping;
|
||||
pub mod reload_cfg;
|
||||
pub mod view_guilds;
|
||||
pub mod whoami;
|
||||
}
|
||||
mod events;
|
||||
mod messages;
|
||||
mod python;
|
||||
|
||||
+3
-2
@@ -199,7 +199,7 @@ pub async fn http_edit_msg(
|
||||
}
|
||||
|
||||
|
||||
pub async fn send_dm(msg: String, args: Args, owners: Vec<u64>) {
|
||||
pub async fn send_dm(msg: String, args: Args, receivers: Vec<u64>) {
|
||||
let token: String =
|
||||
if !args.test { env::var("ASSISTANT_TOKEN") .expect("Missing ASSISTANT_TOKEN env var!") }
|
||||
else { env::var("ASSISTANT_TOKEN_TEST").expect("Missing ASSISTANT_TOKEN_TEST env var!") };
|
||||
@@ -208,7 +208,8 @@ pub async fn send_dm(msg: String, args: Args, owners: Vec<u64>) {
|
||||
|
||||
let c_msg = CreateMessage::new().content(msg);
|
||||
|
||||
for uid in owners {
|
||||
for uid in receivers {
|
||||
if uid == 0 { continue; }
|
||||
let user = UserId::new(uid);
|
||||
let _ = user.dm(http.as_ref(), c_msg.clone()).await;
|
||||
}
|
||||
|
||||
+3
-3
@@ -36,10 +36,10 @@ pub async fn start(args: Args) -> PyResult<()> {
|
||||
let mut traceback: String = String::new();
|
||||
let mut is_error = false;
|
||||
|
||||
pyo3::prepare_freethreaded_python();
|
||||
Python::initialize();
|
||||
|
||||
let _ = Python::with_gil(|py| -> Result<(), PyErr> {
|
||||
let syspath = py.import("sys")?.getattr("path")?.downcast_into::<PyList>()?;
|
||||
let _ = Python::attach(|py| -> Result<(), PyErr> {
|
||||
let syspath = py.import("sys")?.getattr("path")?.cast_into::<PyList>()?;
|
||||
syspath.insert(0, path)?;
|
||||
let empty = CString::new("").unwrap();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user