feat(ticket): cooldown 5m after close (DB ticket_cooldowns + check on create)
This commit is contained in:
parent
9c0b2624e2
commit
2a7ace8c09
4 changed files with 75 additions and 2 deletions
|
|
@ -12,8 +12,12 @@ pub async fn run(pool: &SqlitePool) -> anyhow::Result<()> {
|
||||||
.execute(pool)
|
.execute(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let migrations =
|
let migrations = [
|
||||||
[("V1__initial", V1_INITIAL), ("V2__tickets", V2_TICKETS), ("V3__reminders", V3_REMINDERS)];
|
("V1__initial", V1_INITIAL),
|
||||||
|
("V2__tickets", V2_TICKETS),
|
||||||
|
("V3__reminders", V3_REMINDERS),
|
||||||
|
("V4__ticket_cooldown", V4_COOLDOWN),
|
||||||
|
];
|
||||||
for (name, sql) in migrations {
|
for (name, sql) in migrations {
|
||||||
let exists: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM _migrations WHERE name = ?")
|
let exists: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM _migrations WHERE name = ?")
|
||||||
.bind(name)
|
.bind(name)
|
||||||
|
|
@ -76,3 +80,11 @@ CREATE TABLE IF NOT EXISTS reminders (
|
||||||
sent INTEGER NOT NULL DEFAULT 0
|
sent INTEGER NOT NULL DEFAULT 0
|
||||||
);
|
);
|
||||||
";
|
";
|
||||||
|
const V4_COOLDOWN: &str = "
|
||||||
|
CREATE TABLE IF NOT EXISTS ticket_cooldowns (
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
guild_id TEXT NOT NULL,
|
||||||
|
expires_at INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY (user_id, guild_id)
|
||||||
|
);
|
||||||
|
";
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,18 @@ pub async fn handle_close_modal(ctx: Context, interaction: serenity::all::ModalI
|
||||||
haste_url.clone(),
|
haste_url.clone(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
let opener_for_cooldown = if let Some(pool) = service::pool() {
|
||||||
|
service::get_opener(pool, channel_id.get()).await
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
if let Some(pool) = service::pool() {
|
if let Some(pool) = service::pool() {
|
||||||
service::cleanup_ticket(pool, channel_id.get()).await;
|
service::cleanup_ticket(pool, channel_id.get()).await;
|
||||||
|
if let Some(opener) = opener_for_cooldown {
|
||||||
|
if let Some(gid) = interaction.guild_id {
|
||||||
|
service::set_cooldown(pool, gid.get(), opener, 300).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let control_row = serenity::all::CreateActionRow::Buttons(vec![
|
let control_row = serenity::all::CreateActionRow::Buttons(vec![
|
||||||
serenity::all::CreateButton::new("ticket_reopen")
|
serenity::all::CreateButton::new("ticket_reopen")
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,20 @@ pub async fn on_modal(ctx: Context, interaction: ModalInteraction) {
|
||||||
.await;
|
.await;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if let Some(rem) = service::is_on_cooldown(pool, guild_id.get(), user.id.get()).await {
|
||||||
|
let _ = interaction
|
||||||
|
.create_followup(
|
||||||
|
&ctx.http,
|
||||||
|
serenity::all::CreateInteractionResponseFollowup::new()
|
||||||
|
.content(format!(
|
||||||
|
"Cooldown: wait {}s before new ticket (5m after close).",
|
||||||
|
rem
|
||||||
|
))
|
||||||
|
.ephemeral(true),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Ok(channels) = guild_id.channels(&ctx.http).await {
|
if let Ok(channels) = guild_id.channels(&ctx.http).await {
|
||||||
let exists = channels.values().any(|c| {
|
let exists = channels.values().any(|c| {
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,43 @@ pub async fn cleanup_ticket(p: &SqlitePool, c: u64) {
|
||||||
let _ = sqlx::query("DELETE FROM tickets WHERE channel_id=?").bind(c.to_string()).execute(p).await;
|
let _ = sqlx::query("DELETE FROM tickets WHERE channel_id=?").bind(c.to_string()).execute(p).await;
|
||||||
let _ = sqlx::query("DELETE FROM ticket_claims WHERE channel_id=?").bind(c.to_string()).execute(p).await;
|
let _ = sqlx::query("DELETE FROM ticket_claims WHERE channel_id=?").bind(c.to_string()).execute(p).await;
|
||||||
}
|
}
|
||||||
|
pub async fn is_on_cooldown(p: &SqlitePool, g: u64, u: u64) -> Option<u64> {
|
||||||
|
let _ = sqlx::query("CREATE TABLE IF NOT EXISTS ticket_cooldowns (user_id TEXT NOT NULL, guild_id TEXT NOT NULL, expires_at INTEGER NOT NULL, PRIMARY KEY (user_id, guild_id))").execute(p).await;
|
||||||
|
let row: Option<(i64,)> =
|
||||||
|
sqlx::query_as("SELECT expires_at FROM ticket_cooldowns WHERE user_id=? AND guild_id=?")
|
||||||
|
.bind(u.to_string())
|
||||||
|
.bind(g.to_string())
|
||||||
|
.fetch_optional(p)
|
||||||
|
.await
|
||||||
|
.unwrap_or(None);
|
||||||
|
if let Some((exp,)) = row {
|
||||||
|
let now =
|
||||||
|
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs()
|
||||||
|
as i64;
|
||||||
|
if exp > now {
|
||||||
|
return Some((exp - now) as u64);
|
||||||
|
}
|
||||||
|
let _ = sqlx::query("DELETE FROM ticket_cooldowns WHERE user_id=? AND guild_id=?")
|
||||||
|
.bind(u.to_string())
|
||||||
|
.bind(g.to_string())
|
||||||
|
.execute(p)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
pub async fn set_cooldown(p: &SqlitePool, g: u64, u: u64, secs: u64) {
|
||||||
|
let _ = sqlx::query("CREATE TABLE IF NOT EXISTS ticket_cooldowns (user_id TEXT NOT NULL, guild_id TEXT NOT NULL, expires_at INTEGER NOT NULL, PRIMARY KEY (user_id, guild_id))").execute(p).await;
|
||||||
|
let exp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs()
|
||||||
|
+ secs;
|
||||||
|
let _ = sqlx::query(
|
||||||
|
"INSERT OR REPLACE INTO ticket_cooldowns(user_id, guild_id, expires_at) VALUES(?,?,?)",
|
||||||
|
)
|
||||||
|
.bind(u.to_string())
|
||||||
|
.bind(g.to_string())
|
||||||
|
.bind(exp as i64)
|
||||||
|
.execute(p)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
pub async fn add_user_to_ticket(
|
pub async fn add_user_to_ticket(
|
||||||
http: &Http,
|
http: &Http,
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue