fix: make sure that wolves data is pulled in before roles are ran

This commit is contained in:
silver 2023-11-23 21:53:27 +00:00
parent 5745118ede
commit 1e486d7a57
4 changed files with 204 additions and 191 deletions

View file

@ -1,8 +1,4 @@
use skynet_discord_bot::{db_init, get_config, get_server_config_bulk, Config, ServerMembers, Servers, Wolves}; use skynet_discord_bot::{db_init, get_config, get_data::get_wolves};
use serde::{Deserialize, Serialize};
use serenity::model::id::GuildId;
use sqlx::{Pool, Sqlite};
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@ -15,109 +11,3 @@ async fn main() {
// handle wolves api here // handle wolves api here
get_wolves(&db, &config).await; get_wolves(&db, &config).await;
} }
#[derive(Deserialize, Serialize, Debug)]
struct WolvesResultUser {
committee: String,
wolves_id: String,
first_name: String,
last_name: String,
contact_email: String,
student_id: Option<String>,
note: Option<String>,
expiry: String,
requested: String,
approved: String,
sitename: String,
domain: String,
}
#[derive(Deserialize, Serialize, Debug)]
struct WolvesResult {
success: i8,
result: Vec<WolvesResultUser>,
}
#[derive(Deserialize, Serialize, Debug)]
struct WolvesResultLocal {
pub id_wolves: String,
pub email: String,
pub expiry: String,
}
async fn get_wolves(db: &Pool<Sqlite>, config: &Config) {
for server_config in get_server_config_bulk(db).await {
let Servers {
server,
wolves_api,
..
} = server_config;
for user in get_wolves_sub(config, &wolves_api).await {
add_users_wolves(db, &server, &user).await;
}
}
}
async fn get_wolves_sub(config: &Config, wolves_api: &str) -> Vec<WolvesResultUser> {
if config.wolves_url.is_empty() {
return vec![];
}
// get wolves data
if let Ok(mut res) = surf::post(&config.wolves_url).header("X-AM-Identity", wolves_api).await {
if let Ok(WolvesResult {
success,
result,
}) = res.body_json().await
{
if success != 1 {
return vec![];
}
return result;
}
}
vec![]
}
async fn add_users_wolves(db: &Pool<Sqlite>, server: &GuildId, user: &WolvesResultUser) {
// expiry
match sqlx::query_as::<_, Wolves>(
"
INSERT INTO wolves (id_wolves, email)
VALUES ($1, $2)
ON CONFLICT(id_wolves) DO UPDATE SET email = $2
",
)
.bind(&user.wolves_id)
.bind(&user.contact_email)
.fetch_optional(db)
.await
{
Ok(_) => {}
Err(e) => {
println!("Failure to insert into Wolves {:?}", user);
println!("{:?}", e);
}
}
match sqlx::query_as::<_, ServerMembers>(
"
INSERT OR REPLACE INTO server_members (server, id_wolves, expiry)
VALUES (?1, ?2, ?3)
",
)
.bind(*server.as_u64() as i64)
.bind(&user.wolves_id)
.bind(&user.expiry)
.fetch_optional(db)
.await
{
Ok(_) => {}
Err(e) => {
println!("Failure to insert into ServerMembers {} {:?}", server.as_u64(), user);
println!("{:?}", e);
}
}
}

View file

@ -4,7 +4,7 @@ use serenity::{
model::gateway::{GatewayIntents, Ready}, model::gateway::{GatewayIntents, Ready},
Client, Client,
}; };
use skynet_discord_bot::{db_init, get_config, get_server_config_bulk, update_server, Config, DataBase}; use skynet_discord_bot::{db_init, get_config, get_server_config_bulk, set_roles::update_server, Config, DataBase};
use std::{process, sync::Arc}; use std::{process, sync::Arc};
use tokio::sync::RwLock; use tokio::sync::RwLock;

View file

