2023-09-24 00:56:20 +00:00
|
|
|
use crate::{Data, Error};
|
2024-01-24 04:05:34 +00:00
|
|
|
use poise::serenity_prelude::{
|
|
|
|
self as serenity, CreateActionRow, CreateButton, CreateEmbed, CreateInteractionResponse,
|
|
|
|
CreateInteractionResponseMessage, CreateMessage,
|
|
|
|
};
|
2023-09-24 00:56:20 +00:00
|
|
|
use poise::Modal;
|
|
|
|
|
|
|
|
const MANUAL_INTRO: &str = indoc::indoc! {"
|
|
|
|
Submit details to be manually checked by a committee member:
|
|
|
|
- Your Imperial Shortcode
|
|
|
|
- Your First and Last Names as on your Imperial record
|
|
|
|
- Preferred First and Last Names for the Nano whois command
|
|
|
|
- URL to proof of being an Imperial student, e.g. photo of College ID Card \
|
|
|
|
or screenshot of College Acceptance Letter, if you need to upload this, \
|
|
|
|
you can send it in a DM and then copy the image URL
|
|
|
|
|
|
|
|
We try to respond quickly but this may take a day or two during busy term times :)
|
|
|
|
|
|
|
|
First, are you a fresher?
|
|
|
|
"};
|
|
|
|
|
2023-09-29 00:06:37 +00:00
|
|
|
#[tracing::instrument(skip_all)]
|
2023-09-24 00:56:20 +00:00
|
|
|
pub(crate) async fn manual_1(
|
|
|
|
ctx: &serenity::Context,
|
2024-01-24 04:05:34 +00:00
|
|
|
m: &serenity::ComponentInteraction,
|
2023-09-24 00:56:20 +00:00
|
|
|
) -> Result<(), Error> {
|
2024-01-24 04:05:34 +00:00
|
|
|
m.create_response(
|
|
|
|
&ctx.http,
|
|
|
|
CreateInteractionResponse::UpdateMessage(
|
|
|
|
CreateInteractionResponseMessage::new()
|
|
|
|
.content(MANUAL_INTRO)
|
|
|
|
.components(vec![CreateActionRow::Buttons(vec![
|
|
|
|
CreateButton::new("restart")
|
|
|
|
.style(serenity::ButtonStyle::Danger)
|
|
|
|
.emoji('🔙'),
|
|
|
|
CreateButton::new("manual_2f")
|
|
|
|
.style(serenity::ButtonStyle::Success)
|
|
|
|
.emoji('✅')
|
|
|
|
.label("Fresher"),
|
|
|
|
CreateButton::new("manual_2n")
|
|
|
|
.style(serenity::ButtonStyle::Primary)
|
|
|
|
.emoji('❌')
|
|
|
|
.label("Non-fresher"),
|
|
|
|
])]),
|
|
|
|
),
|
|
|
|
)
|
2023-09-24 00:56:20 +00:00
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Modal)]
|
|
|
|
#[name = "Manual Verification"]
|
|
|
|
struct Manual {
|
|
|
|
#[name = "Imperial Shortcode"]
|
|
|
|
#[placeholder = "ab1234"]
|
|
|
|
shortcode: String,
|
|
|
|
#[name = "Name as on Imperial record"]
|
|
|
|
#[placeholder = "Firstname Lastname"]
|
|
|
|
realname: String,
|
|
|
|
#[name = "URL to proof image"]
|
|
|
|
#[placeholder = "E.g. photo of College ID Card \
|
|
|
|
or screenshot of College Acceptance Letter"]
|
|
|
|
url: String,
|
|
|
|
#[name = "Preferred name for Nano whois commands"]
|
|
|
|
#[placeholder = "Firstname Lastname"]
|
|
|
|
nickname: String,
|
|
|
|
}
|
|
|
|
|
2023-09-29 00:06:37 +00:00
|
|
|
#[tracing::instrument(skip_all)]
|
2023-09-24 00:56:20 +00:00
|
|
|
pub(crate) async fn manual_2(
|
|
|
|
ctx: &serenity::Context,
|
2024-01-24 04:05:34 +00:00
|
|
|
m: &serenity::ComponentInteraction,
|
2023-09-24 00:56:20 +00:00
|
|
|
data: &Data,
|
|
|
|
fresher: bool,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
// Delete from manual if exists
|
2023-09-25 11:36:01 +00:00
|
|
|
let _ = crate::db::delete_manual_by_id(&data.db, m.user.id.into()).await;
|
2023-09-24 00:56:20 +00:00
|
|
|
|
2024-01-24 04:05:34 +00:00
|
|
|
m.create_response(
|
|
|
|
&ctx.http,
|
|
|
|
Manual::create(
|
2023-09-24 00:56:20 +00:00
|
|
|
None,
|
|
|
|
if fresher {
|
|
|
|
"manual_3f".to_string()
|
|
|
|
} else {
|
|
|
|
"manual_3n".to_string()
|
|
|
|
},
|
2024-01-24 04:05:34 +00:00
|
|
|
),
|
|
|
|
)
|
2023-09-24 00:56:20 +00:00
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-09-29 00:06:37 +00:00
|
|
|
#[tracing::instrument(skip_all)]
|
2023-09-24 00:56:20 +00:00
|
|
|
pub(crate) async fn manual_3(
|
|
|
|
ctx: &serenity::Context,
|
2024-01-24 04:05:34 +00:00
|
|
|
m: &serenity::ModalInteraction,
|
2023-09-24 00:56:20 +00:00
|
|
|
data: &Data,
|
|
|
|
fresher: bool,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
match Manual::parse(m.data.clone()) {
|
|
|
|
Ok(Manual {
|
|
|
|
shortcode,
|
|
|
|
realname,
|
|
|
|
url,
|
|
|
|
nickname,
|
|
|
|
}) => {
|
|
|
|
if ::url::Url::parse(&url).is_err() {
|
2024-01-24 04:05:34 +00:00
|
|
|
m.create_response(
|
|
|
|
&ctx.http,
|
|
|
|
CreateInteractionResponse::Message(
|
|
|
|
CreateInteractionResponseMessage::new()
|
|
|
|
.content("The url provided is invalid, please try again")
|
|
|
|
.ephemeral(true),
|
|
|
|
),
|
|
|
|
)
|
2023-09-24 00:56:20 +00:00
|
|
|
.await?;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete from pending if exists
|
2023-09-25 11:36:01 +00:00
|
|
|
let _ = crate::db::delete_pending_by_id(&data.db, m.user.id.into()).await?;
|
2023-09-24 00:56:20 +00:00
|
|
|
|
|
|
|
let prompt_sent = data
|
|
|
|
.au_ch_id
|
2024-01-24 04:05:34 +00:00
|
|
|
.send_message(
|
|
|
|
&ctx.http,
|
|
|
|
CreateMessage::new()
|
|
|
|
.embed(
|
|
|
|
CreateEmbed::new()
|
|
|
|
.title("New verification request from")
|
|
|
|
.thumbnail(m.user.avatar_url().unwrap_or(super::AVATAR.to_string()))
|
|
|
|
.description(m.user.to_string())
|
|
|
|
.field("Real Name (To be checked)", &realname, true)
|
|
|
|
.field("Imperial Shortcode (To be checked", &shortcode, true)
|
|
|
|
.field("Fresher (To be checked)", fresher.to_string(), true)
|
|
|
|
.field("Nickname (Nano whois commands)", &nickname, true)
|
|
|
|
.field("Verification URL (Also displayed below)", &url, true)
|
|
|
|
.image(&url)
|
|
|
|
.timestamp(serenity::Timestamp::now()),
|
|
|
|
)
|
|
|
|
.components(vec![CreateActionRow::Buttons(vec![
|
|
|
|
CreateButton::new(format!("verify-y-{}", m.user.id))
|
|
|
|
.style(serenity::ButtonStyle::Success)
|
|
|
|
.emoji('✅')
|
|
|
|
.label("Accept"),
|
|
|
|
CreateButton::new(format!("verify-n-{}", m.user.id))
|
|
|
|
.style(serenity::ButtonStyle::Danger)
|
|
|
|
.emoji('❎')
|
|
|
|
.label("Deny"),
|
|
|
|
])]),
|
|
|
|
)
|
2023-09-24 00:56:20 +00:00
|
|
|
.await
|
|
|
|
.is_ok();
|
|
|
|
|
|
|
|
let inserted = crate::db::insert_manual(
|
|
|
|
&data.db,
|
|
|
|
crate::ManualMember {
|
2023-09-25 11:36:01 +00:00
|
|
|
discord_id: m.user.id.into(),
|
2023-09-24 00:56:20 +00:00
|
|
|
shortcode,
|
|
|
|
nickname,
|
|
|
|
realname,
|
|
|
|
fresher,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
.is_ok();
|
|
|
|
|
|
|
|
let msg = if prompt_sent {
|
|
|
|
if inserted {
|
|
|
|
"Thanks, your verification request has been sent, we'll try to get back to you quickly!"
|
|
|
|
} else {
|
|
|
|
"Thanks, your verification request has been sent, but there was an issue, please ask a Committee member to take a look!"
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
"Sending your verification request failed, please try again."
|
|
|
|
};
|
|
|
|
|
2024-01-24 04:05:34 +00:00
|
|
|
m.create_response(
|
|
|
|
&ctx.http,
|
|
|
|
CreateInteractionResponse::UpdateMessage(
|
|
|
|
CreateInteractionResponseMessage::new()
|
|
|
|
.content(msg)
|
|
|
|
.components(vec![]),
|
|
|
|
),
|
|
|
|
)
|
2023-09-24 00:56:20 +00:00
|
|
|
.await?;
|
|
|
|
return Ok(());
|
|
|
|
}
|
2023-09-29 00:06:37 +00:00
|
|
|
Err(e) => tracing::error!("{e}"),
|
2023-09-24 00:56:20 +00:00
|
|
|
};
|
2024-01-24 04:05:34 +00:00
|
|
|
m.create_response(
|
|
|
|
&ctx.http,
|
|
|
|
CreateInteractionResponse::Message(
|
|
|
|
CreateInteractionResponseMessage::new()
|
|
|
|
.content("Sorry, something went wrong. Please try again")
|
|
|
|
.ephemeral(true),
|
|
|
|
),
|
|
|
|
)
|
2023-09-24 00:56:20 +00:00
|
|
|
.await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-09-29 00:06:37 +00:00
|
|
|
#[tracing::instrument(skip_all)]
|
2023-09-24 00:56:20 +00:00
|
|
|
pub(crate) async fn manual_4(
|
|
|
|
ctx: &serenity::Context,
|
2024-01-24 04:05:34 +00:00
|
|
|
m: &serenity::ComponentInteraction,
|
2023-09-24 00:56:20 +00:00
|
|
|
data: &Data,
|
|
|
|
id: &str,
|
|
|
|
) -> Result<(), Error> {
|
2023-09-25 12:23:32 +00:00
|
|
|
let verify = matches!(id.chars().nth(7), Some('y'));
|
2023-09-24 00:56:20 +00:00
|
|
|
let user = id
|
|
|
|
.chars()
|
|
|
|
.skip(9)
|
|
|
|
.collect::<String>()
|
|
|
|
.parse::<u64>()
|
2024-01-24 04:05:34 +00:00
|
|
|
.map(serenity::UserId::new)
|
2023-09-24 00:56:20 +00:00
|
|
|
.unwrap_or_default()
|
|
|
|
.to_user(ctx)
|
|
|
|
.await
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
2023-09-24 15:04:28 +00:00
|
|
|
let mut member = data.server.member(&ctx.http, &user).await?;
|
|
|
|
|
2023-09-24 13:50:14 +00:00
|
|
|
if verify {
|
2023-09-25 11:36:01 +00:00
|
|
|
match crate::db::insert_member_from_manual(&data.db, user.id.into()).await {
|
2023-11-11 17:32:27 +00:00
|
|
|
Ok(mm) => {
|
2023-09-25 11:36:01 +00:00
|
|
|
let fresher = crate::db::get_member_by_id(&data.db, user.id.into())
|
2023-09-24 13:50:14 +00:00
|
|
|
.await?
|
|
|
|
.unwrap()
|
|
|
|
.fresher;
|
2023-09-29 00:06:37 +00:00
|
|
|
tracing::info!(
|
2023-09-24 15:04:28 +00:00
|
|
|
"{} ({}) added via manual{}",
|
|
|
|
user.name,
|
|
|
|
user.id,
|
|
|
|
if fresher { " (fresher)" } else { "" }
|
|
|
|
);
|
|
|
|
crate::verify::apply_role(ctx, &mut member, data.member).await?;
|
2023-09-24 13:50:14 +00:00
|
|
|
if fresher {
|
2023-09-24 15:04:28 +00:00
|
|
|
crate::verify::apply_role(ctx, &mut member, data.fresher).await?;
|
2023-09-24 13:50:14 +00:00
|
|
|
}
|
2024-01-24 04:05:34 +00:00
|
|
|
m.create_response(
|
|
|
|
&ctx.http,
|
|
|
|
CreateInteractionResponse::UpdateMessage(
|
|
|
|
CreateInteractionResponseMessage::new()
|
|
|
|
.components(vec![])
|
|
|
|
.embed(
|
|
|
|
CreateEmbed::new()
|
|
|
|
.thumbnail(
|
|
|
|
user.avatar_url().unwrap_or(super::AVATAR.to_string()),
|
|
|
|
)
|
2023-09-25 12:23:32 +00:00
|
|
|
.title("Member verified via manual")
|
2024-01-24 04:05:34 +00:00
|
|
|
.description(user.to_string())
|
|
|
|
.field("Fresher", fresher.to_string(), true)
|
2023-11-11 17:32:27 +00:00
|
|
|
.field("Nickname", mm.nickname, true)
|
|
|
|
.field("Name", mm.realname, true)
|
2024-01-24 04:05:34 +00:00
|
|
|
.timestamp(serenity::Timestamp::now()),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
2023-09-24 15:04:28 +00:00
|
|
|
.await?;
|
2023-11-11 17:31:07 +00:00
|
|
|
let _ = member.remove_role(&ctx.http, data.non_member).await;
|
2023-10-11 23:25:11 +00:00
|
|
|
if member.roles.contains(&data.old_member) {
|
|
|
|
crate::verify::remove_role(ctx, &mut member, data.old_member).await?;
|
|
|
|
} else {
|
2023-09-27 15:18:20 +00:00
|
|
|
crate::verify::welcome_user(&ctx.http, &data.gn_ch_id, &user, fresher).await?;
|
|
|
|
}
|
2023-09-24 00:56:20 +00:00
|
|
|
}
|
2023-09-24 13:50:14 +00:00
|
|
|
Err(e) => {
|
2023-09-29 00:06:37 +00:00
|
|
|
tracing::error!("{e}");
|
2024-01-24 04:05:34 +00:00
|
|
|
m.create_response(
|
|
|
|
&ctx.http,
|
|
|
|
CreateInteractionResponse::Message(
|
|
|
|
CreateInteractionResponseMessage::new()
|
|
|
|
.content(format!("Failed to add user {user} to member database")),
|
|
|
|
),
|
|
|
|
)
|
2023-09-25 12:23:32 +00:00
|
|
|
.await?;
|
2023-09-24 13:50:14 +00:00
|
|
|
}
|
2023-09-24 00:56:20 +00:00
|
|
|
}
|
2023-09-24 13:50:14 +00:00
|
|
|
} else {
|
2023-09-25 11:36:01 +00:00
|
|
|
crate::db::delete_manual_by_id(&data.db, user.id.into()).await?;
|
2023-09-29 00:06:37 +00:00
|
|
|
tracing::info!("{} ({}) denied via manual", user.name, user.id);
|
2024-01-24 04:05:34 +00:00
|
|
|
m.create_response(
|
|
|
|
&ctx.http,
|
|
|
|
CreateInteractionResponse::UpdateMessage(
|
|
|
|
CreateInteractionResponseMessage::new()
|
|
|
|
.components(vec![])
|
|
|
|
.embed(
|
|
|
|
CreateEmbed::new()
|
|
|
|
.title("Member denied via manual")
|
|
|
|
.description(user.to_string())
|
2023-09-25 12:23:32 +00:00
|
|
|
.thumbnail(user.avatar_url().unwrap_or(super::AVATAR.to_string()))
|
2024-01-24 04:05:34 +00:00
|
|
|
.timestamp(serenity::Timestamp::now()),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
2023-09-25 12:23:32 +00:00
|
|
|
.await?;
|
2023-09-24 00:56:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|