feat: now store the roles and channel ids in teh database

This commit is contained in:
silver 2025-02-27 01:19:40 +00:00
parent 6a5f651ba2
commit 555e38ee26
Signed by: silver
GPG key ID: 36F93D61BAD3FD7D
3 changed files with 209 additions and 83 deletions

View file

@ -0,0 +1,10 @@
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
);

View file

@ -190,14 +190,28 @@ impl<'r> FromRow<'r, SqliteRow> for RoleAdder {
}
}
fn get_role_from_row(row: &SqliteRow, col: &str) -> RoleId {
match row.try_get(col) {
pub(crate) fn get_role_from_row(row: &SqliteRow, col: &str) -> RoleId {
let id = match row.try_get(col) {
Ok(x) => {
let tmp: i64 = x;
RoleId::new(tmp as u64)
tmp as u64
}
_ => RoleId::from(0u64),
}
_ => 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)
}
pub async fn db_init(config: &Config) -> Result<Pool<Sqlite>, Error> {

View file

@ -131,9 +131,10 @@ pub mod normal {
// for updating committee members
pub mod committee {
use crate::common::database::{DataBase, Wolves};
use crate::common::database::{get_channel_from_row, get_role_from_row, 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;
@ -141,7 +142,8 @@ pub mod committee {
use serenity::model::guild::Member;
use serenity::model::id::ChannelId;
use serenity::model::prelude::RoleId;
use sqlx::{Pool, Sqlite};
use sqlx::sqlite::SqliteRow;
use sqlx::{Error, FromRow, Pool, Row, Sqlite};
use std::collections::HashMap;
use std::sync::Arc;
@ -174,8 +176,7 @@ pub mod committee {
let server = config.committee_server;
let committee_member = RoleId::new(1226602779968274573);
let committees = get_committees(db).await;
let categories = vec![
// C&S Chats 1
let categories = [
ChannelId::new(1226606560973815839),
// C&S Chats 2
ChannelId::new(1341457244973305927),
@ -184,35 +185,30 @@ pub mod committee {
];
// information about the server
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 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 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());
}
}
}
}
let mut channels = server.channels(&ctx).await.unwrap_or_default();
// a map of users and the roles they are goign to be getting
let mut users_roles = HashMap::new();
// 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 re_order = false;
// we need to create roles and channels if tehy dont already exist
let mut category_index = 0;
let mut i = 0;
loop {
if i >= committees.len() {
@ -220,24 +216,17 @@ pub mod committee {
}
let committee = &committees[i];
// 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,
}
}
};
// create teh channel if it does nto exist
if !channels_name.contains_key(&committee.name_profile) {
match server
// if a club/soc ever changes their name
if let Some(x) = roles_db.get_mut(&committee.id) {
x.name_role = committee.name_full.to_owned();
x.name_channel = committee.name_profile.to_owned();
}
// 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_channel(
&ctx,
CreateChannel::new(&committee.name_profile)
@ -247,40 +236,72 @@ pub mod committee {
.await
{
Ok(x) => {
// update teh channels name list
channels_name.insert(x.name.to_owned(), x.to_owned());
println!("Created channel: {}", &committee.name_profile);
x.id
}
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;
}
dbg!("Unable to create channel: ", &tmp, &tmp.contains("Maximum number of channels in category reached (50)"));
ChannelId::new(1)
}
}
};
// 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;
};
// so if the role exists
if let Some(r) = role {
committee_roles.push(r.id);
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![]);
values.push(r);
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![]);
values.push(r.id);
if let Some(x) = roles_db.get_mut(&committee.id) {
x.count += 1;
}
}
}
}
i += 1;
}
// now we have a map of all users that should get roles time to go through all the folks on teh server
@ -315,6 +336,10 @@ 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 {
@ -335,33 +360,110 @@ pub mod committee {
}
}
// 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();
let mut channel_names = vec![];
for role in roles_db.values() {
// save these to db
db_role_set(db, role).await;
// 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));
}
// pull out teh channel names
if re_order {
channel_names.push((role.name_channel.to_owned(), role.id_channel));
}
}
if !new_positions.is_empty() {
match server.reorder_channels(&ctx, new_positions).await {
Ok(_) => {
println!("Successfully re-orderd the committee category");
if re_order {
channel_names.sort_by_key(|(name, _)| name.to_owned());
// get a list of all teh new positions
let mut new_positions = vec![];
for (i, (_, id)) in channel_names.iter().enumerate() {
if let Some(channel) = channels.get_mut(id) {
let position_new = i as u64;
if position_new != channel.position as u64 {
new_positions.push((channel.id.to_owned(), position_new));
}
}
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)]
struct CommitteeRoles {
id_wolves: i64,
id_role: RoleId,
id_channel: ChannelId,
name_role: String,
name_channel: String,
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 = $4, 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);
}
}
}
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![]
})
}
async fn get_committees(db: &Pool<Sqlite>) -> Vec<Committees> {
sqlx::query_as::<_, Committees>(
r#"