@ -6,7 +6,8 @@ use serenity::{
prelude::{command::CommandOptionType, interaction::application_command::CommandDataOptionValue}, prelude::{command::CommandOptionType, interaction::application_command::CommandDataOptionValue},
}, },
}; };
use skynet_discord_bot::{get_server_config, update_server, DataBase, Servers}; use skynet_discord_bot::get_data::get_wolves;
use skynet_discord_bot::{get_server_config, set_roles::update_server, Config, DataBase, Servers};
use sqlx::{Error, Pool, Sqlite}; use sqlx::{Error, Pool, Sqlite};
pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String { pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String {
@ -172,6 +173,15 @@ async fn add_server(db: &Pool<Sqlite>, ctx: &Context, server: &Servers) -> Resul
// update all users // update all users
if update { if update {
let config_lock = {
let data_read = ctx.data.read().await;
data_read.get::<Config>().expect("Expected Config in TypeMap.").clone()
};
let config = config_lock.read().await;
// handle wolves api here
get_wolves(db, &config).await;
let mut roles_remove = vec![]; let mut roles_remove = vec![];
if current_remove { if current_remove {
roles_remove.push(current_role) roles_remove.push(current_role)

View file

@ -379,82 +379,84 @@ pub fn random_string(len: usize) -> String {
thread_rng().sample_iter(&Alphanumeric).take(len).map(char::from).collect() thread_rng().sample_iter(&Alphanumeric).take(len).map(char::from).collect()
} }
pub async fn update_server(db: &Pool<Sqlite>, ctx: &Context, server: &Servers, remove_roles: &[Option<RoleId>]) { pub mod set_roles {
let Servers { use super::*;
server, pub async fn update_server(db: &Pool<Sqlite>, ctx: &Context, server: &Servers, remove_roles: &[Option<RoleId>]) {
role_past, let Servers {
role_current, server,
.. role_past,
} = server; role_current,
..
} = server;
let mut roles_set = [0, 0, 0]; let mut roles_set = [0, 0, 0];
let mut members = vec![]; let mut members = vec![];
for member in get_server_member_bulk(db, server).await { for member in get_server_member_bulk(db, server).await {
if let Some(x) = member.discord { if let Some(x) = member.discord {
members.push(x); members.push(x);
}
} }
} let mut members_all = members.len();
let mut members_all = members.len();
if let Ok(x) = server.members(ctx, None, None).await { if let Ok(x) = server.members(ctx, None, None).await {
for mut member in x { for mut member in x {
if members.contains(&member.user.id) { if members.contains(&member.user.id) {
let mut roles = vec![]; let mut roles = vec![];
if let Some(role) = &role_past { if let Some(role) = &role_past {
if !member.roles.contains(role) { if !member.roles.contains(role) {
roles_set[0] += 1; roles_set[0] += 1;
roles.push(role.to_owned()); roles.push(role.to_owned());
}
} }
}
if let Some(role) = &role_current { if let Some(role) = &role_current {
if !member.roles.contains(role) { if !member.roles.contains(role) {
roles_set[1] += 1; roles_set[1] += 1;
roles.push(role.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 {
println!("{:?}", e); println!("{:?}", e);
}
} else {
// old and never
if let Some(role) = &role_past {
if member.roles.contains(role) {
members_all += 1;
} }
} } else {
// old and never
if let Some(role) = &role_current { if let Some(role) = &role_past {
if member.roles.contains(role) { if member.roles.contains(role) {
roles_set[2] += 1; members_all += 1;
// if theya re not a current member and have the role then remove it }
if let Err(e) = member.remove_role(ctx, role).await { }
println!("{:?}", e);
if let Some(role) = &role_current {
if member.roles.contains(role) {
roles_set[2] += 1;
// if theya re not a current member and have the role then remove it
if let Err(e) = member.remove_role(ctx, role).await {
println!("{:?}", e);
}
} }
} }
} }
} for role in remove_roles.iter().flatten() {
for role in remove_roles.iter().flatten() { if let Err(e) = member.remove_role(ctx, role).await {
if let Err(e) = member.remove_role(ctx, role).await { println!("{:?}", e);
println!("{:?}", e); }
} }
} }
} }
set_server_numbers(db, server, members_all as i64, members.len() as i64).await;
// small bit of logging to note changes over time
println!("{:?} Changes: New: +{}, Current: +{}/-{}", server.as_u64(), roles_set[0], roles_set[1], roles_set[2]);
} }
set_server_numbers(db, server, members_all as i64, members.len() as i64).await; async fn get_server_member_bulk(db: &Pool<Sqlite>, server: &GuildId) -> Vec<ServerMembersWolves> {
sqlx::query_as::<_, ServerMembersWolves>(
// small bit of logging to note changes over time r#"
println!("{:?} Changes: New: +{}, Current: +{}/-{}", server.as_u64(), roles_set[0], roles_set[1], roles_set[2]);
}
async fn get_server_member_bulk(db: &Pool<Sqlite>, server: &GuildId) -> Vec<ServerMembersWolves> {
sqlx::query_as::<_, ServerMembersWolves>(
r#"
SELECT * SELECT *
FROM server_members FROM server_members
JOIN wolves USING (id_wolves) JOIN wolves USING (id_wolves)
@ -464,32 +466,143 @@ async fn get_server_member_bulk(db: &Pool<Sqlite>, server: &GuildId) -> Vec<Serv
AND expiry > ? AND expiry > ?
) )
"#, "#,
) )
.bind(*server.as_u64() as i64) .bind(*server.as_u64() as i64)
.bind(get_now_iso(true)) .bind(get_now_iso(true))
.fetch_all(db) .fetch_all(db)
.await .await
.unwrap_or_default() .unwrap_or_default()
} }
async fn set_server_numbers(db: &Pool<Sqlite>, server: &GuildId, past: i64, current: i64) { async fn set_server_numbers(db: &Pool<Sqlite>, server: &GuildId, past: i64, current: i64) {
match sqlx::query_as::<_, Wolves>( match sqlx::query_as::<_, Wolves>(
" "
UPDATE servers UPDATE servers
SET member_past = ?, member_current = ? SET member_past = ?, member_current = ?
WHERE server = ? WHERE server = ?
", ",
) )
.bind(past) .bind(past)
.bind(current) .bind(current)
.bind(*server.as_u64() as i64) .bind(*server.as_u64() as i64)
.fetch_optional(db) .fetch_optional(db)
.await .await
{ {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
println!("Failure to insert into {}", server.as_u64()); println!("Failure to insert into {}", server.as_u64());
println!("{:?}", e); println!("{:?}", e);
}
}
}
}
pub mod get_data {
use super::*;
#[derive(Deserialize, Serialize, Debug)]
struct WolvesResultUser {
committee: String,
wolves_id: String,
first_name: String,
last_name: String,
contact_email: String,
student_id: Option<String>,
note: Option<String>,
expiry: String,
requested: String,
approved: String,
sitename: String,
domain: String,
}
#[derive(Deserialize, Serialize, Debug)]
struct WolvesResult {
success: i8,
result: Vec<WolvesResultUser>,
}
#[derive(Deserialize, Serialize, Debug)]
struct WolvesResultLocal {
pub id_wolves: String,
pub email: String,
pub expiry: String,
}
pub async fn get_wolves(db: &Pool<Sqlite>, config: &Config) {
for server_config in get_server_config_bulk(db).await {
let Servers {
server,
wolves_api,
..
} = server_config;
for user in get_wolves_sub(config, &wolves_api).await {
add_users_wolves(db, &server, &user).await;
}
}
}
async fn get_wolves_sub(config: &Config, wolves_api: &str) -> Vec<WolvesResultUser> {
if config.wolves_url.is_empty() {
return vec![];
}
// get wolves data
if let Ok(mut res) = surf::post(&config.wolves_url).header("X-AM-Identity", wolves_api).await {
if let Ok(WolvesResult {
success,
result,
}) = res.body_json().await
{
if success != 1 {
return vec![];
}
return result;
}
}
vec![]
}
async fn add_users_wolves(db: &Pool<Sqlite>, server: &GuildId, user: &WolvesResultUser) {
// expiry
match sqlx::query_as::<_, Wolves>(
"
INSERT INTO wolves (id_wolves, email)
VALUES ($1, $2)
ON CONFLICT(id_wolves) DO UPDATE SET email = $2
",
)
.bind(&user.wolves_id)
.bind(&user.contact_email)
.fetch_optional(db)
.await
{
Ok(_) => {}
Err(e) => {
println!("Failure to insert into Wolves {:?}", user);
println!("{:?}", e);
}
}
match sqlx::query_as::<_, ServerMembers>(
"
INSERT OR REPLACE INTO server_members (server, id_wolves, expiry)
VALUES (?1, ?2, ?3)
",
)
.bind(*server.as_u64() as i64)
.bind(&user.wolves_id)
.bind(&user.expiry)
.fetch_optional(db)
.await
{
Ok(_) => {}
Err(e) => {
println!("Failure to insert into ServerMembers {} {:?}", server.as_u64(), user);
println!("{:?}", e);
}
} }
} }
} }