diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-04 01:08:31 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-04 01:08:31 +0100 |
| commit | feb0e771a11b71855d268fa1b4f141f28ed53db3 (patch) | |
| tree | 0e9d1a666897fc7bc6cf31ece59bf64b332fa9da | |
| parent | commands: gate admin, trigger, cron and recording behind permissions (diff) | |
| download | senator-sperma-feb0e771a11b71855d268fa1b4f141f28ed53db3.tar.gz senator-sperma-feb0e771a11b71855d268fa1b4f141f28ed53db3.zip | |
cron: scope jobs to the guild that created them
| -rw-r--r-- | src/commands/cron.rs | 16 | ||||
| -rw-r--r-- | src/database/mod.rs | 50 |
2 files changed, 47 insertions, 19 deletions
diff --git a/src/commands/cron.rs b/src/commands/cron.rs index 47c3d62..ebaa96d 100644 --- a/src/commands/cron.rs +++ b/src/commands/cron.rs | |||
| @@ -44,8 +44,10 @@ pub async fn dodaj_audio( | |||
| 44 | ctx.data().copyparty.build_url_no_pw(&audio_filename) | 44 | ctx.data().copyparty.build_url_no_pw(&audio_filename) |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; | ||
| 47 | database::add_cron_job( | 48 | database::add_cron_job( |
| 48 | &ctx.data().db_pool, | 49 | &ctx.data().db_pool, |
| 50 | guild_id.get() as i64, | ||
| 49 | &cron_expression, | 51 | &cron_expression, |
| 50 | "audio", | 52 | "audio", |
| 51 | channel_id, | 53 | channel_id, |
| @@ -72,8 +74,10 @@ pub async fn dodaj_wiadomość( | |||
| 72 | _ => return Err(lang::err_bad_channel_type()), | 74 | _ => return Err(lang::err_bad_channel_type()), |
| 73 | }; | 75 | }; |
| 74 | 76 | ||
| 77 | let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; | ||
| 75 | database::add_cron_job( | 78 | database::add_cron_job( |
| 76 | &ctx.data().db_pool, | 79 | &ctx.data().db_pool, |
| 80 | guild_id.get() as i64, | ||
| 77 | &cron_expression, | 81 | &cron_expression, |
| 78 | "wiadomość", | 82 | "wiadomość", |
| 79 | channel_id, | 83 | channel_id, |
| @@ -89,7 +93,8 @@ pub async fn dodaj_wiadomość( | |||
| 89 | /// List all cron jobs | 93 | /// List all cron jobs |
| 90 | #[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")] | 94 | #[poise::command(slash_command, guild_only, required_permissions = "MANAGE_GUILD")] |
| 91 | pub async fn pokaż(ctx: Context<'_>) -> Result<()> { | 95 | pub async fn pokaż(ctx: Context<'_>) -> Result<()> { |
| 92 | let jobs = database::list_cron_jobs(&ctx.data().db_pool).await?; | 96 | let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; |
| 97 | let jobs = database::list_cron_jobs(&ctx.data().db_pool, guild_id.get() as i64).await?; | ||
| 93 | if jobs.is_empty() { | 98 | if jobs.is_empty() { |
| 94 | ctx.say(lang::L_CRON_NONE).await?; | 99 | ctx.say(lang::L_CRON_NONE).await?; |
| 95 | return Ok(()); | 100 | return Ok(()); |
| @@ -126,7 +131,8 @@ pub async fn usuń( | |||
| 126 | ctx: Context<'_>, | 131 | ctx: Context<'_>, |
| 127 | #[description = "ID pracy do usunięcia"] job_id: i64, | 132 | #[description = "ID pracy do usunięcia"] job_id: i64, |
| 128 | ) -> Result<()> { | 133 | ) -> Result<()> { |
| 129 | if database::delete_cron_job(&ctx.data().db_pool, job_id).await? { | 134 | let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; |
| 135 | if database::delete_cron_job(&ctx.data().db_pool, job_id, guild_id.get() as i64).await? { | ||
| 130 | ctx.say(lang::fmt_cron_deleted(job_id)).await?; | 136 | ctx.say(lang::fmt_cron_deleted(job_id)).await?; |
| 131 | } else { | 137 | } else { |
| 132 | ctx.say(lang::fmt_cron_not_found(job_id)).await?; | 138 | ctx.say(lang::fmt_cron_not_found(job_id)).await?; |
| @@ -140,7 +146,8 @@ pub async fn pauza( | |||
| 140 | ctx: Context<'_>, | 146 | ctx: Context<'_>, |
| 141 | #[description = "ID pracy do zapauzowania"] job_id: i64, | 147 | #[description = "ID pracy do zapauzowania"] job_id: i64, |
| 142 | ) -> Result<()> { | 148 | ) -> Result<()> { |
| 143 | if database::set_cron_job_active(&ctx.data().db_pool, job_id, false).await? { | 149 | let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; |
| 150 | if database::set_cron_job_active(&ctx.data().db_pool, job_id, guild_id.get() as i64, false).await? { | ||
| 144 | ctx.say(lang::fmt_cron_paused(job_id)).await?; | 151 | ctx.say(lang::fmt_cron_paused(job_id)).await?; |
| 145 | } else { | 152 | } else { |
| 146 | ctx.say(lang::fmt_cron_not_found(job_id)).await?; | 153 | ctx.say(lang::fmt_cron_not_found(job_id)).await?; |
| @@ -154,7 +161,8 @@ pub async fn wznów( | |||
| 154 | ctx: Context<'_>, | 161 | ctx: Context<'_>, |
| 155 | #[description = "ID pracy cron do wznowienia"] job_id: i64, | 162 | #[description = "ID pracy cron do wznowienia"] job_id: i64, |
| 156 | ) -> Result<()> { | 163 | ) -> Result<()> { |
| 157 | if database::set_cron_job_active(&ctx.data().db_pool, job_id, true).await? { | 164 | let guild_id = ctx.guild_id().ok_or_else(lang::err_not_in_guild)?; |
| 165 | if database::set_cron_job_active(&ctx.data().db_pool, job_id, guild_id.get() as i64, true).await? { | ||
| 158 | ctx.say(lang::fmt_cron_resumed(job_id)).await?; | 166 | ctx.say(lang::fmt_cron_resumed(job_id)).await?; |
| 159 | } else { | 167 | } else { |
| 160 | ctx.say(lang::fmt_cron_not_found(job_id)).await?; | 168 | ctx.say(lang::fmt_cron_not_found(job_id)).await?; |
diff --git a/src/database/mod.rs b/src/database/mod.rs index b68d927..9679811 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs | |||
| @@ -55,17 +55,22 @@ async fn run_migrations(pool: &DbPool) -> Result<()> { | |||
| 55 | audio_filename TEXT, | 55 | audio_filename TEXT, |
| 56 | message TEXT, | 56 | message TEXT, |
| 57 | created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | 57 | created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
| 58 | last_run TIMESTAMP | 58 | last_run TIMESTAMP, |
| 59 | guild_id INTEGER NOT NULL DEFAULT 0 | ||
| 59 | )", | 60 | )", |
| 60 | ) | 61 | ) |
| 61 | .execute(pool) | 62 | .execute(pool) |
| 62 | .await?; | 63 | .await?; |
| 63 | 64 | ||
| 64 | // Add last_run column for pre-existing databases that lack it. | 65 | // Add columns for pre-existing databases that lack them. |
| 65 | sqlx::query("ALTER TABLE cron_jobs ADD COLUMN last_run TIMESTAMP") | 66 | sqlx::query("ALTER TABLE cron_jobs ADD COLUMN last_run TIMESTAMP") |
| 66 | .execute(pool) | 67 | .execute(pool) |
| 67 | .await | 68 | .await |
| 68 | .ok(); | 69 | .ok(); |
| 70 | sqlx::query("ALTER TABLE cron_jobs ADD COLUMN guild_id INTEGER NOT NULL DEFAULT 0") | ||
| 71 | .execute(pool) | ||
| 72 | .await | ||
| 73 | .ok(); | ||
| 69 | 74 | ||
| 70 | sqlx::query( | 75 | sqlx::query( |
| 71 | "CREATE TABLE IF NOT EXISTS triggers ( | 76 | "CREATE TABLE IF NOT EXISTS triggers ( |
| @@ -305,6 +310,8 @@ pub async fn get_user_rank(pool: &DbPool, user_id: &str, metric: &str) -> Result | |||
| 305 | #[derive(Debug, Clone, FromRow)] | 310 | #[derive(Debug, Clone, FromRow)] |
| 306 | pub struct CronJob { | 311 | pub struct CronJob { |
| 307 | pub id: i64, | 312 | pub id: i64, |
| 313 | #[allow(dead_code)] | ||
| 314 | pub guild_id: i64, | ||
| 308 | pub cron_expression: String, | 315 | pub cron_expression: String, |
| 309 | pub r#type: String, | 316 | pub r#type: String, |
| 310 | pub channel_id: i64, | 317 | pub channel_id: i64, |
| @@ -317,10 +324,13 @@ pub struct CronJob { | |||
| 317 | } | 324 | } |
| 318 | 325 | ||
| 319 | #[allow(dead_code)] | 326 | #[allow(dead_code)] |
| 320 | pub async fn list_cron_jobs(pool: &DbPool) -> Result<Vec<CronJob>> { | 327 | pub async fn list_cron_jobs(pool: &DbPool, guild_id: i64) -> Result<Vec<CronJob>> { |
| 321 | Ok(sqlx::query_as("SELECT * FROM cron_jobs ORDER BY id") | 328 | Ok( |
| 322 | .fetch_all(pool) | 329 | sqlx::query_as("SELECT * FROM cron_jobs WHERE guild_id = ? ORDER BY id") |
| 323 | .await?) | 330 | .bind(guild_id) |
| 331 | .fetch_all(pool) | ||
| 332 | .await?, | ||
| 333 | ) | ||
| 324 | } | 334 | } |
| 325 | 335 | ||
| 326 | #[allow(dead_code)] | 336 | #[allow(dead_code)] |
| @@ -332,6 +342,7 @@ pub async fn list_active_cron_jobs(pool: &DbPool) -> Result<Vec<CronJob>> { | |||
| 332 | 342 | ||
| 333 | pub async fn add_cron_job( | 343 | pub async fn add_cron_job( |
| 334 | pool: &DbPool, | 344 | pool: &DbPool, |
| 345 | guild_id: i64, | ||
| 335 | cron_expression: &str, | 346 | cron_expression: &str, |
| 336 | r#type: &str, | 347 | r#type: &str, |
| 337 | channel_id: i64, | 348 | channel_id: i64, |
| @@ -353,9 +364,10 @@ pub async fn add_cron_job( | |||
| 353 | }).unwrap_or(existing.len() as i64 + 1); | 364 | }).unwrap_or(existing.len() as i64 + 1); |
| 354 | 365 | ||
| 355 | let result = sqlx::query( | 366 | let result = sqlx::query( |
| 356 | "INSERT INTO cron_jobs (id, cron_expression, type, channel_id, audio_filename, message) VALUES (?, ?, ?, ?, ?, ?)", | 367 | "INSERT INTO cron_jobs (id, guild_id, cron_expression, type, channel_id, audio_filename, message) VALUES (?, ?, ?, ?, ?, ?, ?)", |
| 357 | ) | 368 | ) |
| 358 | .bind(next_id) | 369 | .bind(next_id) |
| 370 | .bind(guild_id) | ||
| 359 | .bind(cron_expression) | 371 | .bind(cron_expression) |
| 360 | .bind(r#type) | 372 | .bind(r#type) |
| 361 | .bind(channel_id) | 373 | .bind(channel_id) |
| @@ -366,9 +378,10 @@ pub async fn add_cron_job( | |||
| 366 | Ok(result.last_insert_rowid()) | 378 | Ok(result.last_insert_rowid()) |
| 367 | } | 379 | } |
| 368 | 380 | ||
| 369 | pub async fn delete_cron_job(pool: &DbPool, id: i64) -> Result<bool> { | 381 | pub async fn delete_cron_job(pool: &DbPool, id: i64, guild_id: i64) -> Result<bool> { |
| 370 | let result = sqlx::query("DELETE FROM cron_jobs WHERE id = ?") | 382 | let result = sqlx::query("DELETE FROM cron_jobs WHERE id = ? AND guild_id = ?") |
| 371 | .bind(id) | 383 | .bind(id) |
| 384 | .bind(guild_id) | ||
| 372 | .execute(pool) | 385 | .execute(pool) |
| 373 | .await?; | 386 | .await?; |
| 374 | Ok(result.rows_affected() > 0) | 387 | Ok(result.rows_affected() > 0) |
| @@ -383,12 +396,19 @@ pub async fn update_cron_last_run(pool: &DbPool, id: i64, last_run: DateTime<Utc | |||
| 383 | Ok(()) | 396 | Ok(()) |
| 384 | } | 397 | } |
| 385 | 398 | ||
| 386 | pub async fn set_cron_job_active(pool: &DbPool, id: i64, active: bool) -> Result<bool> { | 399 | pub async fn set_cron_job_active( |
| 387 | let result = sqlx::query("UPDATE cron_jobs SET active = ? WHERE id = ?") | 400 | pool: &DbPool, |
| 388 | .bind(if active { 1 } else { 0 }) | 401 | id: i64, |
| 389 | .bind(id) | 402 | guild_id: i64, |
| 390 | .execute(pool) | 403 | active: bool, |
| 391 | .await?; | 404 | ) -> Result<bool> { |
| 405 | let result = | ||
| 406 | sqlx::query("UPDATE cron_jobs SET active = ? WHERE id = ? AND guild_id = ?") | ||
| 407 | .bind(if active { 1 } else { 0 }) | ||
| 408 | .bind(id) | ||
| 409 | .bind(guild_id) | ||
| 410 | .execute(pool) | ||
| 411 | .await?; | ||
| 392 | Ok(result.rows_affected() > 0) | 412 | Ok(result.rows_affected() > 0) |
| 393 | } | 413 | } |
| 394 | 414 | ||
