discord-bot/src/common/wolves.rs

279 lines
7.7 KiB
Rust
Raw Normal View History

2024-10-28 21:53:04 +00:00
use crate::common::database::Wolves;
use serde::{Deserialize, Serialize};
use sqlx::{Pool, Sqlite};
/**
2024-10-28 21:53:04 +00:00
This file relates to anything that directly interacts with teh wolves API
*/
#[derive(Deserialize, Serialize, Debug)]
struct WolvesResultUserMin {
// committee: String,
member_id: String,
// first_name: String,
// last_name: String,
contact_email: String,
// opt_in_email: String,
// student_id: Option<String>,
// note: Option<String>,
// expiry: String,
// requested: String,
// approved: String,
// sitename: String,
// domain: String,
}
async fn add_users_wolves(db: &Pool<Sqlite>, user: &WolvesResultUserMin) {
// expiry
match sqlx::query_as::<_, Wolves>(
"
INSERT INTO wolves (id_wolves, email)
VALUES ($1, $2)
ON CONFLICT(id_wolves) DO UPDATE SET email = $2
",
)
2024-10-28 21:53:04 +00:00
.bind(&user.member_id)
.bind(&user.contact_email)
.fetch_optional(db)
.await
{
Ok(_) => {}
Err(e) => {
println!("Failure to insert into Wolves {:?}", user);
println!("{:?}", e);
}
}
}
/**
This is getting data for Clubs and Socs
*/
pub mod cns {
2024-10-28 21:53:04 +00:00
use crate::common::database::{get_server_config_bulk, DataBase, ServerMembers, ServerMembersWolves, Servers};
use crate::common::set_roles::normal::update_server;
2024-10-28 21:53:04 +00:00
use crate::common::wolves::{add_users_wolves, WolvesResultUserMin};
use crate::Config;
use serenity::client::Context;
use serenity::model::id::GuildId;
use sqlx::{Pool, Sqlite};
2024-10-28 21:53:04 +00:00
use std::collections::BTreeMap;
impl From<&wolves_oxidised::WolvesUser> for WolvesResultUserMin {
fn from(value: &wolves_oxidised::WolvesUser) -> Self {
Self {
member_id: value.member_id.to_owned(),
contact_email: value.contact_email.to_owned(),
}
}
}
pub async fn get_wolves(ctx: &Context) {
let db_lock = {
let data_read = ctx.data.read().await;
data_read.get::<DataBase>().expect("Expected Database in TypeMap.").clone()
};
let db = db_lock.read().await;
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;
// set up teh client
let wolves = wolves_oxidised::Client::new(&config.wolves_url, Some(&config.wolves_api));
for server_config in get_server_config_bulk(&db).await {
let Servers {
server,
// this is the unique api key for each club/soc
wolves_api,
server_name,
..
} = &server_config;
// dbg!(&server_config);
let existing_tmp = get_server_member(&db, server).await;
let existing = existing_tmp.iter().map(|data| (data.id_wolves, data)).collect::<BTreeMap<_, _>>();
// list of users that need to be updated for this server
let mut user_to_update = vec![];
let mut server_name_tmp = None;
for user in wolves.get_members(wolves_api).await {
// dbg!(&user.committee);
if server_name_tmp.is_none() {
server_name_tmp = Some(user.committee.to_owned());
}
let id = user.member_id.parse::<u64>().unwrap_or_default();
match existing.get(&(id as i64)) {
None => {
// user does not exist already, add everything
add_users_wolves(&db, &WolvesResultUserMin::from(&user)).await;
add_users_server_members(&db, server, &user).await;
}
Some(old) => {
// always update wolves table, in case data has changed
add_users_wolves(&db, &WolvesResultUserMin::from(&user)).await;
if old.expiry != user.expiry {
add_users_server_members(&db, server, &user).await;
if let Some(discord_id) = old.discord {
user_to_update.push(discord_id);
}
}
}
}
}
if let Some(name) = server_name_tmp {
if &name != server_name {
set_server_member(&db, server, &name).await;
}
}
if !user_to_update.is_empty() {
update_server(ctx, &server_config, &[], &user_to_update).await;
}
}
}
async fn set_server_member(db: &Pool<Sqlite>, server: &GuildId, name: &str) {
match sqlx::query_as::<_, Servers>(
"
UPDATE servers
SET server_name = ?
WHERE server = ?
",
)
.bind(name)
.bind(server.get() as i64)
.fetch_optional(db)
.await
{
Ok(_) => {}
Err(e) => {
println!("Failure to set server name {}", server.get());
println!("{:?}", e);
}
}
}
async fn get_server_member(db: &Pool<Sqlite>, server: &GuildId) -> Vec<ServerMembersWolves> {
sqlx::query_as::<_, ServerMembersWolves>(
r#"
SELECT *
FROM server_members
JOIN wolves USING (id_wolves)
WHERE (
server = ?
AND discord IS NOT NULL
)
"#,
)
.bind(server.get() as i64)
.fetch_all(db)
.await
.unwrap_or_default()
}
async fn add_users_server_members(db: &Pool<Sqlite>, server: &GuildId, user: &wolves_oxidised::WolvesUser) {
match sqlx::query_as::<_, ServerMembers>(
"
INSERT OR REPLACE INTO server_members (server, id_wolves, expiry)
VALUES (?1, ?2, ?3)
",
)
.bind(server.get() as i64)
.bind(&user.member_id)
.bind(&user.expiry)
.fetch_optional(db)
.await
{
Ok(_) => {}
Err(e) => {
println!("Failure to insert into ServerMembers {} {:?}", server.get(), user);
println!("{:?}", e);
}
}
}
}
/**
Get and store the data on C&S committees
*/
pub mod committees {
2024-10-28 21:53:04 +00:00
use crate::common::database::DataBase;
use crate::Config;
use serenity::client::Context;
2024-10-28 21:53:04 +00:00
use sqlx::{Pool, Sqlite};
// Database entry for it
#[derive(Debug, Clone, sqlx::FromRow)]
pub struct Committees {
2024-10-28 21:53:04 +00:00
pub id: i64,
2025-02-18 13:36:08 +00:00
pub name_full: String,
pub name_profile: String,
pub name_plain: String,
2024-10-28 21:53:04 +00:00
pub link: String,
#[sqlx(json)]
pub committee: Vec<i64>,
}
impl From<wolves_oxidised::WolvesCNS> for Committees {
fn from(value: wolves_oxidised::WolvesCNS) -> Self {
2024-10-28 21:53:04 +00:00
Self {
2025-02-18 13:36:08 +00:00
id: value.id,
name_full: value.name_full,
name_profile: value.name_profile,
name_plain: value.name_plain,
link: value.link,
2025-02-18 13:36:08 +00:00
committee: value.committee,
}
}
}
2024-10-28 21:53:04 +00:00
pub async fn get_cns(ctx: &Context) {
let db_lock = {
let data_read = ctx.data.read().await;
data_read.get::<DataBase>().expect("Expected Database in TypeMap.").clone()
};
let db = db_lock.read().await;
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;
let wolves = wolves_oxidised::Client::new(&config.wolves_url, Some(&config.wolves_api));
// request data from wolves
for committee_wolves in wolves.get_committees().await {
let committee = Committees::from(committee_wolves);
add_committee(&db, &committee).await;
}
}
async fn add_committee(db: &Pool<Sqlite>, committee: &Committees) {
match sqlx::query_as::<_, Committees>(
"
INSERT INTO committees (id, name_profile, name_full, name_plain, link, committee)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT(id) DO UPDATE SET committee = $6
",
)
2024-10-28 21:53:04 +00:00
.bind(committee.id)
2025-02-18 13:36:08 +00:00
.bind(&committee.name_profile)
.bind(&committee.name_full)
.bind(&committee.name_plain)
2024-10-28 21:53:04 +00:00
.bind(&committee.link)
.bind(serde_json::to_string(&committee.committee).unwrap_or_default())
.fetch_optional(db)
.await
{
Ok(_) => {}
Err(e) => {
println!("Failure to insert into Committees {:?}", committee);
println!("{:?}", e);
}
}
}
}