Working on database
This commit is contained in:
parent
dd33bc8f81
commit
90dadc92d6
|
@ -4,4 +4,5 @@
|
|||
Conf.toml
|
||||
/data
|
||||
/log
|
||||
join_audio.mp3
|
||||
*.mp3
|
||||
.env
|
|
@ -29,9 +29,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.38"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
|
||||
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
|
@ -91,6 +91,17 @@ dependencies = [
|
|||
"webpki-roots 0.21.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "audiopus"
|
||||
version = "0.2.0"
|
||||
|
@ -300,6 +311,39 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel"
|
||||
version = "1.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"diesel_derives",
|
||||
"pq-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_derives"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_migrations"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf3cde8413353dc7f5d72fa8ce0b99a560a359d2c5ef1e5817ca731cd9008f4c"
|
||||
dependencies = [
|
||||
"migrations_internals",
|
||||
"migrations_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
|
@ -343,6 +387,19 @@ dependencies = [
|
|||
"num-traits 0.1.43",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.20"
|
||||
|
@ -827,6 +884,27 @@ version = "2.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "migrations_internals"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b4fc84e4af020b837029e017966f86a1c2d5e83e64b589963d5047525995860"
|
||||
dependencies = [
|
||||
"diesel",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "migrations_macros"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c"
|
||||
dependencies = [
|
||||
"migrations_internals",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.16"
|
||||
|
@ -1135,6 +1213,15 @@ version = "0.2.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "pq-sys"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda"
|
||||
dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
|
@ -1361,14 +1448,34 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
|
||||
|
||||
[[package]]
|
||||
name = "rusty-bot-convert-data"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"diesel",
|
||||
"env_logger",
|
||||
"log",
|
||||
"rusty-bot-database",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusty-bot-database"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"diesel",
|
||||
"diesel_migrations",
|
||||
"log",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusty_bot"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"ctrlc",
|
||||
|
@ -1378,6 +1485,7 @@ dependencies = [
|
|||
"log4rs",
|
||||
"rand 0.8.3",
|
||||
"reqwest",
|
||||
"rusty-bot-database",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serenity",
|
||||
|
@ -1738,19 +1846,28 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.24"
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.24"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
|
||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2239,6 +2356,15 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"rusty-bot",
|
||||
"rusty-bot-database"
|
||||
"rusty-bot-database",
|
||||
"rusty-bot-convert-data"
|
||||
]
|
|
@ -11,4 +11,6 @@ root:
|
|||
- file-debug
|
||||
loggers:
|
||||
rusty_bot:
|
||||
level: trace
|
||||
rusty_bot_database:
|
||||
level: trace
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "rusty-bot-convert-data"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
rusty-bot-database = { path = "../rusty-bot-database" }
|
||||
log = "0.4.14"
|
||||
env_logger = "0.9.0"
|
||||
diesel = { version = "1.4", features = ["postgres"] }
|
|
@ -0,0 +1,64 @@
|
|||
use std::{env::args, path::Path};
|
||||
|
||||
use anyhow::Context;
|
||||
use diesel::{query_builder::AsQuery, RunQueryDsl};
|
||||
use env_logger::Env;
|
||||
use rusty_bot_database::{establish_connection, models::NewSettings};
|
||||
|
||||
mod models;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||
|
||||
let mut args = args().skip(1);
|
||||
|
||||
let data_path = args.next().expect("missing data path");
|
||||
let data_path = Path::new(&data_path);
|
||||
let database_url = args.next().expect("missing database url");
|
||||
|
||||
let conn = establish_connection(&database_url)?;
|
||||
|
||||
let guild_options_path = data_path.join("guilds_options");
|
||||
for entry in std::fs::read_dir(&guild_options_path)
|
||||
.with_context(move || format!("failed to open {:?}", guild_options_path))?
|
||||
.filter_map(|e| e.ok())
|
||||
{
|
||||
match serde_json::from_reader::<std::fs::File, models::GuildOptions>(std::fs::File::open(
|
||||
entry.path(),
|
||||
)?) {
|
||||
Ok(options) => {
|
||||
let id = entry
|
||||
.file_name()
|
||||
.to_string_lossy()
|
||||
.split('.')
|
||||
.next()
|
||||
.unwrap()
|
||||
.parse::<u64>()
|
||||
.unwrap();
|
||||
|
||||
let new_settings = NewSettings::new(
|
||||
id,
|
||||
options.mute_id,
|
||||
Some(options.roulette_options.kick_enabled),
|
||||
options.mention_log_channel,
|
||||
);
|
||||
|
||||
if let Err(e) = diesel::insert_into(rusty_bot_database::schema::settings::table)
|
||||
.values(&new_settings)
|
||||
.as_query()
|
||||
.execute(&conn)
|
||||
.context("failed to instart data")
|
||||
{
|
||||
println!("{:?}", e);
|
||||
} else {
|
||||
log::info!("inserted");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("While parsing guild option {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub(crate) struct GuildOptions {
|
||||
pub(crate) mute_id: Option<u64>,
|
||||
pub(crate) mention_log_channel: Option<u64>,
|
||||
pub(crate) roulette_options: RouletteOptions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub(crate) struct RouletteOptions {
|
||||
pub(crate) kick_enabled: bool,
|
||||
}
|
|
@ -6,3 +6,7 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
diesel = { version = "1.4", features = ["postgres"] }
|
||||
thiserror = "1.0"
|
||||
log = "0.4"
|
||||
diesel_migrations = "1.4"
|
|
@ -0,0 +1,5 @@
|
|||
# RustyBot Database
|
||||
|
||||
## TODO
|
||||
|
||||
![Screenshot](schema/database.svg)
|
|
@ -0,0 +1,5 @@
|
|||
# For documentation on how to configure this file,
|
||||
# see diesel.rs/guides/configuring-diesel-cli
|
||||
|
||||
[print_schema]
|
||||
file = "src/schema.rs"
|
|
@ -0,0 +1,6 @@
|
|||
-- This file was automatically created by Diesel to setup helper functions
|
||||
-- and other internal bookkeeping. This file is safe to edit, any future
|
||||
-- changes will be added to existing projects as new migrations.
|
||||
|
||||
DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
|
||||
DROP FUNCTION IF EXISTS diesel_set_updated_at();
|
|
@ -0,0 +1,36 @@
|
|||
-- This file was automatically created by Diesel to setup helper functions
|
||||
-- and other internal bookkeeping. This file is safe to edit, any future
|
||||
-- changes will be added to existing projects as new migrations.
|
||||
|
||||
|
||||
|
||||
|
||||
-- Sets up a trigger for the given table to automatically set a column called
|
||||
-- `updated_at` whenever the row is modified (unless `updated_at` was included
|
||||
-- in the modified columns)
|
||||
--
|
||||
-- # Example
|
||||
--
|
||||
-- ```sql
|
||||
-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
|
||||
--
|
||||
-- SELECT diesel_manage_updated_at('users');
|
||||
-- ```
|
||||
CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
|
||||
BEGIN
|
||||
EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
|
||||
FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
|
||||
BEGIN
|
||||
IF (
|
||||
NEW IS DISTINCT FROM OLD AND
|
||||
NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
|
||||
) THEN
|
||||
NEW.updated_at := current_timestamp;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
|
@ -0,0 +1,13 @@
|
|||
-- This file should undo anything in `up.sql`
|
||||
|
||||
drop table if exists music_info;
|
||||
|
||||
drop table if exists music_session_list;
|
||||
|
||||
drop table if exists music;
|
||||
|
||||
drop table if exists music_session;
|
||||
|
||||
drop table if exists settings;
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
CREATE TABLE MUSIC
|
||||
(
|
||||
musicID SERIAL NOT NULL,
|
||||
musicSourceURL TEXT NOT NULL,
|
||||
musicUserRequesterID BIGINT NOT NULL, -- TO BE TRANSMUTED TO U64 ?
|
||||
PRIMARY KEY (musicid)
|
||||
);
|
||||
|
||||
CREATE TABLE MUSIC_INFO
|
||||
(
|
||||
musicInfoSourceURL TEXT NOT NULL,
|
||||
musicInfoTitle TEXT NOT NULL,
|
||||
musicInfoThumbnailURL TEXT,
|
||||
musicInfoLength INTEGER NOT NULL,
|
||||
musicInfoMusicID INTEGER NOT NULL,
|
||||
PRIMARY KEY (musicInfoSourceURL)
|
||||
);
|
||||
|
||||
CREATE TABLE MUSIC_SESSION
|
||||
(
|
||||
musicSessionID SERIAL NOT NULL,
|
||||
musicSessionCurrentPlayingIndex SMALLINT DEFAULT 0, -- START FROM 0
|
||||
musicSessionGuildID BIGINT NOT NULL,
|
||||
musicSessionTextChannelID BIGINT NOT NULL,
|
||||
musicSessionPlayingChannelID BIGINT NOT NULL,
|
||||
PRIMARY KEY (musicsessionid)
|
||||
);
|
||||
|
||||
CREATE TABLE MUSIC_SESSION_LIST
|
||||
(
|
||||
musicSessionID INTEGER NOT NULL,
|
||||
musicID INTEGER NOT NULL,
|
||||
musicSessionListIndex SMALLINT NOT NULL,
|
||||
PRIMARY KEY (musicSessionID, musicID, musicSessionListIndex)
|
||||
);
|
||||
|
||||
CREATE TABLE SETTINGS
|
||||
(
|
||||
settingsGuildID BIGINT NOT NULL,
|
||||
settingsMuteRoleID BIGINT,
|
||||
settingsRouletteKickEnabled BOOLEAN DEFAULT FALSE,
|
||||
settingsLogChannelID BIGINT,
|
||||
PRIMARY KEY (settingsGuildID)
|
||||
);
|
||||
|
||||
ALTER TABLE MUSIC_INFO
|
||||
ADD FOREIGN KEY (musicInfoMusicID) REFERENCES MUSIC (musicID);
|
||||
|
||||
ALTER TABLE MUSIC_SESSION_LIST
|
||||
ADD FOREIGN KEY (musicID) REFERENCES MUSIC (musicID);
|
||||
|
||||
ALTER TABLE MUSIC_SESSION_LIST
|
||||
ADD FOREIGN KEY (musicSessionID) REFERENCES MUSIC_SESSION (musicSessionID);
|
|
@ -0,0 +1,244 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="911" height="346" view_box="0 0 911 346" xmlns="http://www.w3.org/2000/svg" xmlns:link="http://www.w3.org/1999/xlink">
|
||||
\n\n
|
||||
<desc>Généré par Mocodo 2.3.7 le Tue, 15 Mar 2022 13:53:31</desc>
|
||||
|
||||
<rect id="frame" x="0" y="0" width="911" height="346" fill="#f5f5f5" stroke="none" stroke-width="0" />
|
||||
|
||||
<!-- Association PLAYING_ON_MUSIC_SESSION -->
|
||||
<line x1="280" y1="127" x2="280" y2="43" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="285.0" y="85" fill="#01665e" font-family="Verdana" font-size="12">0,N</text>
|
||||
<line x1="481" y1="43" x2="280" y2="43" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="389" y="60.0" fill="#01665e" font-family="Verdana" font-size="12">0,1</text>
|
||||
<path d="M 415.0 43.0 L 403.0 49.0 L 407.0 43.0 L 403.0 37.0 Z" fill="#bf812d" stroke-width="0" />
|
||||
<g id="association-PLAYING_ON_MUSIC_SESSION">
|
||||
<path d="M 369 18 a 14 14 90 0 1 14 14 V 43 h -206 V 32 a 14 14 90 0 1 14 -14" fill="#dfc27d" stroke="#dfc27d" stroke-width="0" />
|
||||
<path d="M 383 43.0 v 11 a 14 14 90 0 1 -14 14 H 191 a 14 14 90 0 1 -14 -14 V 43.0 H 206" fill="#f6e8c3" stroke="#f6e8c3" stroke-width="0" />
|
||||
<rect x="177" y="18" width="206" height="50" fill="none" rx="14" stroke="#bf812d" stroke-width="2" />
|
||||
<line x1="177" y1="43" x2="383" y2="43" stroke="#bf812d" stroke-width="1" />
|
||||
<text x="184" y="35.7" fill="#000000" font-family="Verdana" font-size="12">PLAYING_ON_MUSIC_SESSION</text>
|
||||
</g>
|
||||
|
||||
<!-- Association LOG_CHANNEL -->
|
||||
<line x1="836" y1="43" x2="836" y2="127" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="841.0" y="85" fill="#01665e" font-family="Verdana" font-size="12">0,1</text>
|
||||
<path d="M 836.0 68.0 L 842.0 80.0 L 836.0 76.0 L 830.0 80.0 Z" fill="#bf812d" stroke-width="0" />
|
||||
<line x1="836" y1="228" x2="836" y2="127" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="841.0" y="186" fill="#01665e" font-family="Verdana" font-size="12">1,1</text>
|
||||
<g id="association-LOG_CHANNEL">
|
||||
<path d="M 875 102 a 14 14 90 0 1 14 14 V 127 h -106 V 116 a 14 14 90 0 1 14 -14" fill="#dfc27d" stroke="#dfc27d" stroke-width="0" />
|
||||
<path d="M 889 127.0 v 11 a 14 14 90 0 1 -14 14 H 797 a 14 14 90 0 1 -14 -14 V 127.0 H 106" fill="#f6e8c3" stroke="#f6e8c3" stroke-width="0" />
|
||||
<rect x="783" y="102" width="106" height="50" fill="none" rx="14" stroke="#bf812d" stroke-width="2" />
|
||||
<line x1="783" y1="127" x2="889" y2="127" stroke="#bf812d" stroke-width="1" />
|
||||
<text x="790" y="119.7" fill="#000000" font-family="Verdana" font-size="12">LOG_CHANNEL</text>
|
||||
</g>
|
||||
|
||||
<!-- Association TEXT_CHANNEL -->
|
||||
<line x1="836" y1="43" x2="664" y2="43" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="774" y="35.0" fill="#01665e" font-family="Verdana" font-size="12">1,1</text>
|
||||
<path d="M 800.0 43.0 L 788.0 49.0 L 792.0 43.0 L 788.0 37.0 Z" fill="#bf812d" stroke-width="0" />
|
||||
<line x1="481" y1="43" x2="664" y2="43" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="552" y="35.0" fill="#01665e" font-family="Verdana" font-size="12">0,1</text>
|
||||
<g id="association-TEXT_CHANNEL">
|
||||
<path d="M 706 18 a 14 14 90 0 1 14 14 V 43 h -112 V 32 a 14 14 90 0 1 14 -14" fill="#dfc27d" stroke="#dfc27d" stroke-width="0" />
|
||||
<path d="M 720 43.0 v 11 a 14 14 90 0 1 -14 14 H 622 a 14 14 90 0 1 -14 -14 V 43.0 H 112" fill="#f6e8c3" stroke="#f6e8c3" stroke-width="0" />
|
||||
<rect x="608" y="18" width="112" height="50" fill="none" rx="14" stroke="#bf812d" stroke-width="2" />
|
||||
<line x1="608" y1="43" x2="720" y2="43" stroke="#bf812d" stroke-width="1" />
|
||||
<text x="615" y="35.7" fill="#000000" font-family="Verdana" font-size="12">TEXT_CHANNEL</text>
|
||||
</g>
|
||||
|
||||
<!-- Association MUSIC_METADATAS -->
|
||||
<line x1="90" y1="228" x2="280" y2="228" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="162" y="245.0" fill="#01665e" font-family="Verdana" font-size="12">0,1</text>
|
||||
<path d="M 157.0 228.0 L 169.0 222.0 L 165.0 228.0 L 169.0 234.0 Z" fill="#bf812d" stroke-width="0" />
|
||||
<line x1="280" y1="127" x2="280" y2="228" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="285.0" y="178" fill="#01665e" font-family="Verdana" font-size="12">0,N</text>
|
||||
<g id="association-MUSIC_METADATAS">
|
||||
<path d="M 335 203 a 14 14 90 0 1 14 14 V 228 h -138 V 217 a 14 14 90 0 1 14 -14" fill="#dfc27d" stroke="#dfc27d" stroke-width="0" />
|
||||
<path d="M 349 228.0 v 11 a 14 14 90 0 1 -14 14 H 225 a 14 14 90 0 1 -14 -14 V 228.0 H 138" fill="#f6e8c3" stroke="#f6e8c3" stroke-width="0" />
|
||||
<rect x="211" y="203" width="138" height="50" fill="none" rx="14" stroke="#bf812d" stroke-width="2" />
|
||||
<line x1="211" y1="228" x2="349" y2="228" stroke="#bf812d" stroke-width="1" />
|
||||
<text x="218" y="220.7" fill="#000000" font-family="Verdana" font-size="12">MUSIC_METADATAS</text>
|
||||
</g>
|
||||
|
||||
<!-- Association MUSIC_REQUESTED_BY -->
|
||||
<line x1="90" y1="43" x2="90" y2="127" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="95.0" y="85" fill="#01665e" font-family="Verdana" font-size="12">1,1</text>
|
||||
<path d="M 90.0 68.0 L 96.0 80.0 L 90.0 76.0 L 84.0 80.0 Z" fill="#bf812d" stroke-width="0" />
|
||||
<line x1="280" y1="127" x2="90" y2="127" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="197" y="144.0" fill="#01665e" font-family="Verdana" font-size="12">0,N</text>
|
||||
<g id="association-MUSIC_REQUESTED_BY">
|
||||
<path d="M 157 102 a 14 14 90 0 1 14 14 V 127 h -162 V 116 a 14 14 90 0 1 14 -14" fill="#dfc27d" stroke="#dfc27d" stroke-width="0" />
|
||||
<path d="M 171 127.0 v 11 a 14 14 90 0 1 -14 14 H 23 a 14 14 90 0 1 -14 -14 V 127.0 H 162" fill="#f6e8c3" stroke="#f6e8c3" stroke-width="0" />
|
||||
<rect x="9" y="102" width="162" height="50" fill="none" rx="14" stroke="#bf812d" stroke-width="2" />
|
||||
<line x1="9" y1="127" x2="171" y2="127" stroke="#bf812d" stroke-width="1" />
|
||||
<text x="16" y="119.7" fill="#000000" font-family="Verdana" font-size="12">MUSIC_REQUESTED_BY</text>
|
||||
</g>
|
||||
|
||||
<!-- Association SETTINGS_OF_GUILD -->
|
||||
<line x1="836" y1="228" x2="664" y2="228" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="744" y="245.0" fill="#01665e" font-family="Verdana" font-size="12">0,1</text>
|
||||
<line x1="481" y1="228" x2="664" y2="228" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="513" y="245.0" fill="#01665e" font-family="Verdana" font-size="12">1,1</text>
|
||||
<path d="M 508.0 228.0 L 520.0 222.0 L 516.0 228.0 L 520.0 234.0 Z" fill="#bf812d" stroke-width="0" />
|
||||
<g id="association-SETTINGS_OF_GUILD">
|
||||
<path d="M 724 203 a 14 14 90 0 1 14 14 V 228 h -148 V 217 a 14 14 90 0 1 14 -14" fill="#dfc27d" stroke="#dfc27d" stroke-width="0" />
|
||||
<path d="M 738 228.0 v 11 a 14 14 90 0 1 -14 14 H 604 a 14 14 90 0 1 -14 -14 V 228.0 H 148" fill="#f6e8c3" stroke="#f6e8c3" stroke-width="0" />
|
||||
<rect x="590" y="203" width="148" height="50" fill="none" rx="14" stroke="#bf812d" stroke-width="2" />
|
||||
<line x1="590" y1="228" x2="738" y2="228" stroke="#bf812d" stroke-width="1" />
|
||||
<text x="597" y="220.7" fill="#000000" font-family="Verdana" font-size="12">SETTINGS_OF_GUILD</text>
|
||||
</g>
|
||||
|
||||
<!-- Association PLAYING_ON_GUILD -->
|
||||
<line x1="481" y1="43" x2="481" y2="127" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="455.0" y="94" fill="#01665e" font-family="Verdana" font-size="12">0,1</text>
|
||||
<line x1="481" y1="228" x2="481" y2="127" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="486.0" y="195" fill="#01665e" font-family="Verdana" font-size="12">1,1</text>
|
||||
<path d="M 481.0 203.0 L 475.0 191.0 L 481.0 195.0 L 487.0 191.0 Z" fill="#bf812d" stroke-width="0" />
|
||||
<g id="association-PLAYING_ON_GUILD">
|
||||
<path d="M 538 102 a 14 14 90 0 1 14 14 V 127 h -142 V 116 a 14 14 90 0 1 14 -14" fill="#dfc27d" stroke="#dfc27d" stroke-width="0" />
|
||||
<path d="M 552 127.0 v 11 a 14 14 90 0 1 -14 14 H 424 a 14 14 90 0 1 -14 -14 V 127.0 H 142" fill="#f6e8c3" stroke="#f6e8c3" stroke-width="0" />
|
||||
<rect x="410" y="102" width="142" height="50" fill="none" rx="14" stroke="#bf812d" stroke-width="2" />
|
||||
<line x1="410" y1="127" x2="552" y2="127" stroke="#bf812d" stroke-width="1" />
|
||||
<text x="417" y="119.7" fill="#000000" font-family="Verdana" font-size="12">PLAYING_ON_GUILD</text>
|
||||
</g>
|
||||
|
||||
<!-- Association PLAYING_ON_CHANNEL -->
|
||||
<line x1="481" y1="43" x2="664" y2="127" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="552" y="68.8895407756" fill="#01665e" font-family="Verdana" font-size="12">0,1</text>
|
||||
<line x1="836" y1="43" x2="664" y2="127" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="774" y="56.401628839" fill="#01665e" font-family="Verdana" font-size="12">1,1</text>
|
||||
<path d="M 800.0 60.5813953488 L 791.850201599 71.2388240268 L 792.811459872 64.0920777369 L 786.584178017 60.456013835 Z" fill="#bf812d" stroke-width="0" />
|
||||
<g id="association-PLAYING_ON_CHANNEL">
|
||||
<path d="M 730 102 a 14 14 90 0 1 14 14 V 127 h -160 V 116 a 14 14 90 0 1 14 -14" fill="#dfc27d" stroke="#dfc27d" stroke-width="0" />
|
||||
<path d="M 744 127.0 v 11 a 14 14 90 0 1 -14 14 H 598 a 14 14 90 0 1 -14 -14 V 127.0 H 160" fill="#f6e8c3" stroke="#f6e8c3" stroke-width="0" />
|
||||
<rect x="584" y="102" width="160" height="50" fill="none" rx="14" stroke="#bf812d" stroke-width="2" />
|
||||
<line x1="584" y1="127" x2="744" y2="127" stroke="#bf812d" stroke-width="1" />
|
||||
<text x="591" y="119.7" fill="#000000" font-family="Verdana" font-size="12">PLAYING_ON_CHANNEL</text>
|
||||
</g>
|
||||
|
||||
<!-- Association MUTE_ROLE -->
|
||||
<line x1="836" y1="228" x2="836" y2="312" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="841.0" y="279" fill="#01665e" font-family="Verdana" font-size="12">1,1</text>
|
||||
<line x1="664" y1="312" x2="836" y2="312" stroke="#bf812d" stroke-width="2" />
|
||||
<text x="693" y="329.0" fill="#01665e" font-family="Verdana" font-size="12">0,1</text>
|
||||
<path d="M 688.0 312.0 L 700.0 306.0 L 696.0 312.0 L 700.0 318.0 Z" fill="#bf812d" stroke-width="0" />
|
||||
<g id="association-MUTE_ROLE">
|
||||
<path d="M 867 287 a 14 14 90 0 1 14 14 V 312 h -90 V 301 a 14 14 90 0 1 14 -14" fill="#dfc27d" stroke="#dfc27d" stroke-width="0" />
|
||||
<path d="M 881 312.0 v 11 a 14 14 90 0 1 -14 14 H 805 a 14 14 90 0 1 -14 -14 V 312.0 H 90" fill="#f6e8c3" stroke="#f6e8c3" stroke-width="0" />
|
||||
<rect x="791" y="287" width="90" height="50" fill="none" rx="14" stroke="#bf812d" stroke-width="2" />
|
||||
<line x1="791" y1="312" x2="881" y2="312" stroke="#bf812d" stroke-width="1" />
|
||||
<text x="798" y="304.7" fill="#000000" font-family="Verdana" font-size="12">MUTE_ROLE</text>
|
||||
</g>
|
||||
|
||||
<!-- Entity GUILD -->
|
||||
<g id="entity-GUILD">
|
||||
<g id="frame-GUILD">
|
||||
<rect x="454" y="203" width="54" height="25" fill="#80cdc1" stroke="#80cdc1" stroke-width="0" />
|
||||
<rect x="454" y="228.0" width="54" height="25" fill="#c7eae5" stroke="#c7eae5" stroke-width="0" />
|
||||
<rect x="454" y="203" width="54" height="50" fill="none" stroke="#35978f" stroke-width="2" />
|
||||
<line x1="454" y1="228" x2="508" y2="228" stroke="#35978f" stroke-width="1" />
|
||||
</g>
|
||||
<text x="461" y="220.7" fill="#000000" font-family="Verdana" font-size="12">GUILD</text>
|
||||
<text x="459" y="245.8" fill="#000000" font-family="Verdana" font-size="12">guildID</text>
|
||||
<line x1="459" y1="248" x2="503" y2="248" stroke="#000000" stroke-width="1" />
|
||||
</g>
|
||||
|
||||
<!-- Entity SETTINGS -->
|
||||
<g id="entity-SETTINGS">
|
||||
<g id="frame-SETTINGS">
|
||||
<rect x="770" y="194" width="132" height="25" fill="#80cdc1" stroke="#80cdc1" stroke-width="0" />
|
||||
<rect x="770" y="219.0" width="132" height="43" fill="#c7eae5" stroke="#c7eae5" stroke-width="0" />
|
||||
<rect x="770" y="194" width="132" height="68" fill="none" stroke="#35978f" stroke-width="2" />
|
||||
<line x1="770" y1="219" x2="902" y2="219" stroke="#35978f" stroke-width="1" />
|
||||
</g>
|
||||
<text x="804" y="211.7" fill="#000000" font-family="Verdana" font-size="12">SETTINGS</text>
|
||||
<text x="775" y="236.8" fill="#000000" font-family="Verdana" font-size="12">settingsID</text>
|
||||
<line x1="775" y1="239" x2="838" y2="239" stroke="#000000" stroke-width="1" />
|
||||
<text x="775" y="253.8" fill="#000000" font-family="Verdana" font-size="12">rouletteKickEnabled</text>
|
||||
</g>
|
||||
|
||||
<!-- Entity DISCORD_USER -->
|
||||
<g id="entity-DISCORD_USER">
|
||||
<g id="frame-DISCORD_USER">
|
||||
<rect x="35" y="18" width="110" height="25" fill="#80cdc1" stroke="#80cdc1" stroke-width="0" />
|
||||
<rect x="35" y="43.0" width="110" height="25" fill="#c7eae5" stroke="#c7eae5" stroke-width="0" />
|
||||
<rect x="35" y="18" width="110" height="50" fill="none" stroke="#35978f" stroke-width="2" />
|
||||
<line x1="35" y1="43" x2="145" y2="43" stroke="#35978f" stroke-width="1" />
|
||||
</g>
|
||||
<text x="40" y="35.7" fill="#000000" font-family="Verdana" font-size="12">DISCORD_USER</text>
|
||||
<text x="40" y="60.8" fill="#000000" font-family="Verdana" font-size="12">userId</text>
|
||||
<line x1="40" y1="63" x2="80" y2="63" stroke="#000000" stroke-width="1" />
|
||||
</g>
|
||||
|
||||
<!-- Entity MUSIC_INFO -->
|
||||
<g id="entity-MUSIC_INFO">
|
||||
<g id="frame-MUSIC_INFO">
|
||||
<rect x="23" y="177" width="134" height="25" fill="#80cdc1" stroke="#80cdc1" stroke-width="0" />
|
||||
<rect x="23" y="202.0" width="134" height="77" fill="#c7eae5" stroke="#c7eae5" stroke-width="0" />
|
||||
<rect x="23" y="177" width="134" height="102" fill="none" stroke="#35978f" stroke-width="2" />
|
||||
<line x1="23" y1="202" x2="157" y2="202" stroke="#35978f" stroke-width="1" />
|
||||
</g>
|
||||
<text x="50" y="194.7" fill="#000000" font-family="Verdana" font-size="12">MUSIC_INFO</text>
|
||||
<text x="28" y="219.7" fill="#000000" font-family="Verdana" font-size="12">musicSourceURL</text>
|
||||
<line x1="28" y1="222" x2="129" y2="222" stroke="#000000" stroke-width="1" />
|
||||
<text x="28" y="236.8" fill="#000000" font-family="Verdana" font-size="12">musicTitle</text>
|
||||
<text x="28" y="253.8" fill="#000000" font-family="Verdana" font-size="12">musicThumbnailURL</text>
|
||||
<text x="28" y="270.8" fill="#000000" font-family="Verdana" font-size="12">musicLength</text>
|
||||
</g>
|
||||
|
||||
<!-- Entity MUSIC -->
|
||||
<g id="entity-MUSIC">
|
||||
<g id="frame-MUSIC">
|
||||
<rect x="224" y="93" width="112" height="25" fill="#80cdc1" stroke="#80cdc1" stroke-width="0" />
|
||||
<rect x="224" y="118.0" width="112" height="43" fill="#c7eae5" stroke="#c7eae5" stroke-width="0" />
|
||||
<rect x="224" y="93" width="112" height="68" fill="none" stroke="#35978f" stroke-width="2" />
|
||||
<line x1="224" y1="118" x2="336" y2="118" stroke="#35978f" stroke-width="1" />
|
||||
</g>
|
||||
<text x="259" y="110.7" fill="#000000" font-family="Verdana" font-size="12">MUSIC</text>
|
||||
<text x="229" y="135.8" fill="#000000" font-family="Verdana" font-size="12">musicID</text>
|
||||
<line x1="229" y1="138" x2="279" y2="138" stroke="#000000" stroke-width="1" />
|
||||
<text x="229" y="152.8" fill="#000000" font-family="Verdana" font-size="12">musicSourceURL</text>
|
||||
</g>
|
||||
|
||||
<!-- Entity ROLE -->
|
||||
<g id="entity-ROLE">
|
||||
<g id="frame-ROLE">
|
||||
<rect x="640" y="287" width="48" height="25" fill="#80cdc1" stroke="#80cdc1" stroke-width="0" />
|
||||
<rect x="640" y="312.0" width="48" height="25" fill="#c7eae5" stroke="#c7eae5" stroke-width="0" />
|
||||
<rect x="640" y="287" width="48" height="50" fill="none" stroke="#35978f" stroke-width="2" />
|
||||
<line x1="640" y1="312" x2="688" y2="312" stroke="#35978f" stroke-width="1" />
|
||||
</g>
|
||||
<text x="647" y="304.7" fill="#000000" font-family="Verdana" font-size="12">ROLE</text>
|
||||
<text x="645" y="329.8" fill="#000000" font-family="Verdana" font-size="12">roleID</text>
|
||||
<line x1="645" y1="332" x2="683" y2="332" stroke="#000000" stroke-width="1" />
|
||||
</g>
|
||||
|
||||
<!-- Entity MUSIC_SESSION -->
|
||||
<g id="entity-MUSIC_SESSION">
|
||||
<g id="frame-MUSIC_SESSION">
|
||||
<rect x="415" y="9" width="132" height="25" fill="#80cdc1" stroke="#80cdc1" stroke-width="0" />
|
||||
<rect x="415" y="34.0" width="132" height="43" fill="#c7eae5" stroke="#c7eae5" stroke-width="0" />
|
||||
<rect x="415" y="9" width="132" height="68" fill="none" stroke="#35978f" stroke-width="2" />
|
||||
<line x1="415" y1="34" x2="547" y2="34" stroke="#35978f" stroke-width="1" />
|
||||
</g>
|
||||
<text x="428" y="26.7" fill="#000000" font-family="Verdana" font-size="12">MUSIC_SESSION</text>
|
||||
<text x="420" y="51.8" fill="#000000" font-family="Verdana" font-size="12">musicSessionID</text>
|
||||
<line x1="420" y1="54" x2="516" y2="54" stroke="#000000" stroke-width="1" />
|
||||
<text x="420" y="68.8" fill="#000000" font-family="Verdana" font-size="12">currentPlayingIndex</text>
|
||||
</g>
|
||||
|
||||
<!-- Entity CHANNEL -->
|
||||
<g id="entity-CHANNEL">
|
||||
<g id="frame-CHANNEL">
|
||||
<rect x="800" y="18" width="72" height="25" fill="#80cdc1" stroke="#80cdc1" stroke-width="0" />
|
||||
<rect x="800" y="43.0" width="72" height="25" fill="#c7eae5" stroke="#c7eae5" stroke-width="0" />
|
||||
<rect x="800" y="18" width="72" height="50" fill="none" stroke="#35978f" stroke-width="2" />
|
||||
<line x1="800" y1="43" x2="872" y2="43" stroke="#35978f" stroke-width="1" />
|
||||
</g>
|
||||
<text x="806" y="35.7" fill="#000000" font-family="Verdana" font-size="12">CHANNEL</text>
|
||||
<text x="805" y="60.8" fill="#000000" font-family="Verdana" font-size="12">channelID</text>
|
||||
<line x1="805" y1="63" x2="867" y2="63" stroke="#000000" stroke-width="1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,21 @@
|
|||
DISCORD_USER: userId
|
||||
PLAYING_ON_MUSIC_SESSION, 0N MUSIC, 01> MUSIC_SESSION
|
||||
MUSIC_SESSION: musicSessionID, currentPlayingIndex
|
||||
TEXT_CHANNEL, 11> CHANNEL, 01 MUSIC_SESSION
|
||||
CHANNEL: channelID
|
||||
|
||||
MUSIC_REQUESTED_BY, 11> DISCORD_USER, 0N MUSIC
|
||||
MUSIC: musicID, musicSourceURL
|
||||
PLAYING_ON_GUILD, 01 MUSIC_SESSION, 11> GUILD
|
||||
PLAYING_ON_CHANNEL, 01 MUSIC_SESSION, 11> CHANNEL
|
||||
LOG_CHANNEL, 01> CHANNEL, 11 SETTINGS
|
||||
|
||||
MUSIC_INFO: musicSourceURL, musicTitle, musicThumbnailURL, musicLength
|
||||
MUSIC_METADATAS, 01> MUSIC_INFO, 0N MUSIC
|
||||
GUILD: guildID
|
||||
SETTINGS_OF_GUILD, 01 SETTINGS, 11> GUILD
|
||||
SETTINGS: settingsID, rouletteKickEnabled
|
||||
|
||||
:::
|
||||
ROLE: roleID
|
||||
MUTE_ROLE, 11 SETTINGS, 01> ROLE
|
|
@ -0,0 +1,23 @@
|
|||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
#[error("Failed to fetch")]
|
||||
Database(#[from] diesel::result::Error),
|
||||
#[error("Failed to connect to db")]
|
||||
Connection(#[from] diesel::result::ConnectionError),
|
||||
#[error("Failed to run migrations")]
|
||||
Migrations(#[from] diesel_migrations::RunMigrationsError)
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn is_not_found_error(&self) -> bool {
|
||||
if let Error::Database(e) = self {
|
||||
e == &diesel::result::Error::NotFound
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
|
@ -1 +1,24 @@
|
|||
// KEEP
|
||||
#[macro_use]
|
||||
pub extern crate diesel;
|
||||
|
||||
#[macro_use]
|
||||
extern crate diesel_migrations;
|
||||
|
||||
use diesel::prelude::*;
|
||||
|
||||
pub mod error;
|
||||
pub mod models;
|
||||
pub mod queries;
|
||||
pub mod schema;
|
||||
|
||||
use error::*;
|
||||
|
||||
diesel_migrations::embed_migrations!();
|
||||
|
||||
pub fn establish_connection(database_url: &str) -> Result<PgConnection> {
|
||||
let conn = PgConnection::establish(&database_url)?;
|
||||
|
||||
embedded_migrations::run(&conn)?;
|
||||
|
||||
Ok(conn)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
#[derive(Queryable, Debug)]
|
||||
pub struct Music {
|
||||
pub id: i32,
|
||||
pub music_source_url: String,
|
||||
pub music_requester_id: i64,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Debug)]
|
||||
pub struct MusicInfo {
|
||||
pub source_url: String,
|
||||
pub info_title: Option<String>,
|
||||
pub thumbnail_url: Option<String>,
|
||||
pub length: i32,
|
||||
pub music_id: i64,
|
||||
}
|
||||
|
||||
// TODO FIX SCHEMA DIR
|
||||
#[derive(Queryable, Debug)]
|
||||
pub struct MusicSession {
|
||||
pub id: i32,
|
||||
pub current_playing_index: Option<i16>,
|
||||
pub guild_id: i64,
|
||||
pub text_channel_id: i64,
|
||||
pub playing_channel_id: i64,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Debug)]
|
||||
pub struct MusicSessionList {
|
||||
pub session_id: i32,
|
||||
pub music_id: i32,
|
||||
pub index: i16,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Debug)]
|
||||
pub struct Settings {
|
||||
pub guild_id: i64,
|
||||
pub mute_role_id: Option<i64>,
|
||||
pub roulette_kick_enabled: Option<bool>,
|
||||
pub log_channel_id: Option<i64>,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub fn get_mute_role_id(&self) -> Option<u64> {
|
||||
self.mute_role_id
|
||||
.map(|id| unsafe { std::mem::transmute(id) })
|
||||
}
|
||||
}
|
||||
|
||||
use super::schema::settings;
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[table_name = "settings"]
|
||||
pub struct NewSettings {
|
||||
#[column_name = "settingsguildid"]
|
||||
pub guild_id: i64,
|
||||
#[column_name = "settingsmuteroleid"]
|
||||
pub mute_role_id: Option<i64>,
|
||||
#[column_name = "settingsroulettekickenabled"]
|
||||
pub roulette_kick_enabled: Option<bool>,
|
||||
#[column_name = "settingslogchannelid"]
|
||||
pub log_channel_id: Option<i64>,
|
||||
}
|
||||
|
||||
impl NewSettings {
|
||||
pub fn new(
|
||||
guild_id: u64,
|
||||
mute_role_id: Option<u64>,
|
||||
roulette_kick_enabled: Option<bool>,
|
||||
log_channel_id: Option<u64>,
|
||||
) -> Self {
|
||||
Self {
|
||||
guild_id: unsafe { std::mem::transmute(guild_id) },
|
||||
mute_role_id: mute_role_id.map(|f| unsafe { std::mem::transmute(f) }),
|
||||
roulette_kick_enabled,
|
||||
log_channel_id: log_channel_id.map(|f| unsafe { std::mem::transmute(f) }),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
use diesel::prelude::*;
|
||||
use diesel::{QueryDsl, RunQueryDsl};
|
||||
|
||||
use crate::models::{NewSettings, Settings};
|
||||
use crate::schema;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
pub trait RustyConnectionExt {
|
||||
fn fetch_settings(&self, guild_id: u64) -> Result<Settings>;
|
||||
fn settings_edit_kick(&self, guild_id: u64, disable: bool) -> Result<()>;
|
||||
fn settings_fetch_mute_role(&self, guild_id: u64) -> Result<Option<u64>>;
|
||||
fn settings_edit_mute_role(&self, guild_id: u64, mute_role: Option<u64>) -> Result<()>;
|
||||
fn settings_fetch_log_channel(&self, guild_id: u64) -> Result<Option<u64>>;
|
||||
fn settings_edit_log_channel(&self, guild_id: u64, channel: Option<u64>) -> Result<()>;
|
||||
fn insert_settings(&self, settings: NewSettings) -> Result<()>;
|
||||
}
|
||||
|
||||
impl RustyConnectionExt for PgConnection {
|
||||
fn fetch_settings(&self, guild_id: u64) -> Result<Settings> {
|
||||
use schema::settings::dsl::*;
|
||||
|
||||
let id = unsafe { std::mem::transmute::<u64, i64>(guild_id) };
|
||||
|
||||
let res = settings
|
||||
.filter(settingsguildid.eq(id))
|
||||
.first::<Settings>(self)?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn settings_edit_kick(&self, guild_id: u64, disable: bool) -> Result<()> {
|
||||
use schema::settings::dsl::*;
|
||||
|
||||
let id = unsafe { std::mem::transmute::<u64, i64>(guild_id) };
|
||||
|
||||
if diesel::update(settings)
|
||||
.set(settingsroulettekickenabled.eq(!disable))
|
||||
.filter(settingsguildid.eq(id))
|
||||
.execute(self)?
|
||||
== 0
|
||||
{
|
||||
log::error!("inserting");
|
||||
diesel::insert_into(super::schema::settings::table)
|
||||
.values(&NewSettings::new(guild_id, None, Some(!disable), None))
|
||||
.execute(self)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn settings_edit_mute_role(&self, guild_id: u64, mute_role: Option<u64>) -> Result<()> {
|
||||
use schema::settings::dsl::*;
|
||||
|
||||
let id = unsafe { std::mem::transmute::<u64, i64>(guild_id) };
|
||||
let mute_role = mute_role.map(|id| unsafe { std::mem::transmute::<u64, i64>(id) });
|
||||
|
||||
if diesel::update(settings)
|
||||
.set(settingsmuteroleid.eq(mute_role))
|
||||
.filter(settingsguildid.eq(id))
|
||||
.execute(self)?
|
||||
== 0
|
||||
{
|
||||
diesel::insert_into(super::schema::settings::table)
|
||||
.values(&NewSettings {
|
||||
guild_id: id,
|
||||
mute_role_id: mute_role,
|
||||
roulette_kick_enabled: None,
|
||||
log_channel_id: None,
|
||||
})
|
||||
.execute(self)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn settings_fetch_mute_role(&self, guild_id: u64) -> Result<Option<u64>> {
|
||||
use schema::settings::dsl::*;
|
||||
|
||||
let id: QueryResult<Option<i64>> = settings
|
||||
.select(settingsmuteroleid)
|
||||
.filter(settingsguildid.eq(unsafe { std::mem::transmute::<u64, i64>(guild_id) }))
|
||||
.get_result(self);
|
||||
|
||||
if id == Err(diesel::result::Error::NotFound) {
|
||||
Ok(None)
|
||||
} else {
|
||||
let id = id?;
|
||||
Ok(id.map(|id| unsafe { std::mem::transmute(id) }))
|
||||
}
|
||||
}
|
||||
|
||||
fn settings_fetch_log_channel(&self, guild_id: u64) -> Result<Option<u64>> {
|
||||
use schema::settings::dsl::*;
|
||||
|
||||
let id: QueryResult<Option<i64>> = settings
|
||||
.select(settingslogchannelid)
|
||||
.filter(settingsguildid.eq(unsafe { std::mem::transmute::<u64, i64>(guild_id) }))
|
||||
.get_result(self);
|
||||
|
||||
if id == Err(diesel::result::Error::NotFound) {
|
||||
Ok(None)
|
||||
} else {
|
||||
let id = id?;
|
||||
Ok(id.map(|id| unsafe { std::mem::transmute(id) }))
|
||||
}
|
||||
}
|
||||
|
||||
fn settings_edit_log_channel(&self, guild_id: u64, channel: Option<u64>) -> Result<()> {
|
||||
use schema::settings::dsl::*;
|
||||
|
||||
let id = unsafe { std::mem::transmute::<u64, i64>(guild_id) };
|
||||
let channel = channel.map(|id| unsafe { std::mem::transmute::<u64, i64>(id) });
|
||||
|
||||
if diesel::update(settings)
|
||||
.set(settingslogchannelid.eq(channel))
|
||||
.filter(settingsguildid.eq(id))
|
||||
.execute(self)?
|
||||
== 0
|
||||
{
|
||||
diesel::insert_into(super::schema::settings::table)
|
||||
.values(&NewSettings {
|
||||
guild_id: id,
|
||||
mute_role_id: None,
|
||||
roulette_kick_enabled: None,
|
||||
log_channel_id: channel,
|
||||
})
|
||||
.execute(self)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn insert_settings(&self, settings: NewSettings) -> Result<()> {
|
||||
diesel::insert_into(super::schema::settings::table)
|
||||
.values(&settings)
|
||||
.execute(self)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
table! {
|
||||
music (musicid) {
|
||||
musicid -> Int4,
|
||||
musicsourceurl -> Text,
|
||||
musicuserrequesterid -> Int8,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
music_info (musicinfosourceurl) {
|
||||
musicinfosourceurl -> Text,
|
||||
musicinfotitle -> Text,
|
||||
musicinfothumbnailurl -> Nullable<Text>,
|
||||
musicinfolength -> Int4,
|
||||
musicinfomusicid -> Int4,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
music_session (musicsessionid) {
|
||||
musicsessionid -> Int4,
|
||||
musicsessioncurrentplayingindex -> Nullable<Int2>,
|
||||
musicsessionguildid -> Int8,
|
||||
musicsessiontextchannelid -> Int8,
|
||||
musicsessionplayingchannelid -> Int8,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
music_session_list (musicsessionid, musicid, musicsessionlistindex) {
|
||||
musicsessionid -> Int4,
|
||||
musicid -> Int4,
|
||||
musicsessionlistindex -> Int2,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
settings (settingsguildid) {
|
||||
settingsguildid -> Int8,
|
||||
settingsmuteroleid -> Nullable<Int8>,
|
||||
settingsroulettekickenabled -> Nullable<Bool>,
|
||||
settingslogchannelid -> Nullable<Int8>,
|
||||
}
|
||||
}
|
||||
|
||||
joinable!(music_info -> music (musicinfomusicid));
|
||||
joinable!(music_session_list -> music (musicid));
|
||||
joinable!(music_session_list -> music_session (musicsessionid));
|
||||
|
||||
allow_tables_to_appear_in_same_query!(
|
||||
music,
|
||||
music_info,
|
||||
music_session,
|
||||
music_session_list,
|
||||
settings,
|
||||
);
|
|
@ -3,6 +3,7 @@ name = "rusty_bot"
|
|||
version = "0.1.0"
|
||||
authors = ["oupson"]
|
||||
edition = "2018"
|
||||
default-run = "rusty_bot"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -25,3 +26,5 @@ log = "0.4"
|
|||
log4rs = "1.0"
|
||||
ctrlc = "3.1"
|
||||
songbird = { version = "0.2", features = ["driver", "builtin-queue", "yt-dlp"], optional = true }
|
||||
rusty-bot-database = { path = "../rusty-bot-database" }
|
||||
anyhow = "1.0.56"
|
|
@ -1,3 +1,4 @@
|
|||
use rusty_bot_database::queries::RustyConnectionExt;
|
||||
use serenity::{
|
||||
client::Context,
|
||||
framework::standard::CommandResult,
|
||||
|
@ -14,7 +15,7 @@ use serenity::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::{data::GuildOptionsKey, utils::message::embed_author};
|
||||
use crate::{utils::message::embed_author, DatabaseKey};
|
||||
|
||||
pub(crate) async fn handle_interaction(ctx: &Context, interaction: &Interaction) -> CommandResult {
|
||||
match interaction {
|
||||
|
@ -83,14 +84,13 @@ async fn goulag(
|
|||
author: &Member,
|
||||
) -> CommandResult {
|
||||
let ctx_data = ctx.data.read().await;
|
||||
let ctx_data = ctx_data
|
||||
.get::<GuildOptionsKey>()
|
||||
.expect("Failed to get guild cache");
|
||||
|
||||
let guild_options = ctx_data.get(&guild_id.into());
|
||||
let conn = ctx_data.get::<DatabaseKey>().expect("failed to get db");
|
||||
let conn = conn.lock().await;
|
||||
let guild_options = conn.fetch_settings(guild_id).ok();
|
||||
|
||||
if let Some(guild_options) = guild_options {
|
||||
if let Some(mute_role) = guild_options.get_mute_role() {
|
||||
if let Some(mute_role) = guild_options.get_mute_role_id() {
|
||||
let options = &data.options;
|
||||
|
||||
let user = options
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use rusty_bot_database::queries::RustyConnectionExt;
|
||||
use serenity::{
|
||||
builder::CreateMessage,
|
||||
client::Context,
|
||||
|
@ -5,15 +6,15 @@ use serenity::{
|
|||
model::{
|
||||
channel::Message,
|
||||
guild::{Member, PartialMember},
|
||||
id::GuildId,
|
||||
id::{GuildId, RoleId},
|
||||
Permissions,
|
||||
},
|
||||
};
|
||||
use songbird::{input::Metadata, Call};
|
||||
|
||||
use crate::{
|
||||
data::GuildOptionsKey,
|
||||
utils::{message::embed_author, permissions::has_permission},
|
||||
DatabaseKey,
|
||||
};
|
||||
|
||||
use super::error::UseVoiceError;
|
||||
|
@ -24,13 +25,13 @@ pub(crate) async fn is_mute(
|
|||
guild_id: GuildId,
|
||||
) -> CommandResult<bool> {
|
||||
let data = ctx.data.read().await;
|
||||
let conn = data.get::<DatabaseKey>().expect("failed to get db");
|
||||
let conn = conn.lock().await;
|
||||
|
||||
let data = data
|
||||
.get::<GuildOptionsKey>()
|
||||
.expect("Failed to get guild cache");
|
||||
let role_id = conn.settings_fetch_mute_role(guild_id.0)?;
|
||||
|
||||
if let Some(mute_role) = data.get(&guild_id).and_then(|o| o.get_mute_role()) {
|
||||
Ok(member.roles.contains(&mute_role))
|
||||
if let Some(mute_role) = role_id {
|
||||
Ok(member.roles.contains(&RoleId(mute_role)))
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use crate::{
|
||||
api,
|
||||
data::{GuildOptions, GuildOptionsKey},
|
||||
};
|
||||
use crate::{api, DatabaseKey};
|
||||
use rand::Rng;
|
||||
use rusty_bot_database::{queries::RustyConnectionExt};
|
||||
use serenity::{
|
||||
framework::standard::{
|
||||
macros::{command, group},
|
||||
|
@ -45,13 +43,13 @@ async fn shot(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
|||
#[only_in(guilds)]
|
||||
async fn kick(ctx: &Context, msg: &Message) -> CommandResult {
|
||||
if let Some(guild_id) = &msg.guild_id {
|
||||
let mut data = ctx.data.write().await;
|
||||
let guilds_options = data
|
||||
.get_mut::<GuildOptionsKey>()
|
||||
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||
let data = ctx.data.read().await;
|
||||
let conn = data.get::<DatabaseKey>().expect("failed to get db");
|
||||
let conn = conn.lock().await;
|
||||
let guild_options = conn.fetch_settings(guild_id.0).ok();
|
||||
|
||||
let guild_options = guilds_options.entry(*guild_id).or_default();
|
||||
if !guild_options.roulette_options.kick_enabled {
|
||||
if !(guild_options.is_some() && guild_options.unwrap().roulette_kick_enabled == Some(true))
|
||||
{
|
||||
msg.channel_id
|
||||
.say(
|
||||
ctx,
|
||||
|
@ -85,27 +83,23 @@ async fn kick(ctx: &Context, msg: &Message) -> CommandResult {
|
|||
#[required_permissions("ADMINISTRATOR")]
|
||||
#[owner_privilege]
|
||||
async fn disable_kick(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||
let disable = match args.len() {
|
||||
0 => true,
|
||||
_ => args.single::<bool>()?,
|
||||
};
|
||||
let mut data = ctx.data.write().await;
|
||||
let guilds_options = data
|
||||
.get_mut::<GuildOptionsKey>()
|
||||
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||
|
||||
if let Some(guild_id) = msg.guild_id {
|
||||
let entry = guilds_options
|
||||
.entry(guild_id)
|
||||
.or_insert_with(|| GuildOptions::default().set_guild_id(guild_id));
|
||||
entry.roulette_options.kick_enabled = !disable;
|
||||
let disable = match args.len() {
|
||||
0 => true,
|
||||
_ => args.single::<bool>()?,
|
||||
};
|
||||
|
||||
let data = ctx.data.read().await;
|
||||
let conn = data.get::<DatabaseKey>().expect("failed to get db");
|
||||
let conn = conn.lock().await;
|
||||
|
||||
conn.settings_edit_kick(guild_id.0, disable)?;
|
||||
|
||||
if disable {
|
||||
msg.channel_id.say(ctx, "No fun allowed").await?;
|
||||
} else {
|
||||
msg.channel_id.say(ctx, "Done").await?;
|
||||
}
|
||||
|
||||
entry.save_async(guild_id.0).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use rusty_bot_database::queries::RustyConnectionExt;
|
||||
use serenity::{
|
||||
client::Context,
|
||||
framework::standard::{Args, CommandResult},
|
||||
|
@ -11,7 +12,7 @@ use serenity::{
|
|||
model::prelude::*,
|
||||
};
|
||||
|
||||
use crate::data::{GuildOptions, GuildOptionsKey};
|
||||
use crate::DatabaseKey;
|
||||
|
||||
#[group]
|
||||
#[prefix("settings")]
|
||||
|
@ -28,55 +29,44 @@ async fn muterole(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
|
|||
_ => Some(args.single::<String>()?),
|
||||
};
|
||||
|
||||
if let Some(id) = role_id {
|
||||
let mut data = ctx.data.write().await;
|
||||
if let Some(guild_id) = msg.guild_id {
|
||||
if let Some(id) = role_id {
|
||||
let data = ctx.data.read().await;
|
||||
let conn = data.get::<DatabaseKey>().expect("failed to get db");
|
||||
let conn = conn.lock().await;
|
||||
|
||||
let guilds_options = data
|
||||
.get_mut::<GuildOptionsKey>()
|
||||
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||
|
||||
if let Some(guild_id) = msg.guild_id {
|
||||
let entry = guilds_options
|
||||
.entry(guild_id)
|
||||
.or_insert_with(|| GuildOptions::default().set_guild_id(guild_id));
|
||||
|
||||
entry.mute_id = match id.as_str() {
|
||||
"none" => None,
|
||||
_ => Some(RoleId::from_str(&id)?),
|
||||
};
|
||||
|
||||
entry.save_async(guild_id.0).await?;
|
||||
conn.settings_edit_mute_role(
|
||||
guild_id.0,
|
||||
match id.as_str() {
|
||||
"none" => None,
|
||||
_ => Some(RoleId::from_str(&id)?.0),
|
||||
},
|
||||
)?;
|
||||
|
||||
msg.channel_id.say(&ctx.http, "Saved").await?;
|
||||
}
|
||||
} else {
|
||||
let data = ctx.data.read().await;
|
||||
} else {
|
||||
let data = ctx.data.read().await;
|
||||
|
||||
let guilds_options = data
|
||||
.get::<GuildOptionsKey>()
|
||||
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||
let conn = data.get::<DatabaseKey>().expect("failed to get db");
|
||||
let conn = conn.lock().await;
|
||||
|
||||
if let Some(guild_id) = msg.guild_id {
|
||||
if let Some(options) = guilds_options.get(&guild_id) {
|
||||
msg.channel_id
|
||||
.say(
|
||||
&ctx.http,
|
||||
if let Some(role_id) = options.mute_id {
|
||||
format!(
|
||||
"Mute role is @{}",
|
||||
role_id.to_role_cached(&ctx).await.unwrap().name
|
||||
)
|
||||
} else {
|
||||
"Mute role is None".to_string()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
msg.channel_id.say(&ctx.http, "Mute role is None").await?;
|
||||
}
|
||||
let role_id = conn.settings_fetch_mute_role(guild_id.0)?;
|
||||
|
||||
msg.channel_id
|
||||
.say(
|
||||
&ctx.http,
|
||||
if let Some(role_id) = role_id {
|
||||
format!(
|
||||
"Mute role is @{}",
|
||||
RoleId(role_id).to_role_cached(&ctx).await.unwrap().name
|
||||
)
|
||||
} else {
|
||||
"Mute role is None".to_string()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -90,51 +80,38 @@ async fn logchannel(ctx: &Context, msg: &Message, mut args: Args) -> CommandResu
|
|||
_ => Some(args.single::<String>()?),
|
||||
};
|
||||
|
||||
if let Some(id) = channel_id {
|
||||
let mut data = ctx.data.write().await;
|
||||
if let Some(guild_id) = msg.guild_id {
|
||||
if let Some(id) = channel_id {
|
||||
let data = ctx.data.read().await;
|
||||
let conn = data.get::<DatabaseKey>().expect("failed to get db");
|
||||
let conn = conn.lock().await;
|
||||
|
||||
let guilds_options = data
|
||||
.get_mut::<GuildOptionsKey>()
|
||||
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||
|
||||
if let Some(guild_id) = msg.guild_id {
|
||||
let entry = guilds_options
|
||||
.entry(guild_id)
|
||||
.or_insert_with(|| GuildOptions::default().set_guild_id(guild_id));
|
||||
|
||||
entry.mention_log_channel = match id.as_str() {
|
||||
"none" => None,
|
||||
_ => Some(ChannelId::from_str(&id)?),
|
||||
};
|
||||
|
||||
entry.save_async(guild_id.0).await?;
|
||||
conn.settings_edit_log_channel(
|
||||
guild_id.0,
|
||||
match id.as_str() {
|
||||
"none" => None,
|
||||
_ => Some(ChannelId::from_str(&id)?.0),
|
||||
},
|
||||
)?;
|
||||
|
||||
msg.channel_id.say(&ctx.http, "Saved").await?;
|
||||
}
|
||||
} else {
|
||||
let data = ctx.data.read().await;
|
||||
} else {
|
||||
let data = ctx.data.read().await;
|
||||
let conn = data.get::<DatabaseKey>().expect("failed to get db");
|
||||
let conn = conn.lock().await;
|
||||
|
||||
let guilds_options = data
|
||||
.get::<GuildOptionsKey>()
|
||||
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||
let log_channel = conn.settings_fetch_log_channel(guild_id.0)?;
|
||||
|
||||
if let Some(guild_id) = msg.guild_id {
|
||||
if let Some(options) = guilds_options.get(&guild_id) {
|
||||
msg.channel_id
|
||||
.say(
|
||||
&ctx.http,
|
||||
if let Some(channel_id) = options.mention_log_channel {
|
||||
format!("Logging channel is {}", channel_id.mention())
|
||||
} else {
|
||||
"Logging channel is None".to_string()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
msg.channel_id
|
||||
.say(&ctx.http, "Logging channel is None")
|
||||
.await?;
|
||||
}
|
||||
msg.channel_id
|
||||
.say(
|
||||
&ctx.http,
|
||||
if let Some(channel_id) = log_channel {
|
||||
format!("Logging channel is {}", ChannelId(channel_id).mention())
|
||||
} else {
|
||||
"Logging channel is None".to_string()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,4 +10,5 @@ pub(crate) struct Bot {
|
|||
pub(crate) token: String,
|
||||
pub(crate) application_id: u64,
|
||||
pub(crate) invite_url: Option<String>,
|
||||
pub(crate) database_url: String,
|
||||
}
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
use log::error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::{
|
||||
model::{
|
||||
id::ChannelId,
|
||||
prelude::{GuildId, RoleId},
|
||||
},
|
||||
prelude::TypeMapKey,
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
io::{Result as IoResult, Write},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub(crate) struct GuildOptions {
|
||||
#[serde(skip_serializing)]
|
||||
pub(crate) guild_id: Option<GuildId>,
|
||||
pub(crate) mute_id: Option<RoleId>,
|
||||
pub(crate) mention_log_channel: Option<ChannelId>,
|
||||
pub(crate) roulette_options: RouletteOptions,
|
||||
}
|
||||
|
||||
impl GuildOptions {
|
||||
pub async fn save_async(&mut self, guild_id: u64) -> tokio::io::Result<()> {
|
||||
let path = PathBuf::from(format!("./data/guilds_options/{}.json", guild_id));
|
||||
|
||||
if !path.parent().unwrap().exists() {
|
||||
tokio::fs::create_dir_all(path.parent().unwrap()).await?;
|
||||
}
|
||||
|
||||
let mut file = tokio::fs::File::create(path).await?;
|
||||
let serialized = serde_json::to_string_pretty(self)?;
|
||||
file.write_all(&serialized.as_bytes()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save(&mut self, guild_id: u64) -> IoResult<()> {
|
||||
let path = PathBuf::from(format!("./data/guilds_options/{}.json", guild_id));
|
||||
|
||||
if !path.parent().unwrap().exists() {
|
||||
std::fs::create_dir_all(path.parent().unwrap())?;
|
||||
}
|
||||
|
||||
let mut file = std::fs::File::create(path)?;
|
||||
let serialized = serde_json::to_string_pretty(self)?;
|
||||
file.write_all(&serialized.as_bytes())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_guild_id(mut self, id: GuildId) -> Self {
|
||||
self.guild_id = Some(id);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn load_from_dir<P: AsRef<Path>>(path: P) -> IoResult<HashMap<GuildId, GuildOptions>> {
|
||||
let mut res = HashMap::new();
|
||||
for entry in fs::read_dir(path)?.filter_map(|e| e.ok()) {
|
||||
match serde_json::from_reader::<fs::File, GuildOptions>(fs::File::open(entry.path())?) {
|
||||
Ok(options) => {
|
||||
let id = GuildId::from(
|
||||
entry
|
||||
.file_name()
|
||||
.to_string_lossy()
|
||||
.split('.')
|
||||
.next()
|
||||
.unwrap()
|
||||
.parse::<u64>()
|
||||
.unwrap(),
|
||||
);
|
||||
res.insert(id, options.set_guild_id(id));
|
||||
}
|
||||
Err(e) => {
|
||||
error!("While parsing guild option {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub(crate) fn get_mute_role(&self) -> Option<RoleId> {
|
||||
self.mute_id
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GuildOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
roulette_options: RouletteOptions::default(),
|
||||
guild_id: None,
|
||||
mute_id: None,
|
||||
mention_log_channel: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GuildOptions {
|
||||
fn drop(&mut self) {
|
||||
if let Some(id) = self.guild_id {
|
||||
log::debug!("Saving {:?}", self);
|
||||
if let Err(e) = self.save(id.0) {
|
||||
log::error!("While saving {} : {}", id.0, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub(crate) struct RouletteOptions {
|
||||
pub(crate) kick_enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for RouletteOptions {
|
||||
fn default() -> Self {
|
||||
Self { kick_enabled: true }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct GuildOptionsKey;
|
||||
|
||||
impl TypeMapKey for GuildOptionsKey {
|
||||
type Value = HashMap<GuildId, GuildOptions>;
|
||||
}
|
|
@ -4,9 +4,6 @@ use serenity::{
|
|||
};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
mod guilds_options;
|
||||
pub(crate) use guilds_options::{GuildOptions, GuildOptionsKey};
|
||||
|
||||
pub(crate) struct ShardManagerContainer;
|
||||
|
||||
impl TypeMapKey for ShardManagerContainer {
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use crate::{
|
||||
commands::{
|
||||
admin::ADMIN_GROUP, general::GENERAL_GROUP, owner::OWNER_GROUP, roulette::ROULETTE_GROUP,
|
||||
settings::SETTINGS_GROUP,
|
||||
},
|
||||
data::{BulletsContainer, GuildOptions, GuildOptionsKey, ShardManagerContainer, Uptime},
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fs,
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
time::Instant,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use commands::interaction;
|
||||
use log::{debug, error, info};
|
||||
|
||||
use serenity::{
|
||||
framework::standard::{
|
||||
help_commands,
|
||||
|
@ -19,14 +18,17 @@ use serenity::{
|
|||
model::prelude::*,
|
||||
prelude::*,
|
||||
};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fs,
|
||||
io::Result as IoResult,
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
time::Instant,
|
||||
|
||||
use log::{debug, error, info};
|
||||
|
||||
use rusty_bot_database::{diesel::PgConnection, establish_connection, queries::RustyConnectionExt};
|
||||
|
||||
use crate::{
|
||||
commands::{
|
||||
admin::ADMIN_GROUP, general::GENERAL_GROUP, interaction, owner::OWNER_GROUP,
|
||||
roulette::ROULETTE_GROUP, settings::SETTINGS_GROUP,
|
||||
},
|
||||
data::{BulletsContainer, ShardManagerContainer, Uptime},
|
||||
};
|
||||
|
||||
#[cfg(feature = "music")]
|
||||
|
@ -47,9 +49,15 @@ const MINIMUM_MENTIONS: usize = 20;
|
|||
const PREFIX: &str = "?";
|
||||
pub(crate) static mut INVITE_URL: Option<String> = None;
|
||||
|
||||
pub(crate) struct DatabaseKey;
|
||||
|
||||
impl TypeMapKey for DatabaseKey {
|
||||
type Value = Arc<Mutex<PgConnection>>;
|
||||
}
|
||||
|
||||
// TODO CLAP FOR CLI
|
||||
#[tokio::main]
|
||||
async fn main() -> IoResult<()> {
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let now = Instant::now();
|
||||
|
||||
log4rs::init_file("log4rs.yaml", Default::default()).unwrap();
|
||||
|
@ -69,10 +77,12 @@ async fn main() -> IoResult<()> {
|
|||
fs::create_dir(dir)?;
|
||||
}
|
||||
|
||||
let data_dir = Path::new("data");
|
||||
if !data_dir.exists() {
|
||||
fs::create_dir(data_dir)?;
|
||||
}
|
||||
// let data_dir = Path::new("data");
|
||||
// if !data_dir.exists() {
|
||||
// fs::create_dir(data_dir)?;
|
||||
// }
|
||||
|
||||
let conn = Arc::new(Mutex::new(establish_connection(&conf.bot.database_url)?));
|
||||
|
||||
let http = Http::new_with_token(&token);
|
||||
|
||||
|
@ -143,17 +153,15 @@ async fn main() -> IoResult<()> {
|
|||
let mut data = client.data.write().await;
|
||||
data.insert::<BulletsContainer>(HashMap::default());
|
||||
data.insert::<ShardManagerContainer>(Arc::clone(&client.shard_manager));
|
||||
|
||||
/*#[cfg(feature = "music")]
|
||||
{
|
||||
data.insert::<VoiceManager>(std::sync::Arc::clone(&client.voice_manager.unwrap()));
|
||||
}*/
|
||||
|
||||
data.insert::<Uptime>(now);
|
||||
|
||||
data.insert::<GuildOptionsKey>({
|
||||
let options = GuildOptions::load_from_dir("./data/guilds_options").unwrap_or_default();
|
||||
log::debug!("Loaded {:?}", options);
|
||||
options
|
||||
})
|
||||
data.insert::<DatabaseKey>(conn);
|
||||
}
|
||||
|
||||
let current_runtime = tokio::runtime::Handle::current();
|
||||
|
@ -177,7 +185,7 @@ async fn main() -> IoResult<()> {
|
|||
|
||||
struct Messages {}
|
||||
|
||||
#[async_trait]
|
||||
#[async_trait::async_trait]
|
||||
impl EventHandler for Messages {
|
||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||
info!("{} connected to discord", ready.user.name);
|
||||
|
@ -239,10 +247,6 @@ async fn log_mentions(ctx: Context, new_message: &Message) -> CommandResult {
|
|||
|
||||
let data = ctx.data.read().await;
|
||||
|
||||
let guilds_options = data
|
||||
.get::<GuildOptionsKey>()
|
||||
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||
|
||||
let mute = if new_message.mention_everyone {
|
||||
true
|
||||
} else {
|
||||
|
@ -295,31 +299,35 @@ async fn log_mentions(ctx: Context, new_message: &Message) -> CommandResult {
|
|||
|
||||
if mute {
|
||||
if let Some(guild_id) = new_message.guild_id {
|
||||
if let Some(options) = guilds_options.get(&guild_id) {
|
||||
if let Some(role_id) = options.mute_id {
|
||||
let mut member = new_message.member(&ctx).await?;
|
||||
member.add_role(&ctx.http, role_id).await?;
|
||||
}
|
||||
let conn = data.get::<DatabaseKey>().expect("failed to get db");
|
||||
let conn = conn.lock().await;
|
||||
|
||||
if let Some(channel_id) = options.mention_log_channel {
|
||||
channel_id
|
||||
.send_message(&ctx.http, |m| {
|
||||
m.embed(|e| {
|
||||
e.title("New message with mentions")
|
||||
.fields(vec![
|
||||
("Sender", new_message.author.mention().to_string(), false),
|
||||
("Content", new_message.content.clone(), false),
|
||||
(
|
||||
"Channel",
|
||||
new_message.channel_id.mention().to_string(),
|
||||
false,
|
||||
),
|
||||
])
|
||||
.colour((247, 76, 0))
|
||||
})
|
||||
let role_id = conn.settings_fetch_mute_role(guild_id.0)?;
|
||||
let channel_id = conn.settings_fetch_log_channel(guild_id.0)?;
|
||||
|
||||
if let Some(role_id) = role_id {
|
||||
let mut member = new_message.member(&ctx).await?;
|
||||
member.add_role(&ctx.http, role_id).await?;
|
||||
}
|
||||
|
||||
if let Some(channel_id) = channel_id {
|
||||
ChannelId(channel_id)
|
||||
.send_message(&ctx.http, |m| {
|
||||
m.embed(|e| {
|
||||
e.title("New message with mentions")
|
||||
.fields(vec![
|
||||
("Sender", new_message.author.mention().to_string(), false),
|
||||
("Content", new_message.content.clone(), false),
|
||||
(
|
||||
"Channel",
|
||||
new_message.channel_id.mention().to_string(),
|
||||
false,
|
||||
),
|
||||
])
|
||||
.colour((247, 76, 0))
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue