Compare commits
No commits in common. "main" and "#17-automate-onboarding-mk-ii" have entirely different histories.
main
...
#17-automa
23 changed files with 344 additions and 917 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -4166,7 +4166,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "wolves_oxidised"
|
||||
version = "0.1.0"
|
||||
source = "git+https://forgejo.skynet.ie/Skynet/wolves-oxidised.git#265c8c81d1eb870a6149da5ce72556d44f57937f"
|
||||
source = "git+https://forgejo.skynet.ie/Skynet/wolves-oxidised.git#74f00e3dcfd52744583b0ded08efb8bb27fdcec8"
|
||||
dependencies = [
|
||||
"reqwest 0.12.9",
|
||||
"serde",
|
||||
|
|
|
@ -11,9 +11,6 @@ name = "update_data"
|
|||
[[bin]]
|
||||
name = "update_users"
|
||||
|
||||
[[bin]]
|
||||
name = "update_committee"
|
||||
|
||||
[[bin]]
|
||||
name = "update_minecraft"
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
CREATE TABLE IF NOT EXISTS committee_roles (
|
||||
id_wolves integer PRIMARY KEY,
|
||||
id_role integer DEFAULT 1,
|
||||
id_channel integer DEFAULT 1,
|
||||
-- not strictly required but for readability and debugging
|
||||
name_role text NOT NULL DEFAULT '',
|
||||
name_channel text NOT NULL DEFAULT '',
|
||||
count integer DEFAULT 0
|
||||
);
|
|
@ -1,6 +0,0 @@
|
|||
-- No need for this col since it is goign to be in "committees" anyways
|
||||
ALTER TABLE servers DROP COLUMN server_name;
|
||||
|
||||
-- we do care about teh ID of the club/soc though
|
||||
ALTER TABLE servers ADD COLUMN wolves_id integer DEFAULT 0;
|
||||
|
|
@ -7,7 +7,7 @@ For example is a user links on the CompSoc Discord then they will also get their
|
|||
|
||||
## Setup - Committee
|
||||
You need admin access to run any of the commands in this section.
|
||||
Either the server owner or a user with the ``Manage Server`` permission.
|
||||
Either the server owner or a user with the ``Administrator`` permission.
|
||||
|
||||
### Get the API Key
|
||||
The ``api_key`` is used by the Bot in order to request information, it will be used later in the process.
|
||||
|
@ -38,9 +38,9 @@ The reason for both roles is ye have one for active members while the second is
|
|||
### Setup Bot
|
||||
This is where the bot is configured.
|
||||
You will need the ``api_key`` from the start of the process.
|
||||
You (personally) will need a role with ``Manage Server`` permission to be able to do this.
|
||||
You (personally) will need a role with ``Administrator`` permission to be able to do this.
|
||||
|
||||
1. Use the command ``/committee add`` and a list of options will pop up.
|
||||
1. Use the command ``/add`` and a list of options will pop up.
|
||||
2. ``api_key`` is the key you got from Keith earlier.
|
||||
3. ``role_current`` is the ``member-current`` that you created earlier.
|
||||
4. ``role_past`` (optional) is the role for all current and past members.
|
||||
|
|
|
@ -8,13 +8,13 @@ This is to link your Discord account with your UL Wolves account.
|
|||
**You will only need to do this once**.
|
||||
|
||||
### Setup
|
||||
1. In a Discord server with the Skynet Bot enter ``/wolves link YOUR_WOLVES_CONTACT_EMAIL``
|
||||
1. In a Discord server with the Skynet Bot enter ``/link_wolves YOUR_WOLVES_CONTACT_EMAIL``
|
||||
<img src="../media/setup_user_01.png" alt="link process start" width="50%" height="50%">
|
||||
* Your ``YOUR_WOLVES_CONTACT_EMAIL`` is the email in the Contact Email here: <https://ulwolves.ie/memberships/profile>
|
||||
* This is most likely your student mail
|
||||
2. An email will be sent to you with a verification code.
|
||||
<img src="../media/setup_user_02.png" alt="signup email" width="50%" height="50%">
|
||||
3. Verify the code using ``/wolves verify CODE_FROM_EMAIL`` in Discord.
|
||||
3. Verify the code using ``/verify CODE_FROM_EMAIL`` in Discord.
|
||||
<img src="../media/setup_user_03.png" alt="verify in discord" width="50%" height="50%">
|
||||
4. Once complete your Wolves and Discord accounts will be linked.
|
||||
|
||||
|
@ -23,4 +23,4 @@ You will get member roles on any Discord that is using the bot that you are a me
|
|||
### Minecraft
|
||||
You can link your Minecraft username to grant you access to any Minecraft server run by UL Computer Society.
|
||||
|
||||
``/wolves link_minecraft MINECRAFT_USERNAME``
|
||||
``/link_minecraft MINECRAFT_USERNAME``
|
||||
|
|
13
flake.nix
13
flake.nix
|
@ -20,7 +20,6 @@
|
|||
}:
|
||||
utils.lib.eachDefaultSystem (
|
||||
system: let
|
||||
overrides = (builtins.fromTOML (builtins.readFile ./rust-toolchain.toml));
|
||||
pkgs = (import nixpkgs) {inherit system;};
|
||||
naersk' = pkgs.callPackage naersk {};
|
||||
package_name = "skynet_discord_bot";
|
||||
|
@ -63,15 +62,7 @@
|
|||
|
||||
# `nix develop`
|
||||
devShell = pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs; [rustup rustPlatform.bindgenHook pkg-config openssl];
|
||||
# libraries here
|
||||
buildInputs = [ ];
|
||||
RUSTC_VERSION = overrides.toolchain.channel;
|
||||
# https://github.com/rust-lang/rust-bindgen#environment-variables
|
||||
shellHook = ''
|
||||
export PATH="''${CARGO_HOME:-~/.cargo}/bin":"$PATH"
|
||||
export PATH="''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-${pkgs.stdenv.hostPlatform.rust.rustcTarget}/bin":"$PATH"
|
||||
'';
|
||||
nativeBuildInputs = with pkgs; [rustc cargo pkg-config openssl rustfmt];
|
||||
};
|
||||
|
||||
nixosModule = {
|
||||
|
@ -131,8 +122,6 @@
|
|||
"update_data" = "*:0,10,20,30,40,50";
|
||||
# groups are updated every hour, offset from teh ldap
|
||||
"update_users" = "*:05:00";
|
||||
# Committee server has its own timer
|
||||
"update_committee" = "*:15:00";
|
||||
# minecraft stuff is updated at 5am
|
||||
"update_minecraft" = "5:10:00";
|
||||
};
|
||||
|
|
BIN
media/setup_user_01.png
(Stored with Git LFS)
BIN
media/setup_user_01.png
(Stored with Git LFS)
Binary file not shown.
BIN
media/setup_user_03.png
(Stored with Git LFS)
BIN
media/setup_user_03.png
(Stored with Git LFS)
Binary file not shown.
|
@ -1,54 +0,0 @@
|
|||
use serenity::{
|
||||
async_trait,
|
||||
client::{Context, EventHandler},
|
||||
model::gateway::{GatewayIntents, Ready},
|
||||
Client,
|
||||
};
|
||||
use skynet_discord_bot::common::database::{db_init, DataBase};
|
||||
use skynet_discord_bot::common::set_roles::committee;
|
||||
use skynet_discord_bot::{get_config, Config};
|
||||
use std::{process, sync::Arc};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let config = get_config();
|
||||
let db = match db_init(&config).await {
|
||||
Ok(x) => x,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
// Intents are a bitflag, bitwise operations can be used to dictate which intents to use
|
||||
let intents = GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT | GatewayIntents::GUILD_MEMBERS;
|
||||
// Build our client.
|
||||
let mut client = Client::builder(&config.discord_token, intents)
|
||||
.event_handler(Handler {})
|
||||
.await
|
||||
.expect("Error creating client");
|
||||
|
||||
{
|
||||
let mut data = client.data.write().await;
|
||||
|
||||
data.insert::<Config>(Arc::new(RwLock::new(config)));
|
||||
data.insert::<DataBase>(Arc::new(RwLock::new(db)));
|
||||
}
|
||||
|
||||
if let Err(why) = client.start().await {
|
||||
println!("Client error: {:?}", why);
|
||||
}
|
||||
}
|
||||
|
||||
struct Handler;
|
||||
#[async_trait]
|
||||
impl EventHandler for Handler {
|
||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||
let ctx = Arc::new(ctx);
|
||||
println!("{} is connected!", ready.user.name);
|
||||
|
||||
// u[date committee server
|
||||
committee::check_committee(Arc::clone(&ctx)).await;
|
||||
|
||||
// finish up
|
||||
process::exit(0);
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ use serenity::{
|
|||
Client,
|
||||
};
|
||||
use skynet_discord_bot::common::database::{db_init, get_server_config_bulk, DataBase};
|
||||
use skynet_discord_bot::common::set_roles::normal;
|
||||
use skynet_discord_bot::common::set_roles::{committee, normal};
|
||||
use skynet_discord_bot::{get_config, Config};
|
||||
use std::{process, sync::Arc};
|
||||
use tokio::sync::RwLock;
|
||||
|
@ -48,6 +48,9 @@ impl EventHandler for Handler {
|
|||
// this goes into each server and sets roles for each wolves member
|
||||
check_bulk(Arc::clone(&ctx)).await;
|
||||
|
||||
// u[date committee server
|
||||
committee::check_committee(Arc::clone(&ctx)).await;
|
||||
|
||||
// finish up
|
||||
process::exit(0);
|
||||
}
|
||||
|
|
|
@ -1,53 +1,53 @@
|
|||
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteraction};
|
||||
use serenity::client::Context;
|
||||
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteraction, CommandOptionType, CreateCommandOption};
|
||||
use serenity::{builder::CreateCommand, client::Context};
|
||||
use skynet_discord_bot::common::database::{get_server_config, DataBase, Servers};
|
||||
use skynet_discord_bot::common::set_roles::normal::update_server;
|
||||
use skynet_discord_bot::common::wolves::cns::get_wolves;
|
||||
use skynet_discord_bot::is_admin;
|
||||
use sqlx::{Error, Pool, Sqlite};
|
||||
|
||||
pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
||||
let sub_options = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::SubCommand(options),
|
||||
// check if user has high enough permisssions
|
||||
if let Some(msg) = is_admin(command, ctx).await {
|
||||
return msg;
|
||||
}
|
||||
|
||||
let wolves_api = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::String(key),
|
||||
..
|
||||
}) = command.data.options.first()
|
||||
{
|
||||
options
|
||||
} else {
|
||||
return "Please provide sub options".to_string();
|
||||
};
|
||||
|
||||
let wolves_api = if let Some(x) = sub_options.first() {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::String(key) => key.to_string(),
|
||||
_ => return "Please provide a wolves API key".to_string(),
|
||||
}
|
||||
key.to_string()
|
||||
} else {
|
||||
return "Please provide a wolves API key".to_string();
|
||||
};
|
||||
|
||||
let role_current = if let Some(x) = sub_options.get(1) {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::Role(role) => role.to_owned(),
|
||||
_ => return "Please provide a valid role for ``Role Current``".to_string(),
|
||||
}
|
||||
let role_current = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::Role(role),
|
||||
..
|
||||
}) = command.data.options.get(1)
|
||||
{
|
||||
role.to_owned()
|
||||
} else {
|
||||
return "Please provide a valid role for ``Role Current``".to_string();
|
||||
};
|
||||
|
||||
let role_past = if let Some(x) = sub_options.get(5) {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::Role(role) => Some(role.to_owned()),
|
||||
_ => None,
|
||||
}
|
||||
let role_past = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::Role(role),
|
||||
..
|
||||
}) = command.data.options.get(5)
|
||||
{
|
||||
Some(role.to_owned())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let bot_channel_id = if let Some(x) = sub_options.get(2) {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::Channel(channel) => channel.to_owned(),
|
||||
_ => return "Please provide a valid channel for ``Bot Channel``".to_string(),
|
||||
}
|
||||
let bot_channel_id = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::Channel(channel),
|
||||
..
|
||||
}) = command.data.options.get(2)
|
||||
{
|
||||
channel.to_owned()
|
||||
} else {
|
||||
return "Please provide a valid channel for ``Bot Channel``".to_string();
|
||||
};
|
||||
|
@ -61,12 +61,12 @@ pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
|||
let server_data = Servers {
|
||||
server: command.guild_id.unwrap_or_default(),
|
||||
wolves_api,
|
||||
wolves_id: 0,
|
||||
role_past,
|
||||
role_current,
|
||||
member_past: 0,
|
||||
member_current: 0,
|
||||
bot_channel_id,
|
||||
server_name: "".to_string(),
|
||||
};
|
||||
|
||||
match add_server(&db, ctx, &server_data).await {
|
||||
|
@ -80,6 +80,15 @@ pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
|||
"Added/Updated server info".to_string()
|
||||
}
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("add")
|
||||
.description("Enable the bot for this discord")
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::String, "api_key", "UL Wolves API Key").required(true))
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::Role, "role_current", "Role for Current members").required(true))
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::Channel, "bot_channel", "Safe space for folks to use the bot commands.").required(true))
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::Role, "role_past", "Role for Past members").required(false))
|
||||
}
|
||||
|
||||
async fn add_server(db: &Pool<Sqlite>, ctx: &Context, server: &Servers) -> Result<Option<Servers>, Error> {
|
||||
let existing = get_server_config(db, &server.server).await;
|
||||
let role_past = server.role_past.map(|x| x.get() as i64);
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
use serenity::all::{CommandOptionType, CreateCommand, CreateCommandOption};
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("committee")
|
||||
.description("Commands related to what committees can do")
|
||||
.default_member_permissions(serenity::model::Permissions::MANAGE_GUILD)
|
||||
.add_option(
|
||||
CreateCommandOption::new(CommandOptionType::SubCommand, "add", "Enable the bot for this discord")
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::String, "api_key", "UL Wolves API Key").required(true))
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::Role, "role_current", "Role for Current members").required(true))
|
||||
.add_sub_option(
|
||||
CreateCommandOption::new(CommandOptionType::Channel, "bot_channel", "Safe space for folks to use the bot commands.").required(true),
|
||||
)
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::Role, "role_past", "Role for Past members").required(false)),
|
||||
)
|
||||
.add_option(
|
||||
CreateCommandOption::new(CommandOptionType::SubCommand, "roles_adder", "Combine roles together to an new one")
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::Role, "role_a", "A role you want to add to Role B").required(true))
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::Role, "role_b", "A role you want to add to Role A").required(true))
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::Role, "role_c", "Sum of A and B").required(true))
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::Boolean, "delete", "Delete this entry.").required(false)),
|
||||
)
|
||||
}
|
|
@ -1,256 +0,0 @@
|
|||
pub mod committee {
|
||||
|
||||
// get the list of all the current clubs/socs members
|
||||
|
||||
use serenity::all::{
|
||||
CommandDataOption, CommandDataOptionValue, CommandInteraction, CommandOptionType, Context, CreateCommand, CreateCommandOption,
|
||||
};
|
||||
use skynet_discord_bot::common::database::DataBase;
|
||||
use skynet_discord_bot::common::set_roles::committee::db_roles_get;
|
||||
|
||||
pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
||||
let sub_options = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::SubCommand(key),
|
||||
..
|
||||
}) = command.data.options.first()
|
||||
{
|
||||
key
|
||||
} else {
|
||||
return "Please provide a wolves API key".to_string();
|
||||
};
|
||||
|
||||
let all = if let Some(x) = sub_options.first() {
|
||||
match x.value {
|
||||
CommandDataOptionValue::Boolean(y) => y,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let db_lock = {
|
||||
let data_read = ctx.data.read().await;
|
||||
data_read.get::<DataBase>().expect("Expected Databse in TypeMap.").clone()
|
||||
};
|
||||
let db = db_lock.read().await;
|
||||
|
||||
let mut cs = vec![];
|
||||
// pull it from a DB
|
||||
for committee in db_roles_get(&db).await {
|
||||
if !all && committee.count == 0 {
|
||||
continue;
|
||||
}
|
||||
cs.push((committee.count, committee.name_role.to_owned()));
|
||||
}
|
||||
|
||||
cs.sort_by_key(|(count, _)| *count);
|
||||
cs.reverse();
|
||||
|
||||
// msg can be a max 2000 chars long
|
||||
let mut limit = 2000 - 3;
|
||||
|
||||
let mut response = vec!["```".to_string()];
|
||||
for (count, name) in cs {
|
||||
let leading = if count < 10 { " " } else { "" };
|
||||
|
||||
let line = format!("{}{} {}", leading, count, name);
|
||||
|
||||
let length = line.len() + 1;
|
||||
|
||||
if length < (limit + 3) {
|
||||
response.push(line);
|
||||
limit -= length;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
response.push("```".to_string());
|
||||
|
||||
response.join("\n")
|
||||
}
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("count")
|
||||
.description("Count Committee Members")
|
||||
// All Committee members are able to add reactions to posts
|
||||
.default_member_permissions(serenity::model::Permissions::ADD_REACTIONS)
|
||||
.add_option(
|
||||
CreateCommandOption::new(CommandOptionType::SubCommand, "committee", "List out the Committee Roles Numbers")
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::Boolean, "all", "List out all the Committee Roles Numbers").required(false)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod servers {
|
||||
// get the list of all the current clubs/socs
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::all::{CommandInteraction, CommandOptionType, Context, CreateCommand, CreateCommandOption};
|
||||
use skynet_discord_bot::common::database::{get_server_config_bulk, DataBase};
|
||||
use skynet_discord_bot::common::set_roles::committee::get_committees;
|
||||
use skynet_discord_bot::get_now_iso;
|
||||
use sqlx::{Pool, Sqlite};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub async fn run(_command: &CommandInteraction, ctx: &Context) -> String {
|
||||
let db_lock = {
|
||||
let data_read = ctx.data.read().await;
|
||||
data_read.get::<DataBase>().expect("Expected Databse in TypeMap.").clone()
|
||||
};
|
||||
let db = db_lock.read().await;
|
||||
|
||||
let mut committees = HashMap::new();
|
||||
for committee in get_committees(&db).await {
|
||||
committees.insert(committee.id, committee.to_owned());
|
||||
}
|
||||
|
||||
let mut cs = vec![];
|
||||
// pull it from a DB
|
||||
for server_config in get_server_config_bulk(&db).await {
|
||||
if let Some(x) = committees.get(&server_config.wolves_id) {
|
||||
cs.push((server_config.member_current, server_config.member_past, x.name_full.to_owned()));
|
||||
}
|
||||
}
|
||||
|
||||
// get all members
|
||||
let (wolves_current, wolves_past, total) = get_wolves_total(&db).await;
|
||||
cs.push((total, total, String::from("Skynet Network")));
|
||||
cs.push((wolves_current, wolves_past, String::from("Clubs/Socs Servers")));
|
||||
|
||||
// treat teh committee server as its own thing
|
||||
let committee_current = get_wolves_committee(&db).await;
|
||||
cs.push((committee_current, committee_current, String::from("Committee Server")));
|
||||
|
||||
cs.sort_by_key(|(current, _, _)| *current);
|
||||
cs.reverse();
|
||||
|
||||
// msg can be a max 2000 chars long
|
||||
let mut limit = 2000 - 3;
|
||||
|
||||
let mut response = vec!["```".to_string()];
|
||||
for (current, past, name) in cs {
|
||||
let current_leading = if current < 10 {
|
||||
" "
|
||||
} else if current < 100 {
|
||||
" "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let past_leading = if past < 10 {
|
||||
" "
|
||||
} else if past < 100 {
|
||||
" "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
let line = format!("{}{} {}{} {}", current_leading, current, past_leading, past, name);
|
||||
|
||||
let length = line.len() + 1;
|
||||
|
||||
// +3 is to account for the closing fense
|
||||
if length < (limit + 3) {
|
||||
response.push(line);
|
||||
limit -= length;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
response.push("```".to_string());
|
||||
|
||||
response.join("\n")
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, sqlx::FromRow)]
|
||||
pub struct Count {
|
||||
pub count: i64,
|
||||
}
|
||||
|
||||
async fn get_wolves_total(db: &Pool<Sqlite>) -> (i64, i64, i64) {
|
||||
let current = match sqlx::query_as::<_, Count>(
|
||||
r#"
|
||||
SELECT COUNT(DISTINCT id_wolves) as count
|
||||
FROM server_members
|
||||
JOIN wolves USING (id_wolves)
|
||||
WHERE (
|
||||
wolves.discord IS NOT NULL
|
||||
AND server_members.expiry > ?
|
||||
)
|
||||
"#,
|
||||
)
|
||||
.bind(get_now_iso(true))
|
||||
.fetch_one(db)
|
||||
.await
|
||||
{
|
||||
Ok(res) => res.count,
|
||||
Err(e) => {
|
||||
dbg!(e);
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
let cns = match sqlx::query_as::<_, Count>(
|
||||
r#"
|
||||
SELECT COUNT(DISTINCT id_wolves) as count
|
||||
FROM server_members
|
||||
JOIN wolves USING (id_wolves)
|
||||
WHERE wolves.discord IS NOT NULL
|
||||
"#,
|
||||
)
|
||||
.bind(get_now_iso(true))
|
||||
.fetch_one(db)
|
||||
.await
|
||||
{
|
||||
Ok(res) => res.count,
|
||||
Err(e) => {
|
||||
dbg!(e);
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
let total = match sqlx::query_as::<_, Count>(
|
||||
r#"
|
||||
SELECT COUNT(DISTINCT id_wolves) as count
|
||||
FROM wolves
|
||||
WHERE discord IS NOT NULL
|
||||
"#,
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await
|
||||
{
|
||||
Ok(res) => res.count,
|
||||
Err(e) => {
|
||||
dbg!(e);
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
(current, cns, total)
|
||||
}
|
||||
|
||||
async fn get_wolves_committee(db: &Pool<Sqlite>) -> i64 {
|
||||
// expiry
|
||||
match sqlx::query_as::<_, Count>(
|
||||
"
|
||||
SELECT count
|
||||
FROM committee_roles
|
||||
WHERE id_wolves = '0'
|
||||
",
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await
|
||||
{
|
||||
Ok(res) => res.count,
|
||||
Err(e) => {
|
||||
dbg!(e);
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("count")
|
||||
.description("Count the servers")
|
||||
.default_member_permissions(serenity::model::Permissions::MANAGE_GUILD)
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::SubCommand, "servers", "List out all servers using the skynet bot"))
|
||||
}
|
||||
}
|
|
@ -4,8 +4,6 @@ use lettre::{
|
|||
Message, SmtpTransport, Transport,
|
||||
};
|
||||
use maud::html;
|
||||
use serenity::all::CommandOptionType;
|
||||
use serenity::builder::CreateCommandOption;
|
||||
use serenity::{builder::CreateCommand, client::Context, model::id::UserId};
|
||||
use skynet_discord_bot::common::database::{DataBase, Wolves, WolvesVerify};
|
||||
use skynet_discord_bot::{get_now_iso, random_string, Config};
|
||||
|
@ -13,7 +11,8 @@ use sqlx::{Pool, Sqlite};
|
|||
|
||||
pub mod link {
|
||||
use super::*;
|
||||
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteraction};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteraction, CommandOptionType, CreateCommand, CreateCommandOption};
|
||||
|
||||
pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
||||
let db_lock = {
|
||||
|
@ -38,23 +37,14 @@ pub mod link {
|
|||
return "Linking already in process, please check email.".to_string();
|
||||
}
|
||||
|
||||
let sub_options = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::SubCommand(options),
|
||||
let email = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::String(email),
|
||||
..
|
||||
}) = command.data.options.first()
|
||||
{
|
||||
options
|
||||
email.trim()
|
||||
} else {
|
||||
return "Please provide sub options".to_string();
|
||||
};
|
||||
|
||||
let email = if let Some(x) = sub_options.first() {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::String(email) => email.trim(),
|
||||
_ => return "Please provide a valid email".to_string(),
|
||||
}
|
||||
} else {
|
||||
return "Please provide a valid email".to_string();
|
||||
return "Please provide a valid user".to_string();
|
||||
};
|
||||
|
||||
// check if email exists
|
||||
|
@ -98,7 +88,7 @@ pub mod link {
|
|||
|
||||
// generate a auth key
|
||||
let auth = random_string(20);
|
||||
match send_mail(&config, &details.email, &auth, &command.user.name) {
|
||||
match send_mail(&config, &details, &auth, &command.user.name) {
|
||||
Ok(_) => match save_to_db(&db, &details, &auth, &command.user.id).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
|
@ -113,6 +103,12 @@ pub mod link {
|
|||
format!("Verification email sent to {}, it may take up to 15 min for it to arrive. If it takes longer check the Junk folder.", email)
|
||||
}
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("link_wolves")
|
||||
.description("Set Wolves Email")
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::String, "email", "UL Wolves Email").required(true))
|
||||
}
|
||||
|
||||
pub async fn get_server_member_discord(db: &Pool<Sqlite>, user: &UserId) -> Option<Wolves> {
|
||||
sqlx::query_as::<_, Wolves>(
|
||||
r#"
|
||||
|
@ -141,35 +137,33 @@ pub mod link {
|
|||
.ok()
|
||||
}
|
||||
|
||||
fn send_mail(config: &Config, mail: &str, auth: &str, user: &str) -> Result<smtp::response::Response, smtp::Error> {
|
||||
let discord = "https://computer.discord.skynet.ie";
|
||||
fn send_mail(config: &Config, email: &Wolves, auth: &str, user: &str) -> Result<smtp::response::Response, smtp::Error> {
|
||||
let mail = &email.email;
|
||||
let discord = "https://discord.skynet.ie";
|
||||
let sender = format!("UL Computer Society <{}>", &config.mail_user);
|
||||
|
||||
// Create the html we want to send.
|
||||
let html = html! {
|
||||
head {
|
||||
title { "UL Wolves Discord Linker" }
|
||||
title { "Hello from Skynet!" }
|
||||
style type="text/css" {
|
||||
"h2, h4 { font-family: Arial, Helvetica, sans-serif; }"
|
||||
}
|
||||
}
|
||||
div {
|
||||
h2 { "UL Wolves Discord Linker" }
|
||||
|
||||
h3 { "Link your UL Wolves Account to Discord" }
|
||||
h2 { "Hello from Skynet!" }
|
||||
// Substitute in the name of our recipient.
|
||||
p { "Hi " (user) "," }
|
||||
p {
|
||||
"Please paste this line into Discord (and press enter) to verify your discord account:"
|
||||
br;
|
||||
pre { "/wolves verify code: " (auth)}
|
||||
"Please use " pre { "/verify code: " (auth)} " to verify your discord account."
|
||||
}
|
||||
hr;
|
||||
h3 { "Help & Support" }
|
||||
p {
|
||||
"If you have issues please refer to our Computer Society Discord Server:"
|
||||
"If you have issues please refer to our Discord server:"
|
||||
br;
|
||||
a href=(discord) { (discord) }
|
||||
}
|
||||
p {
|
||||
"Skynet Team"
|
||||
br;
|
||||
"UL Computer Society"
|
||||
}
|
||||
|
@ -178,23 +172,15 @@ pub mod link {
|
|||
|
||||
let body_text = format!(
|
||||
r#"
|
||||
UL Wolves Discord Linker
|
||||
Link your UL Wolves Account to Discord
|
||||
|
||||
Link your Account
|
||||
Hi {user}
|
||||
|
||||
Hi {user},
|
||||
|
||||
Please paste this line into Discord (and press enter) to verify your Discord account:
|
||||
/wolves verify code: {auth}
|
||||
Please use "/verify code: {auth}" to verify your discord account.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
Help & Support
|
||||
|
||||
If you have issues please refer to our Computer Society Discord Server:
|
||||
{discord}
|
||||
UL Computer Society
|
||||
If you have issues please refer to our Discord server:
|
||||
{discord}
|
||||
|
||||
Skynet Team
|
||||
UL Computer Society
|
||||
"#
|
||||
);
|
||||
|
||||
|
@ -202,7 +188,7 @@ pub mod link {
|
|||
let email = Message::builder()
|
||||
.from(sender.parse().unwrap())
|
||||
.to(mail.parse().unwrap())
|
||||
.subject("Skynet: Link Discord to Wolves.")
|
||||
.subject("Skynet-Discord: Link Wolves.")
|
||||
.multipart(
|
||||
// This is composed of two parts.
|
||||
// also helps not trip spam settings (uneven number of url's
|
||||
|
@ -264,6 +250,19 @@ pub mod link {
|
|||
.await
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(untagged)]
|
||||
pub enum WolvesResultUserResult {
|
||||
B(bool),
|
||||
S(String),
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
struct WolvesResultUser {
|
||||
success: i64,
|
||||
result: WolvesResultUserResult,
|
||||
}
|
||||
|
||||
async fn save_to_db_user(db: &Pool<Sqlite>, id_wolves: i64, email: &str) -> Result<Option<Wolves>, sqlx::Error> {
|
||||
sqlx::query_as::<_, Wolves>(
|
||||
"
|
||||
|
@ -281,18 +280,17 @@ pub mod link {
|
|||
|
||||
pub mod verify {
|
||||
use super::*;
|
||||
use crate::commands::wolves::link::{db_pending_clear_expired, get_server_member_discord, get_verify_from_db};
|
||||
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteraction, GuildId, RoleId};
|
||||
use crate::commands::link_email::link::{db_pending_clear_expired, get_verify_from_db};
|
||||
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteraction, CommandOptionType, CreateCommandOption};
|
||||
use serenity::model::user::User;
|
||||
use skynet_discord_bot::common::database::get_server_config;
|
||||
use skynet_discord_bot::common::database::{ServerMembersWolves, Servers};
|
||||
use skynet_discord_bot::common::wolves::committees::Committees;
|
||||
use sqlx::Error;
|
||||
|
||||
pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
||||
let db_lock = {
|
||||
let data_read = ctx.data.read().await;
|
||||
data_read.get::<DataBase>().expect("Expected Database in TypeMap.").clone()
|
||||
data_read.get::<DataBase>().expect("Expected Databse in TypeMap.").clone()
|
||||
};
|
||||
let db = db_lock.read().await;
|
||||
|
||||
|
@ -300,31 +298,22 @@ pub mod verify {
|
|||
let details = if let Some(x) = get_verify_from_db(&db, &command.user.id).await {
|
||||
x
|
||||
} else {
|
||||
return "Please use ''/wolves link'' first".to_string();
|
||||
return "Please use /link_wolves first".to_string();
|
||||
};
|
||||
|
||||
let sub_options = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::SubCommand(options),
|
||||
let code = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::String(code),
|
||||
..
|
||||
}) = command.data.options.first()
|
||||
{
|
||||
options
|
||||
} else {
|
||||
return "Please provide sub options".to_string();
|
||||
};
|
||||
|
||||
let code = if let Some(x) = sub_options.first() {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::String(y) => y.trim(),
|
||||
_ => return "Please provide a verification code".to_string(),
|
||||
}
|
||||
code
|
||||
} else {
|
||||
return "Please provide a verification code".to_string();
|
||||
};
|
||||
|
||||
db_pending_clear_expired(&db).await;
|
||||
|
||||
if details.auth_code != code {
|
||||
if &details.auth_code != code {
|
||||
return "Invalid verification code".to_string();
|
||||
}
|
||||
|
||||
|
@ -334,10 +323,6 @@ pub mod verify {
|
|||
Ok(_) => {
|
||||
// get teh right roles for the user
|
||||
set_server_roles(&db, &command.user, ctx).await;
|
||||
|
||||
// check if they are a committee member, and on that server
|
||||
set_server_roles_committee(&db, &command.user, ctx).await;
|
||||
|
||||
"Discord username linked to Wolves".to_string()
|
||||
}
|
||||
Err(e) => {
|
||||
|
@ -352,6 +337,12 @@ pub mod verify {
|
|||
"Failed to verify".to_string()
|
||||
}
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("verify")
|
||||
.description("Verify Wolves Email")
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::String, "code", "Code from verification email").required(true))
|
||||
}
|
||||
|
||||
async fn db_pending_clear_successful(pool: &Pool<Sqlite>, user: &UserId) -> Result<Option<WolvesVerify>, Error> {
|
||||
sqlx::query_as::<_, WolvesVerify>(
|
||||
r#"
|
||||
|
@ -411,38 +402,6 @@ pub mod verify {
|
|||
}
|
||||
}
|
||||
|
||||
async fn get_committees_id(db: &Pool<Sqlite>, wolves_id: i64) -> Vec<Committees> {
|
||||
sqlx::query_as::<_, Committees>(
|
||||
r#"
|
||||
SELECT *
|
||||
FROM committees
|
||||
WHERE committee LIKE ?1
|
||||
"#,
|
||||
)
|
||||
.bind(format!("%{}%", wolves_id))
|
||||
.fetch_all(db)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
dbg!(e);
|
||||
vec![]
|
||||
})
|
||||
}
|
||||
|
||||
async fn set_server_roles_committee(db: &Pool<Sqlite>, discord: &User, ctx: &Context) {
|
||||
if let Some(x) = get_server_member_discord(db, &discord.id).await {
|
||||
// if they are a member of one or more committees, and in teh committee server then give the teh general committee role
|
||||
// they will get teh more specific vanity role later
|
||||
if !get_committees_id(db, x.id_wolves).await.is_empty() {
|
||||
let server = GuildId::new(1220150752656363520);
|
||||
let committee_member = RoleId::new(1226602779968274573);
|
||||
|
||||
if let Ok(member) = server.member(ctx, &discord.id).await {
|
||||
member.add_roles(&ctx, &[committee_member]).await.unwrap_or_default();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_servers(db: &Pool<Sqlite>, discord: &UserId) -> Result<Vec<ServerMembersWolves>, Error> {
|
||||
sqlx::query_as::<_, ServerMembersWolves>(
|
||||
"
|
||||
|
@ -457,63 +416,3 @@ pub mod verify {
|
|||
.await
|
||||
}
|
||||
}
|
||||
|
||||
pub mod unlink {
|
||||
use serenity::all::{CommandInteraction, Context, UserId};
|
||||
use skynet_discord_bot::common::database::{DataBase, Wolves};
|
||||
use sqlx::{Pool, Sqlite};
|
||||
|
||||
pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
||||
let db_lock = {
|
||||
let data_read = ctx.data.read().await;
|
||||
data_read.get::<DataBase>().expect("Expected Databse in TypeMap.").clone()
|
||||
};
|
||||
let db = db_lock.read().await;
|
||||
|
||||
// dosent matter if there is one or not, it will be removed regardless
|
||||
delete_link(&db, &command.user.id).await;
|
||||
|
||||
"Discord link removed".to_string()
|
||||
}
|
||||
|
||||
async fn delete_link(db: &Pool<Sqlite>, user: &UserId) {
|
||||
match sqlx::query_as::<_, Wolves>(
|
||||
"
|
||||
UPDATE wolves
|
||||
SET discord = NULL
|
||||
WHERE discord = ?1;
|
||||
",
|
||||
)
|
||||
.bind(user.get() as i64)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
dbg!(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("wolves")
|
||||
.description("Commands related to UL Wolves")
|
||||
// link
|
||||
.add_option(
|
||||
CreateCommandOption::new(CommandOptionType::SubCommand, "link", "Link your Wolves account to your Discord")
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::String, "email", "UL Wolves Email").required(true)),
|
||||
)
|
||||
// verify
|
||||
.add_option(
|
||||
CreateCommandOption::new(CommandOptionType::SubCommand, "verify", "Verify Wolves Email")
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::String, "code", "Code from verification email").required(true)),
|
||||
)
|
||||
// unlink
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::SubCommand, "unlink", "Unlink your Wolves account from your Discord"))
|
||||
.add_option(
|
||||
CreateCommandOption::new(CommandOptionType::SubCommand, "link_minecraft", "Link your minecraft account")
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::String, "minecraft_username", "Your Minecraft username").required(true))
|
||||
.add_sub_option(CreateCommandOption::new(CommandOptionType::Boolean, "bedrock_account", "Is this a Bedrock account?").required(false)),
|
||||
)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use serenity::client::Context;
|
||||
use serenity::{builder::CreateCommand, client::Context};
|
||||
|
||||
use skynet_discord_bot::common::database::DataBase;
|
||||
use sqlx::{Pool, Sqlite};
|
||||
|
@ -7,15 +7,22 @@ pub(crate) mod user {
|
|||
use super::*;
|
||||
pub(crate) mod add {
|
||||
use super::*;
|
||||
use crate::commands::wolves::link::get_server_member_discord;
|
||||
use crate::commands::link_email::link::get_server_member_discord;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteraction};
|
||||
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteraction, CommandOptionType, CreateCommandOption};
|
||||
use serenity::model::id::UserId;
|
||||
use skynet_discord_bot::common::database::Wolves;
|
||||
use skynet_discord_bot::common::minecraft::{whitelist_update, Minecraft};
|
||||
use skynet_discord_bot::Config;
|
||||
use sqlx::Error;
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("link_minecraft")
|
||||
.description("Link your minecraft account")
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::String, "minecraft_username", "Your Minecraft username").required(true))
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::Boolean, "bedrock_account", "Is this a Bedrock account?").required(false))
|
||||
}
|
||||
|
||||
pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
||||
let db_lock = {
|
||||
let data_read = ctx.data.read().await;
|
||||
|
@ -34,30 +41,23 @@ pub(crate) mod user {
|
|||
return "Not linked with wolves, please use ``/link_wolves`` with your wolves email.".to_string();
|
||||
}
|
||||
|
||||
let sub_options = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::SubCommand(options),
|
||||
let username = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::String(username),
|
||||
..
|
||||
}) = command.data.options.first()
|
||||
{
|
||||
options
|
||||
} else {
|
||||
return "Please provide sub options".to_string();
|
||||
};
|
||||
|
||||
let username = if let Some(x) = sub_options.first() {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::String(username) => username.trim(),
|
||||
_ => return "Please provide a valid username".to_string(),
|
||||
}
|
||||
username.trim()
|
||||
} else {
|
||||
return "Please provide a valid username".to_string();
|
||||
};
|
||||
|
||||
let java = if let Some(x) = sub_options.get(1) {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::Boolean(z) => !z,
|
||||
_ => true,
|
||||
}
|
||||
// this is always true unless they state its not
|
||||
let java = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::Boolean(z),
|
||||
..
|
||||
}) = command.data.options.get(1)
|
||||
{
|
||||
!z
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
@ -192,19 +192,19 @@ pub(crate) mod server {
|
|||
use super::*;
|
||||
use skynet_discord_bot::common::minecraft::update_server;
|
||||
use skynet_discord_bot::common::minecraft::Minecraft;
|
||||
use skynet_discord_bot::Config;
|
||||
use skynet_discord_bot::{is_admin, Config};
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("minecraft_add")
|
||||
.description("Add a minecraft server")
|
||||
.default_member_permissions(serenity::model::Permissions::MANAGE_GUILD)
|
||||
.add_option(
|
||||
CreateCommandOption::new(CommandOptionType::String, "server_id", "ID of the Minecraft server hosted by the Computer Society")
|
||||
.required(true),
|
||||
)
|
||||
CreateCommand::new("minecraft_add").description("Add a minecraft server").add_option(
|
||||
CreateCommandOption::new(CommandOptionType::String, "server_id", "ID of the Minecraft server hosted by the Computer Society").required(true),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
||||
// check if user has high enough permisssions
|
||||
if let Some(msg) = is_admin(command, ctx).await {
|
||||
return msg;
|
||||
}
|
||||
let g_id = match command.guild_id {
|
||||
None => return "Not in a server".to_string(),
|
||||
Some(x) => x,
|
||||
|
@ -265,15 +265,16 @@ pub(crate) mod server {
|
|||
use serenity::client::Context;
|
||||
use skynet_discord_bot::common::database::DataBase;
|
||||
use skynet_discord_bot::common::minecraft::{get_minecraft_config_server, server_information};
|
||||
use skynet_discord_bot::Config;
|
||||
use skynet_discord_bot::{is_admin, Config};
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("minecraft_list")
|
||||
.default_member_permissions(serenity::model::Permissions::MANAGE_GUILD)
|
||||
.description("List your minecraft servers")
|
||||
CreateCommand::new("minecraft_list").description("List your minecraft servers")
|
||||
}
|
||||
|
||||
pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
||||
if let Some(msg) = is_admin(command, ctx).await {
|
||||
return msg;
|
||||
}
|
||||
let g_id = match command.guild_id {
|
||||
None => return "Not in a server".to_string(),
|
||||
Some(x) => x,
|
||||
|
@ -326,19 +327,20 @@ pub(crate) mod server {
|
|||
use serenity::model::id::GuildId;
|
||||
use skynet_discord_bot::common::database::DataBase;
|
||||
use skynet_discord_bot::common::minecraft::Minecraft;
|
||||
use skynet_discord_bot::is_admin;
|
||||
use sqlx::{Error, Pool, Sqlite};
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("minecraft_delete")
|
||||
.description("Delete a minecraft server")
|
||||
.default_member_permissions(serenity::model::Permissions::MANAGE_GUILD)
|
||||
.add_option(
|
||||
CreateCommandOption::new(CommandOptionType::String, "server_id", "ID of the Minecraft server hosted by the Computer Society")
|
||||
.required(true),
|
||||
)
|
||||
CreateCommand::new("minecraft_delete").description("Delete a minecraft server").add_option(
|
||||
CreateCommandOption::new(CommandOptionType::String, "server_id", "ID of the Minecraft server hosted by the Computer Society").required(true),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
||||
// check if user has high enough permisssions
|
||||
if let Some(msg) = is_admin(command, ctx).await {
|
||||
return msg;
|
||||
}
|
||||
let g_id = match command.guild_id {
|
||||
None => return "Not in a server".to_string(),
|
||||
Some(x) => x,
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
pub mod add_server;
|
||||
pub mod committee;
|
||||
pub mod count;
|
||||
pub mod link_email;
|
||||
pub mod minecraft;
|
||||
pub mod role_adder;
|
||||
pub mod wolves;
|
||||
|
|
|
@ -1,48 +1,47 @@
|
|||
use serenity::client::Context;
|
||||
|
||||
use skynet_discord_bot::common::database::{DataBase, RoleAdder};
|
||||
use skynet_discord_bot::is_admin;
|
||||
use sqlx::{Error, Pool, Sqlite};
|
||||
|
||||
pub mod edit {
|
||||
use super::*;
|
||||
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteraction};
|
||||
use serenity::all::{CommandDataOption, CommandDataOptionValue, CommandInteraction, CommandOptionType, CreateCommand, CreateCommandOption};
|
||||
|
||||
pub async fn run(command: &CommandInteraction, ctx: &Context) -> String {
|
||||
let sub_options = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::SubCommand(options),
|
||||
// check if user has high enough permisssions
|
||||
if let Some(msg) = is_admin(command, ctx).await {
|
||||
return msg;
|
||||
}
|
||||
|
||||
let role_a = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::Role(role),
|
||||
..
|
||||
}) = command.data.options.first()
|
||||
{
|
||||
options
|
||||
role.to_owned()
|
||||
} else {
|
||||
return "Please provide sub options".to_string();
|
||||
return "Please provide a valid role for ``Role Current``".to_string();
|
||||
};
|
||||
|
||||
let role_a = if let Some(x) = sub_options.first() {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::Role(role) => role.to_owned(),
|
||||
_ => return "Please provide a valid role for ``Role A``".to_string(),
|
||||
}
|
||||
let role_b = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::Role(role),
|
||||
..
|
||||
}) = command.data.options.get(1)
|
||||
{
|
||||
role.to_owned()
|
||||
} else {
|
||||
return "Please provide a valid role for ``Role A``".to_string();
|
||||
return "Please provide a valid role for ``Role Current``".to_string();
|
||||
};
|
||||
|
||||
let role_b = if let Some(x) = sub_options.get(1) {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::Role(role) => role.to_owned(),
|
||||
_ => return "Please provide a valid role for ``Role B``".to_string(),
|
||||
}
|
||||
let role_c = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::Role(role),
|
||||
..
|
||||
}) = command.data.options.get(2)
|
||||
{
|
||||
role.to_owned()
|
||||
} else {
|
||||
return "Please provide a valid role for ``Role B``".to_string();
|
||||
};
|
||||
|
||||
let role_c = if let Some(x) = sub_options.get(2) {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::Role(role) => role.to_owned(),
|
||||
_ => return "Please provide a valid role for ``Role C``".to_string(),
|
||||
}
|
||||
} else {
|
||||
return "Please provide a valid role for ``Role C``".to_string();
|
||||
return "Please provide a valid role for ``Role Current``".to_string();
|
||||
};
|
||||
|
||||
if role_a == role_b {
|
||||
|
@ -53,11 +52,12 @@ pub mod edit {
|
|||
return "Role C cannot be same as A or B".to_string();
|
||||
}
|
||||
|
||||
let delete = if let Some(x) = sub_options.get(3) {
|
||||
match &x.value {
|
||||
CommandDataOptionValue::Boolean(z) => *z,
|
||||
_ => false,
|
||||
}
|
||||
let delete = if let Some(CommandDataOption {
|
||||
value: CommandDataOptionValue::Boolean(z),
|
||||
..
|
||||
}) = command.data.options.get(3)
|
||||
{
|
||||
*z
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
@ -107,6 +107,15 @@ pub mod edit {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn register() -> CreateCommand {
|
||||
CreateCommand::new("roles_adder")
|
||||
.description("Combine roles together to an new one")
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::Role, "role_a", "A role you want to add to Role B").required(true))
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::Role, "role_b", "A role you want to add to Role A").required(true))
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::Role, "role_c", "Sum of A and B").required(true))
|
||||
.add_option(CreateCommandOption::new(CommandOptionType::Boolean, "delete", "Delete this entry.").required(false))
|
||||
}
|
||||
|
||||
async fn add_server(db: &Pool<Sqlite>, server: &RoleAdder, delete: bool) -> Result<Option<RoleAdder>, Error> {
|
||||
if delete {
|
||||
sqlx::query_as::<_, RoleAdder>(
|
||||
|
|
|
@ -121,12 +121,12 @@ impl<'r> FromRow<'r, SqliteRow> for WolvesVerify {
|
|||
pub struct Servers {
|
||||
pub server: GuildId,
|
||||
pub wolves_api: String,
|
||||
pub wolves_id: i64,
|
||||
pub role_past: Option<RoleId>,
|
||||
pub role_current: RoleId,
|
||||
pub member_past: i64,
|
||||
pub member_current: i64,
|
||||
pub bot_channel_id: ChannelId,
|
||||
pub server_name: String,
|
||||
}
|
||||
|
||||
impl<'r> FromRow<'r, SqliteRow> for Servers {
|
||||
|
@ -158,12 +158,12 @@ impl<'r> FromRow<'r, SqliteRow> for Servers {
|
|||
Ok(Self {
|
||||
server,
|
||||
wolves_api: row.try_get("wolves_api")?,
|
||||
wolves_id: row.try_get("wolves_id").unwrap_or(0),
|
||||
role_past,
|
||||
role_current,
|
||||
member_past: row.try_get("member_past")?,
|
||||
member_current: row.try_get("member_current")?,
|
||||
bot_channel_id,
|
||||
server_name: row.try_get("server_name")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -190,28 +190,14 @@ impl<'r> FromRow<'r, SqliteRow> for RoleAdder {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_role_from_row(row: &SqliteRow, col: &str) -> RoleId {
|
||||
let id = match row.try_get(col) {
|
||||
fn get_role_from_row(row: &SqliteRow, col: &str) -> RoleId {
|
||||
match row.try_get(col) {
|
||||
Ok(x) => {
|
||||
let tmp: i64 = x;
|
||||
tmp as u64
|
||||
RoleId::new(tmp as u64)
|
||||
}
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
RoleId::from(id)
|
||||
}
|
||||
|
||||
pub(crate) fn get_channel_from_row(row: &SqliteRow, col: &str) -> ChannelId {
|
||||
let id = match row.try_get(col) {
|
||||
Ok(x) => {
|
||||
let tmp: i64 = x;
|
||||
tmp as u64
|
||||
}
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
ChannelId::from(id)
|
||||
_ => RoleId::from(0u64),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn db_init(config: &Config) -> Result<Pool<Sqlite>, Error> {
|
||||
|
|
|
@ -131,10 +131,9 @@ pub mod normal {
|
|||
|
||||
// for updating committee members
|
||||
pub mod committee {
|
||||
use crate::common::database::{get_channel_from_row, get_role_from_row, DataBase, Wolves};
|
||||
use crate::common::database::{DataBase, Wolves};
|
||||
use crate::common::wolves::committees::Committees;
|
||||
use crate::Config;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::all::EditRole;
|
||||
use serenity::builder::CreateChannel;
|
||||
use serenity::client::Context;
|
||||
|
@ -142,8 +141,7 @@ pub mod committee {
|
|||
use serenity::model::guild::Member;
|
||||
use serenity::model::id::ChannelId;
|
||||
use serenity::model::prelude::RoleId;
|
||||
use sqlx::sqlite::SqliteRow;
|
||||
use sqlx::{Error, FromRow, Pool, Row, Sqlite};
|
||||
use sqlx::{Pool, Sqlite};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -176,7 +174,8 @@ pub mod committee {
|
|||
let server = config.committee_server;
|
||||
let committee_member = RoleId::new(1226602779968274573);
|
||||
let committees = get_committees(db).await;
|
||||
let categories = [
|
||||
let categories = vec![
|
||||
// C&S Chats 1
|
||||
ChannelId::new(1226606560973815839),
|
||||
// C&S Chats 2
|
||||
ChannelId::new(1341457244973305927),
|
||||
|
@ -185,30 +184,35 @@ pub mod committee {
|
|||
];
|
||||
|
||||
// information about the server
|
||||
let mut roles_db = HashMap::new();
|
||||
for role in db_roles_get(db).await {
|
||||
roles_db.insert(
|
||||
role.id_wolves,
|
||||
CommitteeRoles {
|
||||
id_wolves: role.id_wolves,
|
||||
id_role: role.id_role,
|
||||
id_channel: role.id_channel,
|
||||
name_role: role.name_role,
|
||||
name_channel: role.name_channel,
|
||||
// always start at 0
|
||||
count: 0,
|
||||
},
|
||||
);
|
||||
let roles = server.roles(&ctx).await.unwrap_or_default();
|
||||
let channels = server.channels(&ctx).await.unwrap_or_default();
|
||||
|
||||
// make a hashmap of the nameof roles to quickly get them out again
|
||||
let mut roles_name = HashMap::new();
|
||||
for role in roles.values() {
|
||||
roles_name.insert(role.name.to_owned(), role.to_owned());
|
||||
}
|
||||
|
||||
let mut channels = server.channels(&ctx).await.unwrap_or_default();
|
||||
let mut channels_name = HashMap::new();
|
||||
for channel in channels.values() {
|
||||
// we only care about teh channels in teh category
|
||||
if let Some(x) = channel.parent_id {
|
||||
for category in &categories {
|
||||
if x.eq(category) {
|
||||
channels_name.insert(channel.name.to_owned(), channel.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a map of users and the roles they are goign to be getting
|
||||
let mut users_roles = HashMap::new();
|
||||
|
||||
let mut re_order = false;
|
||||
// we need to create roles and channels if tehy dont already exist
|
||||
// a list of all the roles that can be removed from folks who should have them
|
||||
let mut committee_roles = vec![committee_member];
|
||||
|
||||
let mut category_index = 0;
|
||||
|
||||
let mut i = 0;
|
||||
loop {
|
||||
if i >= committees.len() {
|
||||
|
@ -216,17 +220,24 @@ pub mod committee {
|
|||
}
|
||||
let committee = &committees[i];
|
||||
|
||||
// if a club/soc ever changes their name
|
||||
if let Some(x) = roles_db.get_mut(&committee.id) {
|
||||
committee.name_full.clone_into(&mut x.name_role);
|
||||
committee.name_profile.clone_into(&mut x.name_channel);
|
||||
}
|
||||
// get the role for this committee/club/soc
|
||||
let role = match roles_name.get(&committee.name_full) {
|
||||
Some(x) => Some(x.to_owned()),
|
||||
None => {
|
||||
// create teh role if it does not exist
|
||||
match server
|
||||
.create_role(&ctx, EditRole::new().name(&committee.name_full).hoist(false).mentionable(true))
|
||||
.await
|
||||
{
|
||||
Ok(x) => Some(x),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// handle new clubs/socs
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = roles_db.entry(committee.id) {
|
||||
// create channel
|
||||
// channel is first as the categories can only contain 50 channels
|
||||
let channel = match server
|
||||
// create teh channel if it does nto exist
|
||||
if !channels_name.contains_key(&committee.name_profile) {
|
||||
match server
|
||||
.create_channel(
|
||||
&ctx,
|
||||
CreateChannel::new(&committee.name_profile)
|
||||
|
@ -236,74 +247,40 @@ pub mod committee {
|
|||
.await
|
||||
{
|
||||
Ok(x) => {
|
||||
println!("Created channel: {}", &committee.name_profile);
|
||||
// update teh channels name list
|
||||
channels_name.insert(x.name.to_owned(), x.to_owned());
|
||||
|
||||
x.id
|
||||
println!("Created channel: {}", &committee.name_profile);
|
||||
}
|
||||
Err(x) => {
|
||||
let tmp = x.to_string();
|
||||
dbg!("Unable to create channel: ", &tmp, &tmp.contains("Maximum number of channels in category reached (50)"));
|
||||
|
||||
if x.to_string().contains("Maximum number of channels in category reached (50)") {
|
||||
category_index += 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
ChannelId::new(1)
|
||||
dbg!("Unable to create channel: ", &tmp, &tmp.contains("Maximum number of channels in category reached (50)"));
|
||||
}
|
||||
};
|
||||
|
||||
// create role
|
||||
let role = match server
|
||||
.create_role(&ctx, EditRole::new().name(&committee.name_full).hoist(false).mentionable(true))
|
||||
.await
|
||||
{
|
||||
Ok(x) => x.id,
|
||||
Err(_) => RoleId::new(1),
|
||||
};
|
||||
|
||||
let tmp = CommitteeRoles {
|
||||
id_wolves: committee.id,
|
||||
id_role: role,
|
||||
id_channel: channel,
|
||||
name_role: committee.name_full.to_owned(),
|
||||
name_channel: committee.name_profile.to_owned(),
|
||||
count: 0,
|
||||
};
|
||||
|
||||
// save it to the db in case of crash or error
|
||||
db_role_set(db, &tmp).await;
|
||||
|
||||
// insert it into teh local cache
|
||||
e.insert(tmp);
|
||||
|
||||
re_order = true;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
for committee in &committees {
|
||||
let r = if let Some(x) = roles_db.get(&committee.id) {
|
||||
x.id_role
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
for id_wolves in &committee.committee {
|
||||
// ID in this is the wolves ID, so we need to get a matching discord ID (if one exists)
|
||||
if let Some(x) = get_server_member_discord(db, id_wolves).await {
|
||||
if let Some(member_tmp) = x.discord {
|
||||
if server.member(ctx, &member_tmp).await.is_ok() {
|
||||
let values = users_roles.entry(member_tmp).or_insert(vec![]);
|
||||
values.push(r);
|
||||
// so if the role exists
|
||||
if let Some(r) = role {
|
||||
committee_roles.push(r.id);
|
||||
|
||||
if let Some(x) = roles_db.get_mut(&committee.id) {
|
||||
x.count += 1;
|
||||
}
|
||||
for id_wolves in &committee.committee {
|
||||
// ID in this is the wolves ID, so we need to get a matching discord ID (if one exists)
|
||||
if let Some(x) = get_server_member_discord(db, id_wolves).await {
|
||||
if let Some(member_tmp) = x.discord {
|
||||
let values = users_roles.entry(member_tmp).or_insert(vec![committee_member]);
|
||||
values.push(r.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// now we have a map of all users that should get roles time to go through all the folks on teh server
|
||||
|
@ -338,10 +315,6 @@ pub mod committee {
|
|||
if !roles_required.is_empty() {
|
||||
// if there are committee roles then give the general purporse role
|
||||
roles_add.push(committee_member);
|
||||
|
||||
if let Some(x) = roles_db.get_mut(&0) {
|
||||
x.count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for role in &roles_required {
|
||||
|
@ -362,114 +335,34 @@ pub mod committee {
|
|||
}
|
||||
}
|
||||
|
||||
let mut channel_names = vec![];
|
||||
let mut positions = vec![];
|
||||
for role in roles_db.values() {
|
||||
// save these to db
|
||||
db_role_set(db, role).await;
|
||||
// finally re-order teh channels to make them visually apealing
|
||||
let mut channel_names = channels_name.clone().into_keys().collect::<Vec<String>>();
|
||||
channel_names.sort();
|
||||
|
||||
if re_order {
|
||||
let channel_id = role.id_channel.to_owned();
|
||||
if let Some(channel) = channels.get_mut(&channel_id) {
|
||||
// record the position of each of teh C&S channels
|
||||
positions.push(channel.position);
|
||||
|
||||
// pull out teh channel names
|
||||
channel_names.push((role.name_channel.to_owned(), channel_id));
|
||||
// get a list of all teh new positions
|
||||
let mut new_positions = vec![];
|
||||
for (i, name) in channel_names.iter().enumerate() {
|
||||
if let Some(channel) = channels_name.get_mut(name) {
|
||||
let position_new = i as u64;
|
||||
if position_new != channel.position as u64 {
|
||||
new_positions.push((channel.id.to_owned(), position_new));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if re_order {
|
||||
// sort by the position and name
|
||||
positions.sort();
|
||||
channel_names.sort_by_key(|(name, _)| name.to_owned());
|
||||
|
||||
let mut new_positions = vec![];
|
||||
for (i, (_, id)) in channel_names.iter().enumerate() {
|
||||
new_positions.push((id.to_owned(), positions[i] as u64));
|
||||
}
|
||||
|
||||
if !new_positions.is_empty() {
|
||||
match server.reorder_channels(&ctx, new_positions).await {
|
||||
Ok(_) => {
|
||||
println!("Successfully re-orderd the committee category");
|
||||
}
|
||||
Err(e) => {
|
||||
dbg!("Failed to re-order ", e);
|
||||
}
|
||||
if !new_positions.is_empty() {
|
||||
match server.reorder_channels(&ctx, new_positions).await {
|
||||
Ok(_) => {
|
||||
println!("Successfully re-orderd the committee category");
|
||||
}
|
||||
Err(e) => {
|
||||
dbg!("Failed to re-order ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct CommitteeRoles {
|
||||
id_wolves: i64,
|
||||
id_role: RoleId,
|
||||
id_channel: ChannelId,
|
||||
pub name_role: String,
|
||||
name_channel: String,
|
||||
pub count: i64,
|
||||
}
|
||||
|
||||
impl<'r> FromRow<'r, SqliteRow> for CommitteeRoles {
|
||||
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
id_wolves: row.try_get("id_wolves")?,
|
||||
id_role: get_role_from_row(row, "id_role"),
|
||||
id_channel: get_channel_from_row(row, "id_channel"),
|
||||
name_role: row.try_get("name_role")?,
|
||||
name_channel: row.try_get("name_channel")?,
|
||||
count: row.try_get("count")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn db_role_set(db: &Pool<Sqlite>, role: &CommitteeRoles) {
|
||||
// expiry
|
||||
match sqlx::query_as::<_, CommitteeRoles>(
|
||||
"
|
||||
INSERT INTO committee_roles (id_wolves, id_role, id_channel, name_role, name_channel, count)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
ON CONFLICT(id_wolves) DO UPDATE SET name_role = $4, name_channel = $5, count = $6
|
||||
",
|
||||
)
|
||||
.bind(role.id_wolves)
|
||||
.bind(role.id_role.get() as i64)
|
||||
.bind(role.id_channel.get() as i64)
|
||||
.bind(&role.name_role)
|
||||
.bind(&role.name_channel)
|
||||
.bind(role.count)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!("Failure to insert into Wolves {:?}", role);
|
||||
println!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn db_roles_get(db: &Pool<Sqlite>) -> Vec<CommitteeRoles> {
|
||||
// expiry
|
||||
sqlx::query_as::<_, CommitteeRoles>(
|
||||
"
|
||||
SELECT *
|
||||
FROM committee_roles
|
||||
",
|
||||
)
|
||||
.fetch_all(db)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
println!("Failure to get Roles from committee_roles");
|
||||
println!("{:?}", e);
|
||||
vec![]
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_committees(db: &Pool<Sqlite>) -> Vec<Committees> {
|
||||
async fn get_committees(db: &Pool<Sqlite>) -> Vec<Committees> {
|
||||
sqlx::query_as::<_, Committees>(
|
||||
r#"
|
||||
SELECT *
|
||||
|
|
|
@ -87,7 +87,7 @@ pub mod cns {
|
|||
server,
|
||||
// this is the unique api key for each club/soc
|
||||
wolves_api,
|
||||
wolves_id,
|
||||
server_name,
|
||||
..
|
||||
} = &server_config;
|
||||
// dbg!(&server_config);
|
||||
|
@ -101,7 +101,7 @@ pub mod cns {
|
|||
for user in wolves.get_members(wolves_api).await {
|
||||
// dbg!(&user.committee);
|
||||
if server_name_tmp.is_none() {
|
||||
server_name_tmp = Some(user.committee_id);
|
||||
server_name_tmp = Some(user.committee.to_owned());
|
||||
}
|
||||
let id = user.member_id.parse::<u64>().unwrap_or_default();
|
||||
match existing.get(&(id as i64)) {
|
||||
|
@ -124,9 +124,9 @@ pub mod cns {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(cs_id) = server_name_tmp {
|
||||
if &cs_id != wolves_id {
|
||||
set_server_member(&db, server, cs_id).await;
|
||||
if let Some(name) = server_name_tmp {
|
||||
if &name != server_name {
|
||||
set_server_member(&db, server, &name).await;
|
||||
}
|
||||
}
|
||||
if !user_to_update.is_empty() {
|
||||
|
@ -135,15 +135,15 @@ pub mod cns {
|
|||
}
|
||||
}
|
||||
|
||||
async fn set_server_member(db: &Pool<Sqlite>, server: &GuildId, wolves_id: i64) {
|
||||
async fn set_server_member(db: &Pool<Sqlite>, server: &GuildId, name: &str) {
|
||||
match sqlx::query_as::<_, Servers>(
|
||||
"
|
||||
UPDATE servers
|
||||
SET wolves_id = ?
|
||||
SET server_name = ?
|
||||
WHERE server = ?
|
||||
",
|
||||
)
|
||||
.bind(wolves_id)
|
||||
.bind(name)
|
||||
.bind(server.get() as i64)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
|
|
40
src/lib.rs
40
src/lib.rs
|
@ -3,6 +3,8 @@ pub mod common;
|
|||
use chrono::{Datelike, SecondsFormat, Utc};
|
||||
use dotenvy::dotenv;
|
||||
use rand::{distr::Alphanumeric, rng, Rng};
|
||||
use serenity::all::CommandInteraction;
|
||||
use serenity::client::Context;
|
||||
use serenity::model::id::{ChannelId, GuildId, RoleId};
|
||||
use serenity::prelude::TypeMapKey;
|
||||
use std::{env, sync::Arc};
|
||||
|
@ -125,3 +127,41 @@ pub fn get_now_iso(short: bool) -> String {
|
|||
pub fn random_string(len: usize) -> String {
|
||||
rng().sample_iter(&Alphanumeric).take(len).map(char::from).collect()
|
||||
}
|
||||
|
||||
/**
|
||||
For any time ye need to check if a user who calls a command has admin privlages
|
||||
*/
|
||||
pub async fn is_admin(command: &CommandInteraction, ctx: &Context) -> Option<String> {
|
||||
let mut admin = false;
|
||||
|
||||
let g_id = match command.guild_id {
|
||||
None => return Some("Not in a server".to_string()),
|
||||
Some(x) => x,
|
||||
};
|
||||
|
||||
let roles_server = g_id.roles(&ctx.http).await.unwrap_or_default();
|
||||
|
||||
if let Ok(member) = g_id.member(&ctx.http, command.user.id).await {
|
||||
if let Some(permissions) = member.permissions {
|
||||
if permissions.administrator() {
|
||||
admin = true;
|
||||
}
|
||||
}
|
||||
|
||||
for role_id in member.roles {
|
||||
if admin {
|
||||
break;
|
||||
}
|
||||
if let Some(role) = roles_server.get(&role_id) {
|
||||
if role.permissions.administrator() {
|
||||
admin = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !admin {
|
||||
Some("Administrator permission required".to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
81
src/main.rs
81
src/main.rs
|
@ -1,7 +1,7 @@
|
|||
pub mod commands;
|
||||
|
||||
use crate::commands::role_adder::tools::on_role_change;
|
||||
use serenity::all::{ActivityData, Command, CreateMessage, EditInteractionResponse, GuildId, GuildMemberUpdateEvent, Interaction};
|
||||
use serenity::all::{ActivityData, Command, CreateMessage, EditInteractionResponse, GuildMemberUpdateEvent, Interaction};
|
||||
use serenity::model::guild::Member;
|
||||
use serenity::{
|
||||
async_trait,
|
||||
|
@ -68,7 +68,7 @@ impl EventHandler for Handler {
|
|||
println!("{:?}", e);
|
||||
}
|
||||
} else {
|
||||
let tmp = get_committee(&db, config_server.wolves_id).await;
|
||||
let tmp = get_committee(&db, &config_server.server_name).await;
|
||||
if !tmp.is_empty() {
|
||||
let committee = &tmp[0];
|
||||
let msg = format!(
|
||||
|
@ -113,11 +113,14 @@ Sign up on [UL Wolves]({}) and go to https://discord.com/channels/{}/{} and use
|
|||
match Command::set_global_commands(
|
||||
&ctx.http,
|
||||
vec![
|
||||
commands::wolves::register(),
|
||||
commands::committee::register(),
|
||||
commands::add_server::register(),
|
||||
commands::role_adder::edit::register(),
|
||||
commands::link_email::link::register(),
|
||||
commands::link_email::verify::register(),
|
||||
commands::minecraft::server::add::register(),
|
||||
commands::minecraft::server::list::register(),
|
||||
commands::minecraft::server::delete::register(),
|
||||
commands::minecraft::user::add::register(),
|
||||
],
|
||||
)
|
||||
.await
|
||||
|
@ -127,33 +130,6 @@ Sign up on [UL Wolves]({}) and go to https://discord.com/channels/{}/{} and use
|
|||
println!("{:?}", e)
|
||||
}
|
||||
}
|
||||
|
||||
let config_lock = {
|
||||
let data_read = ctx.data.read().await;
|
||||
data_read.get::<Config>().expect("Expected Config in TypeMap.").clone()
|
||||
};
|
||||
let config_global = config_lock.read().await;
|
||||
|
||||
match &config_global
|
||||
.committee_server
|
||||
.set_commands(&ctx.http, vec![commands::count::committee::register()])
|
||||
.await
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!("{:?}", e)
|
||||
}
|
||||
}
|
||||
|
||||
match GuildId::new(689189992417067052)
|
||||
.set_commands(&ctx.http, vec![commands::count::servers::register()])
|
||||
.await
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
||||
|
@ -163,41 +139,16 @@ Sign up on [UL Wolves]({}) and go to https://discord.com/channels/{}/{} and use
|
|||
|
||||
let content = match command.data.name.as_str() {
|
||||
// user commands
|
||||
"wolves" => match command.data.options.first() {
|
||||
None => "Invalid Command".to_string(),
|
||||
Some(x) => match x.name.as_str() {
|
||||
"link" => commands::wolves::link::run(&command, &ctx).await,
|
||||
"verify" => commands::wolves::verify::run(&command, &ctx).await,
|
||||
"unlink" => commands::wolves::unlink::run(&command, &ctx).await,
|
||||
"link_minecraft" => commands::minecraft::user::add::run(&command, &ctx).await,
|
||||
// "link" => commands::count::servers::run(&command, &ctx).await,
|
||||
&_ => format!("not implemented :( wolves {}", x.name.as_str()),
|
||||
},
|
||||
},
|
||||
|
||||
"link_wolves" => commands::link_email::link::run(&command, &ctx).await,
|
||||
"verify" => commands::link_email::verify::run(&command, &ctx).await,
|
||||
"link_minecraft" => commands::minecraft::user::add::run(&command, &ctx).await,
|
||||
// admin commands
|
||||
"committee" => match command.data.options.first() {
|
||||
None => "Invalid Command".to_string(),
|
||||
Some(x) => match x.name.as_str() {
|
||||
"add" => commands::add_server::run(&command, &ctx).await,
|
||||
"roles_adder" => commands::role_adder::edit::run(&command, &ctx).await,
|
||||
// "link" => commands::count::servers::run(&command, &ctx).await,
|
||||
&_ => format!("not implemented :( committee {}", x.name.as_str()),
|
||||
},
|
||||
},
|
||||
"add" => commands::add_server::run(&command, &ctx).await,
|
||||
"roles_adder" => commands::role_adder::edit::run(&command, &ctx).await,
|
||||
"minecraft_add" => commands::minecraft::server::add::run(&command, &ctx).await,
|
||||
"minecraft_list" => commands::minecraft::server::list::run(&command, &ctx).await,
|
||||
"minecraft_delete" => commands::minecraft::server::delete::run(&command, &ctx).await,
|
||||
// sub command
|
||||
"count" => match command.data.options.first() {
|
||||
None => "Invalid Command".to_string(),
|
||||
Some(x) => match x.name.as_str() {
|
||||
"committee" => commands::count::committee::run(&command, &ctx).await,
|
||||
"servers" => commands::count::servers::run(&command, &ctx).await,
|
||||
&_ => format!("not implemented :( count {}", x.name.as_str()),
|
||||
},
|
||||
},
|
||||
_ => format!("not implemented :( {}", command.data.name.as_str()),
|
||||
_ => "not implemented :(".to_string(),
|
||||
};
|
||||
|
||||
if let Err(why) = command.edit_response(&ctx.http, EditInteractionResponse::new().content(content)).await {
|
||||
|
@ -207,15 +158,15 @@ Sign up on [UL Wolves]({}) and go to https://discord.com/channels/{}/{} and use
|
|||
}
|
||||
}
|
||||
|
||||
async fn get_committee(db: &Pool<Sqlite>, wolves_id: i64) -> Vec<Committees> {
|
||||
async fn get_committee(db: &Pool<Sqlite>, committee: &str) -> Vec<Committees> {
|
||||
sqlx::query_as::<_, Committees>(
|
||||
r#"
|
||||
SELECT *
|
||||
FROM committees
|
||||
WHERE id = ?
|
||||
WHERE name_plain = ?
|
||||
"#,
|
||||
)
|
||||
.bind(wolves_id)
|
||||
.bind(committee)
|
||||
.fetch_all(db)
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
|
|
Loading…
Add table
Reference in a new issue