@@ -4,17 +4,17 @@ use crate::prelude::db::*;
44use crate :: prelude:: errors:: * ;
55use crate :: prelude:: handlers:: * ;
66use crate :: prelude:: i18n:: * ;
7+ use crate :: prelude:: modules:: * ;
78use crate :: prelude:: utils:: * ;
89use chrono:: Utc ;
910use serenity:: FutureExt ;
1011use serenity:: all:: {
11- CommandDataOptionValue , CommandInteraction , CommandOptionType , Context , CreateCommand ,
12- CreateCommandOption , GuildId , ResolvedOption , UserId ,
12+ Channel , CommandDataOptionValue , CommandInteraction , CommandOptionType , Context , CreateCommand ,
13+ CreateCommandOption , GuildId , PermissionOverwriteType , ResolvedOption , RoleId , UserId ,
1314} ;
1415use std:: collections:: HashMap ;
1516use std:: sync:: Arc ;
1617use std:: time:: Duration ;
17- use tokio:: time:: sleep;
1818
1919pub struct CloseCommand ;
2020
@@ -191,16 +191,32 @@ impl RegistrableCommand for CloseCommand {
191191 }
192192
193193 if let Some ( delay) = duration {
194+ if let Ok ( Some ( existing) ) = get_scheduled_closure ( & thread. id , db_pool) . await {
195+ let remaining = existing. close_at - Utc :: now ( ) . timestamp ( ) ;
196+ if remaining > 0 {
197+ let old_human = format_duration ( remaining as u64 ) ;
198+
199+ let mut warn_params = HashMap :: new ( ) ;
200+ warn_params. insert ( "old_time" . to_string ( ) , old_human) ;
201+
202+ let response = MessageBuilder :: system_message ( & ctx, & config)
203+ . translated_content (
204+ "close.replacing_existing_closure" ,
205+ Some ( & warn_params) ,
206+ Some ( command. user . id ) ,
207+ command. guild_id . map ( |g| g. get ( ) ) ,
208+ )
209+ . await
210+ . to_channel ( command. channel_id )
211+ . build_interaction_message_followup ( )
212+ . await ;
213+
214+ let _ = command. create_followup ( & ctx. http , response) . await ;
215+ }
216+ }
217+
194218 let delay_secs = delay. as_secs ( ) ;
195- let human = if delay_secs < 60 {
196- format ! ( "{}s" , delay_secs)
197- } else if delay_secs < 3600 {
198- format ! ( "{}m" , delay_secs / 60 )
199- } else if delay_secs < 86400 {
200- format ! ( "{}h{}m" , delay_secs / 3600 , ( delay_secs % 3600 ) / 60 )
201- } else {
202- format ! ( "{}d{}h" , delay_secs / 86400 , ( delay_secs % 86400 ) / 3600 )
203- } ;
219+ let human = format_duration ( delay_secs) ;
204220 let mut params = HashMap :: new ( ) ;
205221 params. insert ( "time" . to_string ( ) , human) ;
206222
@@ -217,7 +233,7 @@ impl RegistrableCommand for CloseCommand {
217233 . build_interaction_message_followup ( )
218234 . await ;
219235
220- let _ = command. create_followup ( & ctx. http , response) . await ;
236+ command. create_followup ( & ctx. http , response) . await
221237 } else {
222238 let response = MessageBuilder :: system_message ( & ctx, & config)
223239 . translated_content (
@@ -231,18 +247,58 @@ impl RegistrableCommand for CloseCommand {
231247 . build_interaction_message_followup ( )
232248 . await ;
233249
234- let _ = command. create_followup ( & ctx. http , response) . await ;
250+ command. create_followup ( & ctx. http , response) . await
235251 } ;
236252
253+ let closed_by = command. user . id . to_string ( ) ;
254+
255+ let ( category_id, category_name, required_permissions) =
256+ match command. channel_id . to_channel ( & ctx. http ) . await {
257+ Ok ( Channel :: Guild ( guild_channel) ) => {
258+ let guild_id = guild_channel. guild_id ;
259+ let parent_id = guild_channel. parent_id ;
260+
261+ let category_id =
262+ parent_id. map ( |id| id. to_string ( ) ) . unwrap_or_default ( ) ;
263+
264+ let category_name = if let Some ( parent_id) = parent_id {
265+ guild_id
266+ . channels ( & ctx. http )
267+ . await
268+ . ok ( )
269+ . and_then ( |channels| {
270+ channels. get ( & parent_id) . map ( |c| c. name . clone ( ) )
271+ } )
272+ . unwrap_or_default ( )
273+ } else {
274+ String :: new ( )
275+ } ;
276+
277+ let guild = guild_id. to_partial_guild ( & ctx. http ) . await . ok ( ) ;
278+ let everyone_role_id = RoleId :: new ( guild_id. get ( ) ) ;
279+
280+ let mut perms = guild
281+ . and_then ( |g| {
282+ g. roles . get ( & everyone_role_id) . map ( |r| r. permissions . bits ( ) )
283+ } )
284+ . unwrap_or ( 0u64 ) ;
285+
286+ for overwrite in & guild_channel. permission_overwrites {
287+ if let PermissionOverwriteType :: Role ( _) = overwrite. kind {
288+ let allow = overwrite. allow . bits ( ) ;
289+ let deny = overwrite. deny . bits ( ) ;
290+ perms = ( perms & !deny) | allow;
291+ }
292+ }
293+
294+ ( category_id, category_name, perms)
295+ }
296+ _ => ( String :: new ( ) , String :: new ( ) , 0u64 ) ,
297+ } ;
298+
237299 let thread_id = thread. id . clone ( ) ;
238300 let close_at = Utc :: now ( ) . timestamp ( ) + delay. as_secs ( ) as i64 ;
239301
240- let closed_by = command. user . id . to_string ( ) ;
241- let category_id = get_category_id_from_command ( & ctx, & command) . await ;
242- let category_name = get_category_name_from_command ( & ctx, & command) . await ;
243- let required_permissions =
244- get_required_permissions_channel_from_command ( & ctx, & command) . await ;
245-
246302 if let Err ( e) = upsert_scheduled_closure (
247303 & thread_id,
248304 close_at,
@@ -257,103 +313,8 @@ impl RegistrableCommand for CloseCommand {
257313 {
258314 eprintln ! ( "Failed to persist scheduled closure: {e:?}" ) ;
259315 }
260- let channel_id = command. channel_id ;
261- let config_clone = config. clone ( ) ;
262- let ctx_clone = ctx. clone ( ) ;
263- let user_id_clone = user_id;
264- let thread_id_for_task = thread_id. clone ( ) ;
265-
266- tokio:: spawn ( async move {
267- sleep ( delay) . await ;
268- if let Some ( pool) = config_clone. db_pool . as_ref ( ) {
269- if let Ok ( Some ( record) ) =
270- get_scheduled_closure ( & thread_id_for_task, pool) . await
271- {
272- if record. close_at <= Utc :: now ( ) . timestamp ( ) {
273- let _ = close_thread (
274- & thread_id_for_task,
275- & record. closed_by ,
276- & record. category_id ,
277- & record. category_name ,
278- record. required_permissions . parse :: < u64 > ( ) . unwrap_or ( 0 ) ,
279- pool,
280- )
281- . await ;
282- let _ = delete_scheduled_closure ( & thread_id_for_task, pool) . await ;
283-
284- let community_guild_id =
285- GuildId :: new ( config_clone. bot . get_community_guild_id ( ) ) ;
286-
287- let user_still_member = community_guild_id
288- . member ( & ctx_clone. http , user_id_clone)
289- . await
290- . is_ok ( ) ;
291-
292- if !record. silent && user_still_member {
293- let _ =
294- MessageBuilder :: system_message ( & ctx_clone, & config_clone)
295- . content ( & config_clone. bot . close_message )
296- . to_user ( user_id_clone)
297- . send ( true )
298- . await ;
299- }
300- let _ = channel_id. delete ( & ctx_clone. http ) . await ;
301- } else {
302- let delay2 =
303- ( record. close_at - Utc :: now ( ) . timestamp ( ) ) . max ( 1 ) as u64 ;
304- let config_clone2 = config_clone. clone ( ) ;
305- let ctx_clone2 = ctx_clone. clone ( ) ;
306- let thread_id_again = thread_id_for_task. clone ( ) ;
307-
308- tokio:: spawn ( async move {
309- sleep ( Duration :: from_secs ( delay2) ) . await ;
310- if let Some ( pool2) = config_clone2. db_pool . as_ref ( ) {
311- if let Ok ( Some ( r2) ) =
312- get_scheduled_closure ( & thread_id_again, pool2) . await
313- {
314- if r2. close_at <= Utc :: now ( ) . timestamp ( ) {
315- let _ = close_thread (
316- & thread_id_again,
317- & r2. closed_by ,
318- & r2. category_id ,
319- & r2. category_name ,
320- r2. required_permissions
321- . parse :: < u64 > ( )
322- . unwrap_or ( 0 ) ,
323- pool2,
324- )
325- . await ;
326- let _ = delete_scheduled_closure (
327- & thread_id_again,
328- pool2,
329- )
330- . await ;
331- let community_guild_id = GuildId :: new (
332- config_clone2. bot . get_community_guild_id ( ) ,
333- ) ;
334- let user_still_member = community_guild_id
335- . member ( & ctx_clone2. http , user_id_clone)
336- . await
337- . is_ok ( ) ;
338- if !r2. silent && user_still_member {
339- let _ = MessageBuilder :: system_message (
340- & ctx_clone2,
341- & config_clone2,
342- )
343- . content ( & config_clone2. bot . close_message )
344- . to_user ( user_id_clone)
345- . send ( true )
346- . await ;
347- }
348- let _ = channel_id. delete ( & ctx_clone2. http ) . await ;
349- }
350- }
351- }
352- } ) ;
353- }
354- }
355- }
356- } ) ;
316+
317+ schedule_one ( & ctx, & config, thread_id, close_at) ;
357318 return Ok ( ( ) ) ;
358319 }
359320
0 commit comments