nanobot/src/verify/manual.rs

294 lines
11 KiB
Rust
Raw Normal View History

2023-09-24 00:56:20 +00:00
use crate::{Data, Error};
use poise::serenity_prelude as serenity;
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,
m: &serenity::MessageComponentInteraction,
) -> Result<(), Error> {
m.create_interaction_response(&ctx.http, |i| {
i.kind(serenity::InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.content(MANUAL_INTRO).components(|c| {
c.create_action_row(|a| {
a.create_button(|b| {
b.style(serenity::ButtonStyle::Danger)
.emoji('🔙')
.custom_id("restart")
})
.create_button(|b| {
b.style(serenity::ButtonStyle::Success)
.emoji('✅')
.label("Fresher")
.custom_id("manual_2f")
})
.create_button(|b| {
b.style(serenity::ButtonStyle::Primary)
.emoji('❌')
.label("Non-fresher")
.custom_id("manual_2n")
})
})
})
})
})
.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,
m: &serenity::MessageComponentInteraction,
data: &Data,
fresher: bool,
) -> Result<(), Error> {
// Delete from manual if exists
let _ = crate::db::delete_manual_by_id(&data.db, m.user.id.into()).await;
2023-09-24 00:56:20 +00:00
m.create_interaction_response(&ctx.http, |i| {
*i = Manual::create(
None,
if fresher {
"manual_3f".to_string()
} else {
"manual_3n".to_string()
},
);
i
})
.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,
m: &serenity::ModalSubmitInteraction,
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() {
m.create_interaction_response(&ctx.http, |i| {
i.kind(serenity::InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|d| {
d.content("The url provided is invalid, please try again")
.ephemeral(true)
})
})
.await?;
return Ok(());
}
// Delete from pending if exists
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
.send_message(&ctx.http, |cm| {
cm.add_embed(|e| {
e.title("New verification request from")
2023-09-25 12:23:32 +00:00
.thumbnail(m.user.avatar_url().unwrap_or(super::AVATAR.to_string()))
2023-09-24 00:56:20 +00:00
.description(&m.user)
.field("Real Name (To be checked)", &realname, true)
.field("Imperial Shortcode (To be checked", &shortcode, true)
.field("Fresher (To be checked)", fresher, true)
.field("Nickname (Nano whois commands)", &nickname, true)
.field("Verification URL (Also displayed below)", &url, true)
.image(&url)
.timestamp(serenity::Timestamp::now())
})
.components(|c| {
c.create_action_row(|a| {
a.create_button(|b| {
b.style(serenity::ButtonStyle::Success)
.emoji('✅')
.label("Accept")
.custom_id(format!("verify-y-{}", m.user.id))
})
.create_button(|b| {
b.style(serenity::ButtonStyle::Danger)
.emoji('❎')
.label("Deny")
.custom_id(format!("verify-n-{}", m.user.id))
})
})
})
})
.await
.is_ok();
let inserted = crate::db::insert_manual(
&data.db,
crate::ManualMember {
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."
};
m.create_interaction_response(&ctx.http, |i| {
i.kind(serenity::InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| d.content(msg).components(|c| c))
})
.await?;
return Ok(());
}
2023-09-29 00:06:37 +00:00
Err(e) => tracing::error!("{e}"),
2023-09-24 00:56:20 +00:00
};
m.create_interaction_response(&ctx.http, |i| {
i.kind(serenity::InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|d| {
d.content("Sorry, something went wrong. Please try again")
.ephemeral(true)
})
})
.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,
m: &serenity::MessageComponentInteraction,
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>()
.map(serenity::UserId)
.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?;
if verify {
match crate::db::insert_member_from_manual(&data.db, user.id.into()).await {
Ok(mm) => {
let fresher = crate::db::get_member_by_id(&data.db, user.id.into())
.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?;
if fresher {
2023-09-24 15:04:28 +00:00
crate::verify::apply_role(ctx, &mut member, data.fresher).await?;
}
m.create_interaction_response(&ctx.http, |i| {
i.kind(serenity::InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.components(|c| c).embed(|e| {
2023-09-25 12:23:32 +00:00
e.thumbnail(user.avatar_url().unwrap_or(super::AVATAR.to_string()))
.title("Member verified via manual")
.description(&user)
.field("Fresher", fresher, true)
.field("Nickname", mm.nickname, true)
.field("Name", mm.realname, true)
2023-09-25 12:23:32 +00:00
.timestamp(serenity::Timestamp::now())
})
})
})
2023-09-24 15:04:28 +00:00
.await?;
let _ = member.remove_role(&ctx.http, data.non_member).await;
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
}
Err(e) => {
2023-09-29 00:06:37 +00:00
tracing::error!("{e}");
m.create_interaction_response(&ctx.http, |i| {
i.kind(serenity::InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|d| {
d.content(format!("Failed to add user {user} to member database"))
2023-09-24 00:56:20 +00:00
})
})
2023-09-25 12:23:32 +00:00
.await?;
}
2023-09-24 00:56:20 +00:00
}
} else {
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);
m.create_interaction_response(&ctx.http, |i| {
i.kind(serenity::InteractionResponseType::UpdateMessage)
.interaction_response_data(|d| {
d.components(|c| c).embed(|e| {
e.title("Member denied via manual")
.description(&user)
2023-09-25 12:23:32 +00:00
.thumbnail(user.avatar_url().unwrap_or(super::AVATAR.to_string()))
.timestamp(serenity::Timestamp::now())
2023-09-24 00:56:20 +00:00
})
})
})
2023-09-25 12:23:32 +00:00
.await?;
2023-09-24 00:56:20 +00:00
}
Ok(())
}