add message sending

This commit is contained in:
Hay1tsme 2023-08-28 01:36:26 -04:00
parent 3172a07b38
commit c910fa4b97
13 changed files with 287 additions and 5 deletions

3
.gitignore vendored
View File

@ -3,4 +3,5 @@
*.yaml
!example_config.yaml
/data
*.log
*.log
*.lib

109
Cargo.lock generated
View File

@ -274,8 +274,11 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d98235fdc2f355d330a8244184ab6b4b33c28679c0b4158f63138e51d6cf7e88"
dependencies = [
"chrono",
"diesel_derives",
"libsqlite3-sys",
"r2d2",
"serde_json",
"time 0.3.27",
]
@ -291,6 +294,17 @@ dependencies = [
"syn 2.0.29",
]
[[package]]
name = "diesel_migrations"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6036b3f0120c5961381b570ee20a02432d7e2d27ea60de9578799cf9156914ac"
dependencies = [
"diesel",
"migrations_internals",
"migrations_macros",
]
[[package]]
name = "diesel_table_macro_syntax"
version = "0.1.0"
@ -681,6 +695,27 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "migrations_internals"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada"
dependencies = [
"serde",
"toml",
]
[[package]]
name = "migrations_macros"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08"
dependencies = [
"migrations_internals",
"proc-macro2",
"quote",
]
[[package]]
name = "mime"
version = "0.3.17"
@ -862,6 +897,17 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "r2d2"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93"
dependencies = [
"log",
"parking_lot",
"scheduled-thread-pool",
]
[[package]]
name = "rand"
version = "0.8.5"
@ -1048,6 +1094,15 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "scheduled-thread-pool"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19"
dependencies = [
"parking_lot",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@ -1105,6 +1160,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@ -1379,6 +1443,40 @@ dependencies = [
"tracing",
]
[[package]]
name = "toml"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
dependencies = [
"indexmap 2.0.0",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "tower-service"
version = "0.3.2"
@ -1670,9 +1768,11 @@ version = "0.1.0"
dependencies = [
"chrono",
"diesel",
"diesel_migrations",
"once_cell",
"poise",
"serde",
"serde_json",
"serde_yaml",
"serenity",
"tokio",
@ -1775,6 +1875,15 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winnow"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.50.0"

View File

@ -13,4 +13,6 @@ chrono = "0.4"
once_cell = "1.18"
serde = "1.0"
serde_yaml = "0.9"
diesel = { version = "2.1", features = ["sqlite"] }
serde_json = "1.0"
diesel = { version = "2.1", features = ["sqlite", "serde_json", "chrono", "r2d2", "32-column-tables", "64-column-tables", "128-column-tables"] }
diesel_migrations = "2.0"

9
diesel.toml Normal file
View File

@ -0,0 +1,9 @@
# For documentation on how to configure this file,
# see https://diesel.rs/guides/configuring-diesel-cli
[print_schema]
file = "src/db/schema.rs"
custom_type_derives = ["diesel::query_builder::QueryId"]
[migrations_directory]
dir = "migrations"

View File

@ -1,6 +1,11 @@
token: ""
log_level: "info"
log_dir: "logs"
sqlite_file: "data/db.sqlite"
hash_ids: true
channel: 0
admins:
- 0
- 0
picture_dir: "data"
pictures:
- ""

0
migrations/.keep Normal file
View File

View File

@ -0,0 +1 @@
-- This file should undo anything in `up.sql`

View File

@ -0,0 +1,17 @@
-- Your SQL goes here
CREATE TABLE guild (
guild_id BIGINT PRIMARY KEY NOT NULL,
channel_id BIGINT NOT NULL
);
CREATE TABLE user (
discord_id TEXT PRIMARY KEY NOT NULL,
server BIGINT,
fake_id BIGINT NOT NULL,
when_generated DATETIME default CURRENT_TIMESTAMP NOT NULL,
should_notify TINYINT NOT NULL DEFAULT 1,
is_guild_admin TINYINT NOT NULL DEFAULT 0,
is_banned TINYINT NOT NULL DEFAULT 0,
suspend_expires DATETIME,
FOREIGN KEY(server) REFERENCES guild(guild_id)
);

View File

@ -7,24 +7,36 @@ use serde_yaml::{self};
pub struct CoreConfig {
/// Discord bot token.
pub token: String,
/// Log Level
pub log_level: String,
/// Folder to store program logs.
pub log_dir: String,
/// Location for where the sqlite database should be stored
pub sqlite_file: String,
/// If user IDs should be hased in the database, disables @mentioning.
pub hash_ids: bool,
/// Channel where messages should be posted.
pub channel: u64,
/// List of user IDs of users who have admin perms with the bot.
pub admins: Vec<i64>,
/// Directory where pictures are kept.
pub picture_dir: String,
/// List of pictures to acompany users.
pub pictures: Vec<String>,
}
impl Default for CoreConfig {
fn default() -> Self {
Self {
token: Default::default(),
log_level: "info".to_string(),
log_dir: "logs".to_string(),
sqlite_file: "data/db.sqlite".to_string(),
hash_ids: true,
channel: 0,
admins: vec![0]
admins: vec![0],
picture_dir: "data".to_string(),
pictures: Vec::new(),
}
}
}

37
src/db/mod.rs Normal file
View File

@ -0,0 +1,37 @@
use diesel::{Connection, sqlite::SqliteConnection, r2d2::*};
use once_cell::sync::OnceCell;
use crate::{config::CORE_CFG, logging::{LogLevel, log}};
pub mod schema;
pub static DB_CON_POOL: OnceCell<Pool<ConnectionManager<SqliteConnection>>> = OnceCell::new();
pub fn init_db() -> bool {
let cfg = CORE_CFG.get().unwrap();
let manager = ConnectionManager::<SqliteConnection>::new(&cfg.sqlite_file);
let conn_pool_ = Pool::builder()
.test_on_check_out(true)
.build(manager);
if conn_pool_.is_err() {
log(LogLevel::Fatal, "Database", "init_db", "Failed to connect to database:");
return false;
}
let conn_pool: Pool<ConnectionManager<SqliteConnection>> = conn_pool_.unwrap();
let test_res = conn_pool.get().unwrap().begin_test_transaction();
if test_res.is_err() {
log(LogLevel::Fatal, "Database", "init_db", format!("Test Transaction failed: {}", test_res.err().unwrap()).as_str());
return false;
}
let r_ = DB_CON_POOL.set(conn_pool);
if r_.is_err() {
log(LogLevel::Fatal, "Database", "init_db", "Failed to set connection pool");
return false;
}
true
}

28
src/db/schema.rs Normal file
View File

@ -0,0 +1,28 @@
// @generated automatically by Diesel CLI.
diesel::table! {
guild (guild_id) {
guild_id -> BigInt,
channel_id -> BigInt,
}
}
diesel::table! {
user (discord_id) {
discord_id -> Text,
server -> Nullable<BigInt>,
fake_id -> BigInt,
when_generated -> Timestamp,
should_notify -> Bool,
is_guild_admin -> Bool,
is_banned -> Bool,
suspend_expires -> Nullable<Timestamp>,
}
}
diesel::joinable!(user -> guild (server));
diesel::allow_tables_to_appear_in_same_query!(
guild,
user,
);

41
src/handlers.rs Normal file
View File

@ -0,0 +1,41 @@
use serde::ser::StdError;
use poise::serenity_prelude::ChannelId;
use poise::serenity_prelude::{self as serenity};
use crate::logging::{LogLevel, log};
use crate::config::CORE_CFG;
pub async fn handle_msg(ctx: &serenity::Context, msg: &serenity::Message) -> Result<(), Box<(dyn StdError + std::marker::Send + Sync + 'static)>> {
if !msg.is_private() || msg.author.bot {
return Ok(());
}
log(LogLevel::Debug, "event_handlers", "handle_msg", msg.content.as_str());
let cfg = CORE_CFG.get().unwrap();
let new_channel = ChannelId::from(cfg.channel);
let picture = cfg.pictures.first().unwrap();
let attachment_uri = format!("attachment://{}", picture.clone());
let icon_file_uri = format!("{}/{}", cfg.picture_dir, picture.clone());
let msg: Result<serenity::Message, ::serenity::Error> = new_channel
.send_message(&ctx.http, |m| {
m.content("")
.embed(|e| {
e.title("")
.description(&msg.content)
.color(0x9834eb)
.author(|a| {
a.icon_url(attachment_uri);
a.name("85422818")
})
})
.add_file(icon_file_uri.as_str())
})
.await;
Ok(())
}
pub async fn handle_guild_join(ctx: &serenity::Context, guild: &serenity::Guild, is_new: &bool) -> Result<(), Box<(dyn StdError + std::marker::Send + Sync + 'static)>> {
Ok(())
}

View File

@ -1,4 +1,5 @@
use poise::serenity_prelude::{self as serenity};
use std::str::FromStr;
mod config;
use config::{load_core_cfg, CORE_CFG};
@ -9,15 +10,34 @@ use logging::{LogLevel, init_logger, log};
mod commands;
use commands::{notify::*, Data};
mod db;
use db::init_db;
mod handlers;
use handlers::*;
#[tokio::main]
async fn main() {
load_core_cfg(&"config.yaml".to_string());
let cfg = CORE_CFG.get().unwrap();
init_logger(&cfg.log_dir, LogLevel::Info);
init_logger(&cfg.log_dir, LogLevel::from_str(cfg.log_level.as_str()).unwrap());
if !init_db() {
return;
}
let framework = poise::Framework::builder()
.options(poise::FrameworkOptions {
event_handler: |ctx: &serenity::Context, event: &poise::Event<'_>, _framework, _data: &Data| {
Box::pin(async move {
log(LogLevel::Trace, "main", "event_handler", format!("Event Fired: {:?}", event.name()).as_str());
match event {
poise::Event::GuildCreate { guild, is_new } => handle_guild_join(ctx, guild, is_new).await,
poise::Event::Message { new_message } => handle_msg(ctx, new_message).await,
_ => Ok(()),
}
})
},
commands: vec![notify()],
..Default::default()
})