Merge branch 'main' into #17-automate-onboarding-mk-ii
# Conflicts: # .gitignore # src/commands/committee.rs
This commit is contained in:
commit
b2d8238c17
12 changed files with 447 additions and 47 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -8,7 +8,7 @@ result
|
||||||
/result
|
/result
|
||||||
|
|
||||||
*.db
|
*.db
|
||||||
*.db*
|
*.db.*
|
||||||
|
|
||||||
tmp/
|
tmp/
|
||||||
tmp.*
|
tmp.*
|
||||||
|
|
9
LICENSE
Normal file
9
LICENSE
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Skynet
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
5
db/migrations/5_welcome-message.sql
Normal file
5
db/migrations/5_welcome-message.sql
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
-- temp table to allow folks to verify by committee email.
|
||||||
|
-- delete the col in teh server table
|
||||||
|
ALTER TABLE servers ADD COLUMN bot_channel_id integer DEFAULT 0;
|
||||||
|
ALTER TABLE servers ADD COLUMN server_name text NOT NULL DEFAULT "";
|
||||||
|
ALTER TABLE servers ADD COLUMN wolves_link text NOT NULL DEFAULT "";
|
11
db/migrations/6_role-adder.sql
Normal file
11
db/migrations/6_role-adder.sql
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS roles_adder (
|
||||||
|
server integer not null,
|
||||||
|
role_a integer not null,
|
||||||
|
role_b integer not null,
|
||||||
|
role_c integer not null,
|
||||||
|
PRIMARY KEY(server,role_a,role_b,role_c)
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS index_roles_adder_server ON roles_adder (server);
|
||||||
|
CREATE INDEX IF NOT EXISTS index_roles_adder_from ON roles_adder (role_a,role_b);
|
||||||
|
CREATE INDEX IF NOT EXISTS index_roles_adder_to ON roles_adder (role_c);
|
||||||
|
CREATE INDEX IF NOT EXISTS index_roles_adder_search ON roles_adder (server,role_a,role_b);
|
|
@ -75,7 +75,7 @@
|
||||||
cfg = config.services."${package_name}";
|
cfg = config.services."${package_name}";
|
||||||
# secret options are in the env file(s) loaded separately
|
# secret options are in the env file(s) loaded separately
|
||||||
environment_config = {
|
environment_config = {
|
||||||
HOME = cfg.home;
|
DATABASE_HOME = cfg.home;
|
||||||
DATABASE = "database.db";
|
DATABASE = "database.db";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,18 +39,60 @@ pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> Stri
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("Expected role object")
|
.expect("Expected role object")
|
||||||
{
|
{
|
||||||
Some(role.id.to_owned())
|
role.id.to_owned()
|
||||||
} else {
|
} else {
|
||||||
return "Please provide a valid role for ``Role Current``".to_string();
|
return "Please provide a valid role for ``Role Current``".to_string();
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut role_past = None;
|
let mut role_past = None;
|
||||||
if let Some(x) = command.data.options.get(2) {
|
if let Some(x) = command.data.options.get(5) {
|
||||||
if let Some(CommandDataOptionValue::Role(role)) = &x.resolved {
|
if let Some(CommandDataOptionValue::Role(role)) = &x.resolved {
|
||||||
role_past = Some(role.id.to_owned());
|
role_past = Some(role.id.to_owned());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let bot_channel_id = if let CommandDataOptionValue::Channel(channel) = command
|
||||||
|
.data
|
||||||
|
.options
|
||||||
|
.get(2)
|
||||||
|
.expect("Expected channel option")
|
||||||
|
.resolved
|
||||||
|
.as_ref()
|
||||||
|
.expect("Expected channel object")
|
||||||
|
{
|
||||||
|
channel.id.to_owned()
|
||||||
|
} else {
|
||||||
|
return "Please provide a valid channel for ``Bot Channel``".to_string();
|
||||||
|
};
|
||||||
|
|
||||||
|
let server_name = if let CommandDataOptionValue::String(name) = command
|
||||||
|
.data
|
||||||
|
.options
|
||||||
|
.get(3)
|
||||||
|
.expect("Expected Server Name option")
|
||||||
|
.resolved
|
||||||
|
.as_ref()
|
||||||
|
.expect("Expected Server Name object")
|
||||||
|
{
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
&"UL Computer Society".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let wolves_link = if let CommandDataOptionValue::String(wolves) = command
|
||||||
|
.data
|
||||||
|
.options
|
||||||
|
.get(4)
|
||||||
|
.expect("Expected Wolves Link option")
|
||||||
|
.resolved
|
||||||
|
.as_ref()
|
||||||
|
.expect("Expected Server Name object")
|
||||||
|
{
|
||||||
|
wolves
|
||||||
|
} else {
|
||||||
|
&"https://ulwolves.ie/society/computer".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
let db_lock = {
|
let db_lock = {
|
||||||
let data_read = ctx.data.read().await;
|
let data_read = ctx.data.read().await;
|
||||||
data_read.get::<DataBase>().expect("Expected Databse in TypeMap.").clone()
|
data_read.get::<DataBase>().expect("Expected Databse in TypeMap.").clone()
|
||||||
|
@ -64,6 +106,9 @@ pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> Stri
|
||||||
role_current,
|
role_current,
|
||||||
member_past: 0,
|
member_past: 0,
|
||||||
member_current: 0,
|
member_current: 0,
|
||||||
|
bot_channel_id,
|
||||||
|
server_name: server_name.to_owned(),
|
||||||
|
wolves_link: wolves_link.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match add_server(&db, ctx, &server_data).await {
|
match add_server(&db, ctx, &server_data).await {
|
||||||
|
@ -95,6 +140,27 @@ pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicatio
|
||||||
.kind(CommandOptionType::Role)
|
.kind(CommandOptionType::Role)
|
||||||
.required(true)
|
.required(true)
|
||||||
})
|
})
|
||||||
|
.create_option(|option| {
|
||||||
|
option
|
||||||
|
.name("bot_channel")
|
||||||
|
.description("Safe space for folks to use the bot commands.")
|
||||||
|
.kind(CommandOptionType::Channel)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
|
.create_option(|option| {
|
||||||
|
option
|
||||||
|
.name("server_name")
|
||||||
|
.description("Name of the Discord Server.")
|
||||||
|
.kind(CommandOptionType::String)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
|
.create_option(|option| {
|
||||||
|
option
|
||||||
|
.name("wolves_link")
|
||||||
|
.description("Link to the Club/Society on UL Wolves.")
|
||||||
|
.kind(CommandOptionType::String)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
.create_option(|option| {
|
.create_option(|option| {
|
||||||
option
|
option
|
||||||
.name("role_past")
|
.name("role_past")
|
||||||
|
@ -107,18 +173,20 @@ pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicatio
|
||||||
async fn add_server(db: &Pool<Sqlite>, ctx: &Context, server: &Servers) -> Result<Option<Servers>, Error> {
|
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 existing = get_server_config(db, &server.server).await;
|
||||||
let role_past = server.role_past.map(|x| *x.as_u64() as i64);
|
let role_past = server.role_past.map(|x| *x.as_u64() as i64);
|
||||||
let role_current = server.role_current.map(|x| *x.as_u64() as i64);
|
|
||||||
|
|
||||||
let insert = sqlx::query_as::<_, Servers>(
|
let insert = sqlx::query_as::<_, Servers>(
|
||||||
"
|
"
|
||||||
INSERT OR REPLACE INTO servers (server, wolves_api, role_past, role_current)
|
INSERT OR REPLACE INTO servers (server, wolves_api, role_past, role_current, bot_channel_id, server_name, wolves_link)
|
||||||
VALUES (?1, ?2, ?3, ?4)
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.bind(*server.server.as_u64() as i64)
|
.bind(*server.server.as_u64() as i64)
|
||||||
.bind(&server.wolves_api)
|
.bind(&server.wolves_api)
|
||||||
.bind(role_past)
|
.bind(role_past)
|
||||||
.bind(role_current)
|
.bind(*server.role_current.as_u64() as i64)
|
||||||
|
.bind(*server.bot_channel_id.as_u64() as i64)
|
||||||
|
.bind(&server.server_name)
|
||||||
|
.bind(&server.wolves_link)
|
||||||
.fetch_optional(db)
|
.fetch_optional(db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -133,7 +201,7 @@ async fn add_server(db: &Pool<Sqlite>, ctx: &Context, server: &Servers) -> Resul
|
||||||
if x.role_current != server.role_current {
|
if x.role_current != server.role_current {
|
||||||
result.0 = true;
|
result.0 = true;
|
||||||
result.1 = true;
|
result.1 = true;
|
||||||
result.2 = x.role_current;
|
result.2 = Some(x.role_current);
|
||||||
}
|
}
|
||||||
if x.role_past != server.role_past {
|
if x.role_past != server.role_past {
|
||||||
result.0 = true;
|
result.0 = true;
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub mod link {
|
||||||
// check if email exists
|
// check if email exists
|
||||||
let details = match get_server_member_email(&db, email).await {
|
let details = match get_server_member_email(&db, email).await {
|
||||||
None => {
|
None => {
|
||||||
return "Please check it is your preferred contact on https://ulwolves.ie/memberships/profile and that you are fully paid up.".to_string()
|
return "Please check it matches (including case) your preferred contact on https://ulwolves.ie/memberships/profile and that you are fully paid up.".to_string()
|
||||||
}
|
}
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
};
|
};
|
||||||
|
@ -184,7 +184,7 @@ pub mod link {
|
||||||
let creds = Credentials::new(config.mail_user.clone(), config.mail_pass.clone());
|
let creds = Credentials::new(config.mail_user.clone(), config.mail_pass.clone());
|
||||||
|
|
||||||
// Open a remote connection to gmail using STARTTLS
|
// Open a remote connection to gmail using STARTTLS
|
||||||
let mailer = SmtpTransport::starttls_relay(&config.mail_smtp).unwrap().credentials(creds).build();
|
let mailer = SmtpTransport::starttls_relay(&config.mail_smtp)?.credentials(creds).build();
|
||||||
|
|
||||||
// Send the email
|
// Send the email
|
||||||
mailer.send(&email)
|
mailer.send(&email)
|
||||||
|
@ -352,10 +352,8 @@ pub mod verify {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(role) = &role_current {
|
if !member.roles.contains(&role_current) {
|
||||||
if !member.roles.contains(role) {
|
roles.push(role_current.to_owned());
|
||||||
roles.push(role.to_owned());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = member.add_roles(&ctx, &roles).await {
|
if let Err(e) = member.add_roles(&ctx, &roles).await {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod add_server;
|
pub mod add_server;
|
||||||
pub mod link_email;
|
pub mod link_email;
|
||||||
pub mod minecraft;
|
pub mod minecraft;
|
||||||
|
pub mod role_adder;
|
||||||
|
|
238
src/commands/role_adder.rs
Normal file
238
src/commands/role_adder.rs
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
use serenity::{
|
||||||
|
builder::CreateApplicationCommand,
|
||||||
|
client::Context,
|
||||||
|
model::{
|
||||||
|
application::interaction::application_command::ApplicationCommandInteraction,
|
||||||
|
prelude::{command::CommandOptionType, interaction::application_command::CommandDataOptionValue},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use skynet_discord_bot::{is_admin, DataBase, RoleAdder};
|
||||||
|
use sqlx::{Error, Pool, Sqlite};
|
||||||
|
|
||||||
|
pub mod edit {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String {
|
||||||
|
// check if user has high enough permisssions
|
||||||
|
if let Some(msg) = is_admin(command, ctx).await {
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
let role_a = if let CommandDataOptionValue::Role(role) = command
|
||||||
|
.data
|
||||||
|
.options
|
||||||
|
.first()
|
||||||
|
.expect("Expected role option")
|
||||||
|
.resolved
|
||||||
|
.as_ref()
|
||||||
|
.expect("Expected role object")
|
||||||
|
{
|
||||||
|
role.id.to_owned()
|
||||||
|
} else {
|
||||||
|
return "Please provide a valid role for ``Role Current``".to_string();
|
||||||
|
};
|
||||||
|
|
||||||
|
let role_b = if let CommandDataOptionValue::Role(role) = command
|
||||||
|
.data
|
||||||
|
.options
|
||||||
|
.get(1)
|
||||||
|
.expect("Expected role option")
|
||||||
|
.resolved
|
||||||
|
.as_ref()
|
||||||
|
.expect("Expected role object")
|
||||||
|
{
|
||||||
|
role.id.to_owned()
|
||||||
|
} else {
|
||||||
|
return "Please provide a valid role for ``Role Current``".to_string();
|
||||||
|
};
|
||||||
|
|
||||||
|
let role_c = if let CommandDataOptionValue::Role(role) = command
|
||||||
|
.data
|
||||||
|
.options
|
||||||
|
.get(2)
|
||||||
|
.expect("Expected role option")
|
||||||
|
.resolved
|
||||||
|
.as_ref()
|
||||||
|
.expect("Expected role object")
|
||||||
|
{
|
||||||
|
role.id.to_owned()
|
||||||
|
} else {
|
||||||
|
return "Please provide a valid role for ``Role Current``".to_string();
|
||||||
|
};
|
||||||
|
|
||||||
|
if role_a == role_b {
|
||||||
|
return "Roles A and B must be different".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role_c == role_a) || (role_c == role_b) {
|
||||||
|
return "Role C cannot be same as A or B".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut delete = false;
|
||||||
|
|
||||||
|
if let Some(x) = command.data.options.get(3) {
|
||||||
|
let tmp = x.to_owned();
|
||||||
|
if let Some(CommandDataOptionValue::Boolean(z)) = tmp.resolved {
|
||||||
|
delete = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 server = command.guild_id.unwrap_or_default();
|
||||||
|
let server_data = RoleAdder {
|
||||||
|
server,
|
||||||
|
role_a,
|
||||||
|
role_b,
|
||||||
|
role_c,
|
||||||
|
};
|
||||||
|
|
||||||
|
match add_server(&db, &server_data, delete).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
println!("{:?}", e);
|
||||||
|
return format!("Failure to insert into Servers {:?}", server_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut role_a_name = String::new();
|
||||||
|
let mut role_b_name = String::new();
|
||||||
|
let mut role_c_name = String::new();
|
||||||
|
|
||||||
|
if let Ok(x) = server.roles(&ctx).await {
|
||||||
|
if let Some(y) = x.get(&role_a) {
|
||||||
|
role_a_name = y.to_owned().name;
|
||||||
|
}
|
||||||
|
if let Some(y) = x.get(&role_b) {
|
||||||
|
role_b_name = y.to_owned().name;
|
||||||
|
}
|
||||||
|
if let Some(y) = x.get(&role_b) {
|
||||||
|
role_c_name = y.to_owned().name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if delete {
|
||||||
|
format!("Removed {} + {} = {}", role_a_name, role_b_name, role_c_name)
|
||||||
|
} else {
|
||||||
|
format!("Added {} + {} = {}", role_a_name, role_b_name, role_c_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
||||||
|
command
|
||||||
|
.name("roles_adder")
|
||||||
|
.description("Combine roles together to an new one")
|
||||||
|
.create_option(|option| {
|
||||||
|
option
|
||||||
|
.name("role_a")
|
||||||
|
.description("A role you want to add to Role B")
|
||||||
|
.kind(CommandOptionType::Role)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
|
.create_option(|option| {
|
||||||
|
option
|
||||||
|
.name("role_b")
|
||||||
|
.description("A role you want to add to Role A")
|
||||||
|
.kind(CommandOptionType::Role)
|
||||||
|
.required(true)
|
||||||
|
})
|
||||||
|
.create_option(|option| option.name("role_c").description("Sum of A and B").kind(CommandOptionType::Role).required(true))
|
||||||
|
.create_option(|option| {
|
||||||
|
option
|
||||||
|
.name("delete")
|
||||||
|
.description("Delete this entry.")
|
||||||
|
.kind(CommandOptionType::Boolean)
|
||||||
|
.required(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_server(db: &Pool<Sqlite>, server: &RoleAdder, delete: bool) -> Result<Option<RoleAdder>, Error> {
|
||||||
|
if delete {
|
||||||
|
sqlx::query_as::<_, RoleAdder>(
|
||||||
|
"
|
||||||
|
DELETE FROM roles_adder
|
||||||
|
WHERE server = ?1 AND role_a = ?2 AND role_b = ?3 AND role_c = ?4
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(*server.server.as_u64() as i64)
|
||||||
|
.bind(*server.role_a.as_u64() as i64)
|
||||||
|
.bind(*server.role_b.as_u64() as i64)
|
||||||
|
.bind(*server.role_c.as_u64() as i64)
|
||||||
|
.fetch_optional(db)
|
||||||
|
.await
|
||||||
|
} else {
|
||||||
|
sqlx::query_as::<_, RoleAdder>(
|
||||||
|
"
|
||||||
|
INSERT OR REPLACE INTO roles_adder (server, role_a, role_b, role_c)
|
||||||
|
VALUES (?1, ?2, ?3, ?4)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(*server.server.as_u64() as i64)
|
||||||
|
.bind(*server.role_a.as_u64() as i64)
|
||||||
|
.bind(*server.role_b.as_u64() as i64)
|
||||||
|
.bind(*server.role_c.as_u64() as i64)
|
||||||
|
.fetch_optional(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
pub mod list {}
|
||||||
|
|
||||||
|
pub mod tools {
|
||||||
|
use serenity::client::Context;
|
||||||
|
use serenity::model::guild::Member;
|
||||||
|
use skynet_discord_bot::RoleAdder;
|
||||||
|
use sqlx::{Pool, Sqlite};
|
||||||
|
|
||||||
|
pub async fn on_role_change(db: &Pool<Sqlite>, ctx: &Context, mut new_data: Member) {
|
||||||
|
// check if the role changed is part of the oens for this server
|
||||||
|
if let Ok(role_adders) = sqlx::query_as::<_, RoleAdder>(
|
||||||
|
r#"
|
||||||
|
SELECT *
|
||||||
|
FROM roles_adder
|
||||||
|
WHERE server = ?
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(*new_data.guild_id.as_u64() as i64)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
let mut roles_add = vec![];
|
||||||
|
let mut roles_remove = vec![];
|
||||||
|
|
||||||
|
for role_adder in role_adders {
|
||||||
|
// if the user has both A dnd B give them C
|
||||||
|
if new_data.roles.contains(&role_adder.role_a) && new_data.roles.contains(&role_adder.role_b) && !new_data.roles.contains(&role_adder.role_c)
|
||||||
|
{
|
||||||
|
roles_add.push(role_adder.role_c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the suer has C but not A or B remove C
|
||||||
|
if new_data.roles.contains(&role_adder.role_c)
|
||||||
|
&& (!new_data.roles.contains(&role_adder.role_a) || !new_data.roles.contains(&role_adder.role_b))
|
||||||
|
{
|
||||||
|
roles_remove.push(role_adder.role_c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !roles_add.is_empty() {
|
||||||
|
if let Err(e) = new_data.add_roles(&ctx, &roles_add).await {
|
||||||
|
println!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !roles_remove.is_empty() {
|
||||||
|
if let Err(e) = new_data.remove_roles(&ctx, &roles_remove).await {
|
||||||
|
println!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
src/lib.rs
77
src/lib.rs
|
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use serenity::{
|
use serenity::{
|
||||||
model::{
|
model::{
|
||||||
guild,
|
guild,
|
||||||
id::{GuildId, RoleId},
|
id::{ChannelId, GuildId, RoleId},
|
||||||
},
|
},
|
||||||
prelude::TypeMapKey,
|
prelude::TypeMapKey,
|
||||||
};
|
};
|
||||||
|
@ -65,7 +65,7 @@ pub fn get_config() -> Config {
|
||||||
wolves_url: "".to_string(),
|
wolves_url: "".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(x) = env::var("HOME") {
|
if let Ok(x) = env::var("DATABASE_HOME") {
|
||||||
config.home = x.trim().to_string();
|
config.home = x.trim().to_string();
|
||||||
}
|
}
|
||||||
if let Ok(x) = env::var("DATABASE") {
|
if let Ok(x) = env::var("DATABASE") {
|
||||||
|
@ -214,9 +214,13 @@ pub struct Servers {
|
||||||
pub server: GuildId,
|
pub server: GuildId,
|
||||||
pub wolves_api: String,
|
pub wolves_api: String,
|
||||||
pub role_past: Option<RoleId>,
|
pub role_past: Option<RoleId>,
|
||||||
pub role_current: Option<RoleId>,
|
pub role_current: RoleId,
|
||||||
pub member_past: i64,
|
pub member_past: i64,
|
||||||
pub member_current: i64,
|
pub member_current: i64,
|
||||||
|
pub bot_channel_id: ChannelId,
|
||||||
|
// these can be removed in teh future with an API update
|
||||||
|
pub server_name: String,
|
||||||
|
pub wolves_link: String,
|
||||||
}
|
}
|
||||||
impl<'r> FromRow<'r, SqliteRow> for Servers {
|
impl<'r> FromRow<'r, SqliteRow> for Servers {
|
||||||
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||||
|
@ -236,15 +240,14 @@ impl<'r> FromRow<'r, SqliteRow> for Servers {
|
||||||
let role_current = match row.try_get("role_current") {
|
let role_current = match row.try_get("role_current") {
|
||||||
Ok(x) => {
|
Ok(x) => {
|
||||||
let tmp: i64 = x;
|
let tmp: i64 = x;
|
||||||
if tmp == 0 {
|
RoleId::from(tmp as u64)
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(RoleId::from(tmp as u64))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => RoleId::from(0u64),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let bot_channel_tmp: i64 = row.try_get("bot_channel_id")?;
|
||||||
|
let bot_channel_id = ChannelId::from(bot_channel_tmp as u64);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
server,
|
server,
|
||||||
wolves_api: row.try_get("wolves_api")?,
|
wolves_api: row.try_get("wolves_api")?,
|
||||||
|
@ -252,6 +255,9 @@ impl<'r> FromRow<'r, SqliteRow> for Servers {
|
||||||
role_current,
|
role_current,
|
||||||
member_past: row.try_get("member_past")?,
|
member_past: row.try_get("member_past")?,
|
||||||
member_current: row.try_get("member_current")?,
|
member_current: row.try_get("member_current")?,
|
||||||
|
bot_channel_id,
|
||||||
|
server_name: row.try_get("server_name")?,
|
||||||
|
wolves_link: row.try_get("wolves_link")?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,6 +279,37 @@ impl<'r> FromRow<'r, SqliteRow> for Minecraft {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct RoleAdder {
|
||||||
|
pub server: GuildId,
|
||||||
|
pub role_a: RoleId,
|
||||||
|
pub role_b: RoleId,
|
||||||
|
pub role_c: RoleId,
|
||||||
|
}
|
||||||
|
impl<'r> FromRow<'r, SqliteRow> for RoleAdder {
|
||||||
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
||||||
|
let server_tmp: i64 = row.try_get("server")?;
|
||||||
|
let server = GuildId::from(server_tmp as u64);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
server,
|
||||||
|
role_a: get_role_from_row(row, "role_a"),
|
||||||
|
role_b: get_role_from_row(row, "role_b"),
|
||||||
|
role_c: get_role_from_row(row, "role_c"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_role_from_row(row: &SqliteRow, col: &str) -> RoleId {
|
||||||
|
match row.try_get(col) {
|
||||||
|
Ok(x) => {
|
||||||
|
let tmp: i64 = x;
|
||||||
|
RoleId(tmp as u64)
|
||||||
|
}
|
||||||
|
_ => RoleId::from(0u64),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn db_init(config: &Config) -> Result<Pool<Sqlite>, Error> {
|
pub async fn db_init(config: &Config) -> Result<Pool<Sqlite>, Error> {
|
||||||
let database = format!("{}/{}", &config.home, &config.database);
|
let database = format!("{}/{}", &config.home, &config.database);
|
||||||
|
|
||||||
|
@ -286,7 +323,7 @@ pub async fn db_init(config: &Config) -> Result<Pool<Sqlite>, Error> {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// migrations are amazing!
|
// migrations are amazing!
|
||||||
sqlx::migrate!("./db/migrations").run(&pool).await.unwrap();
|
sqlx::migrate!("./db/migrations").run(&pool).await?;
|
||||||
|
|
||||||
Ok(pool)
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
@ -389,11 +426,9 @@ pub mod set_roles {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(role) = &role_current {
|
if !member.roles.contains(role_current) {
|
||||||
if !member.roles.contains(role) {
|
roles_set[1] += 1;
|
||||||
roles_set[1] += 1;
|
roles.push(role_current.to_owned());
|
||||||
roles.push(role.to_owned());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = member.add_roles(ctx, &roles).await {
|
if let Err(e) = member.add_roles(ctx, &roles).await {
|
||||||
|
@ -408,13 +443,11 @@ pub mod set_roles {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(role) = &role_current {
|
if member.roles.contains(role_current) {
|
||||||
if member.roles.contains(role) {
|
roles_set[2] += 1;
|
||||||
roles_set[2] += 1;
|
// if theya re not a current member and have the role then remove it
|
||||||
// if theya re not a current member and have the role then remove it
|
if let Err(e) = member.remove_role(ctx, role_current).await {
|
||||||
if let Err(e) = member.remove_role(ctx, role).await {
|
println!("{:?}", e);
|
||||||
println!("{:?}", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
55
src/main.rs
55
src/main.rs
|
@ -1,25 +1,28 @@
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
|
|
||||||
|
use crate::commands::role_adder::tools::on_role_change;
|
||||||
|
use serenity::model::guild::Member;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
async_trait,
|
async_trait,
|
||||||
client::{Context, EventHandler},
|
client::{Context, EventHandler},
|
||||||
model::{
|
model::{
|
||||||
application::{command::Command, interaction::Interaction},
|
application::{command::Command, interaction::Interaction},
|
||||||
gateway::{GatewayIntents, Ready},
|
gateway::{GatewayIntents, Ready},
|
||||||
guild,
|
prelude::Activity,
|
||||||
|
user::OnlineStatus,
|
||||||
},
|
},
|
||||||
Client,
|
Client,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use skynet_discord_bot::{db_init, get_config, get_server_config, get_server_member, Config, DataBase};
|
use skynet_discord_bot::{db_init, get_config, get_server_config, get_server_member, Config, DataBase};
|
||||||
|
use std::sync::Arc;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
struct Handler;
|
struct Handler;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl EventHandler for Handler {
|
impl EventHandler for Handler {
|
||||||
async fn guild_member_addition(&self, ctx: Context, mut new_member: guild::Member) {
|
// handles previously linked accounts joining the server
|
||||||
|
async fn guild_member_addition(&self, ctx: Context, mut new_member: Member) {
|
||||||
let db_lock = {
|
let db_lock = {
|
||||||
let data_read = ctx.data.read().await;
|
let data_read = ctx.data.read().await;
|
||||||
data_read.get::<DataBase>().expect("Expected Config in TypeMap.").clone()
|
data_read.get::<DataBase>().expect("Expected Config in TypeMap.").clone()
|
||||||
|
@ -40,24 +43,40 @@ impl EventHandler for Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(role) = &config.role_current {
|
if !new_member.roles.contains(&config.role_current) {
|
||||||
if !new_member.roles.contains(role) {
|
roles.push(config.role_current.to_owned());
|
||||||
roles.push(role.to_owned());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = new_member.add_roles(&ctx, &roles).await {
|
if let Err(e) = new_member.add_roles(&ctx, &roles).await {
|
||||||
println!("{:?}", e);
|
println!("{:?}", e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let msg = format!(
|
||||||
|
r#"
|
||||||
|
Welcome {} to the {} server!
|
||||||
|
Sign up on [UL Wolves]({}) and go to https://discord.com/channels/{}/{} and use ``/link_wolves`` to get full access.
|
||||||
|
"#,
|
||||||
|
new_member.display_name(),
|
||||||
|
&config.server_name,
|
||||||
|
&config.wolves_link,
|
||||||
|
&config.server,
|
||||||
|
&config.bot_channel_id
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(err) = new_member.user.direct_message(&ctx, |m| m.content(&msg)).await {
|
||||||
|
dbg!(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ready(&self, ctx: Context, ready: Ready) {
|
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||||
println!("[Main] {} is connected!", ready.user.name);
|
println!("[Main] {} is connected!", ready.user.name);
|
||||||
|
ctx.set_presence(Some(Activity::playing("with humanity's fate")), OnlineStatus::Online).await;
|
||||||
|
|
||||||
match Command::set_global_application_commands(&ctx.http, |commands| {
|
match Command::set_global_application_commands(&ctx.http, |commands| {
|
||||||
commands
|
commands
|
||||||
.create_application_command(|command| commands::add_server::register(command))
|
.create_application_command(|command| commands::add_server::register(command))
|
||||||
|
.create_application_command(|command| commands::role_adder::edit::register(command))
|
||||||
.create_application_command(|command| commands::link_email::link::register(command))
|
.create_application_command(|command| commands::link_email::link::register(command))
|
||||||
.create_application_command(|command| commands::link_email::verify::register(command))
|
.create_application_command(|command| commands::link_email::verify::register(command))
|
||||||
.create_application_command(|command| commands::minecraft::server::add::register(command))
|
.create_application_command(|command| commands::minecraft::server::add::register(command))
|
||||||
|
@ -86,6 +105,7 @@ impl EventHandler for Handler {
|
||||||
"link_minecraft" => commands::minecraft::user::add::run(&command, &ctx).await,
|
"link_minecraft" => commands::minecraft::user::add::run(&command, &ctx).await,
|
||||||
// admin commands
|
// admin commands
|
||||||
"add" => commands::add_server::run(&command, &ctx).await,
|
"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_add" => commands::minecraft::server::add::run(&command, &ctx).await,
|
||||||
"minecraft_list" => commands::minecraft::server::list::run(&command, &ctx).await,
|
"minecraft_list" => commands::minecraft::server::list::run(&command, &ctx).await,
|
||||||
"minecraft_delete" => commands::minecraft::server::delete::run(&command, &ctx).await,
|
"minecraft_delete" => commands::minecraft::server::delete::run(&command, &ctx).await,
|
||||||
|
@ -97,6 +117,20 @@ impl EventHandler for Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handles role updates
|
||||||
|
async fn guild_member_update(&self, ctx: Context, _old_data: Option<Member>, new_data: Member) {
|
||||||
|
// get config/db
|
||||||
|
let db_lock = {
|
||||||
|
let data_read = ctx.data.read().await;
|
||||||
|
data_read.get::<DataBase>().expect("Expected Config in TypeMap.").clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let db = db_lock.read().await;
|
||||||
|
|
||||||
|
// check if the role changed is part of the oens for this server
|
||||||
|
on_role_change(&db, &ctx, new_data).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
@ -104,7 +138,10 @@ async fn main() {
|
||||||
let config = get_config();
|
let config = get_config();
|
||||||
let db = match db_init(&config).await {
|
let db = match db_init(&config).await {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(_) => return,
|
Err(err) => {
|
||||||
|
dbg!(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Intents are a bitflag, bitwise operations can be used to dictate which intents to use
|
// Intents are a bitflag, bitwise operations can be used to dictate which intents to use
|
||||||
|
|
Loading…
Reference in a new issue