@@ -386,19 +386,22 @@ pub async fn create_game_suggestion(
386386 let platform = game_response. platform . name . clone ( ) ;
387387 let company = game_response. company . clone ( ) . map ( |c| c. name ) ;
388388 async move {
389- handle_suggestion_message ( SuggestionMessageHandleData {
390- playmatch_client,
391- serenity_ctx,
392- suggestion_id : suggestion. id ,
393- owners,
394- author_id,
395- r#type : SuggestionType :: Game ,
396- provider : provider_meta,
397- name : game_name,
398- platform : Some ( platform) ,
399- company,
400- comment : suggestion. comment ,
401- } )
389+ handle_suggestion_message (
390+ SuggestionMessageHandleData {
391+ playmatch_client,
392+ serenity_ctx,
393+ suggestion_id : suggestion. id ,
394+ owners,
395+ submitter : SuggestionSubmitter :: DiscordUser ( author_id) ,
396+ r#type : SuggestionType :: Game ,
397+ provider : provider_meta,
398+ name : game_name,
399+ platform : Some ( platform) ,
400+ company,
401+ comment : suggestion. comment ,
402+ } ,
403+ None ,
404+ )
402405 . await
403406 }
404407 } ) ;
@@ -472,19 +475,22 @@ pub async fn create_company_suggestion(
472475 let author_id = ctx. author ( ) . id ;
473476 let company_name = name. clone ( ) ;
474477 async move {
475- handle_suggestion_message ( SuggestionMessageHandleData {
476- playmatch_client,
477- serenity_ctx,
478- suggestion_id : suggestion. id ,
479- owners,
480- author_id,
481- r#type : SuggestionType :: Company ,
482- provider : provider_meta,
483- name : company_name,
484- platform : None ,
485- company : None ,
486- comment : suggestion. comment ,
487- } )
478+ handle_suggestion_message (
479+ SuggestionMessageHandleData {
480+ playmatch_client,
481+ serenity_ctx,
482+ suggestion_id : suggestion. id ,
483+ owners,
484+ submitter : SuggestionSubmitter :: DiscordUser ( author_id) ,
485+ r#type : SuggestionType :: Company ,
486+ provider : provider_meta,
487+ name : company_name,
488+ platform : None ,
489+ company : None ,
490+ comment : suggestion. comment ,
491+ } ,
492+ None ,
493+ )
488494 . await
489495 }
490496 } ) ;
@@ -581,19 +587,22 @@ pub async fn create_platform_suggestion(
581587 let platform_name = name. clone ( ) ;
582588 let company = platform. company_name . clone ( ) ;
583589 async move {
584- handle_suggestion_message ( SuggestionMessageHandleData {
585- playmatch_client,
586- serenity_ctx,
587- suggestion_id : suggestion. id ,
588- owners,
589- author_id,
590- r#type : SuggestionType :: Platform ,
591- provider : provider_meta,
592- name : platform_name,
593- platform : None ,
594- company,
595- comment : suggestion. comment ,
596- } )
590+ handle_suggestion_message (
591+ SuggestionMessageHandleData {
592+ playmatch_client,
593+ serenity_ctx,
594+ suggestion_id : suggestion. id ,
595+ owners,
596+ submitter : SuggestionSubmitter :: DiscordUser ( author_id) ,
597+ r#type : SuggestionType :: Platform ,
598+ provider : provider_meta,
599+ name : platform_name,
600+ platform : None ,
601+ company,
602+ comment : suggestion. comment ,
603+ } ,
604+ None ,
605+ )
597606 . await
598607 }
599608 } ) ;
@@ -838,27 +847,38 @@ impl PlaymatchUserCtx {
838847 }
839848}
840849
841- enum SuggestionType {
850+ pub ( crate ) enum SuggestionType {
842851 Platform ,
843852 Company ,
844853 Game ,
845854}
846855
847- struct SuggestionMessageHandleData {
848- playmatch_client : Arc < playmatch_client:: Client > ,
849- serenity_ctx : Context ,
850- suggestion_id : Uuid ,
851- owners : HashSet < UserId > ,
852- author_id : UserId ,
853- r#type : SuggestionType ,
854- provider : MetadataProvider ,
855- name : String ,
856- platform : Option < String > ,
857- company : Option < String > ,
858- comment : Option < String > ,
856+ pub ( crate ) enum SuggestionSubmitter {
857+ DiscordUser ( UserId ) ,
858+ External { source : String } ,
859+ }
860+
861+ pub ( crate ) struct SuggestionMessageHandleData {
862+ pub playmatch_client : Arc < playmatch_client:: Client > ,
863+ pub serenity_ctx : Context ,
864+ pub suggestion_id : Uuid ,
865+ pub owners : HashSet < UserId > ,
866+ pub submitter : SuggestionSubmitter ,
867+ pub r#type : SuggestionType ,
868+ pub provider : MetadataProvider ,
869+ pub name : String ,
870+ pub platform : Option < String > ,
871+ pub company : Option < String > ,
872+ pub comment : Option < String > ,
859873}
860874
861- async fn handle_suggestion_message ( data : SuggestionMessageHandleData ) -> CommandResult {
875+ /// Posts the staff card (if `existing_message_id` is None) and then waits on the Approve/Decline
876+ /// buttons. Called inline from the suggest commands (with `None`) and from the external-suggestion
877+ /// poller (with `None` for new posts and `Some(id)` to re-attach to a pre-restart message).
878+ pub ( crate ) async fn handle_suggestion_message (
879+ data : SuggestionMessageHandleData ,
880+ existing_message_id : Option < serenity:: all:: MessageId > ,
881+ ) -> CommandResult {
862882 let http: & Http = data. serenity_ctx . http . as_ref ( ) ;
863883 let cache: Arc < Cache > = data. serenity_ctx . cache . clone ( ) ;
864884
@@ -880,7 +900,13 @@ async fn handle_suggestion_message(data: SuggestionMessageHandleData) -> Command
880900 . send ( )
881901 . await ?;
882902
883- let author = http. get_user ( data. author_id ) . await ?;
903+ let ( author_label, dm_target) : ( String , Option < UserId > ) = match & data. submitter {
904+ SuggestionSubmitter :: DiscordUser ( id) => {
905+ let user = http. get_user ( * id) . await ?;
906+ ( format ! ( "<@{}> ({})" , user. id, user. name) , Some ( user. id ) )
907+ }
908+ SuggestionSubmitter :: External { source } => ( format ! ( "External ({source})" ) , None ) ,
909+ } ;
884910
885911 let display_type = match data. r#type {
886912 SuggestionType :: Platform => "Platform" ,
@@ -909,10 +935,7 @@ async fn handle_suggestion_message(data: SuggestionMessageHandleData) -> Command
909935 let provider_label = display_name ( data. provider ) ;
910936
911937 let build_card = |status : Status , heading : String | -> Card < ' static > {
912- let mut card = Card :: new ( status, heading) . row (
913- "Suggested by" ,
914- format ! ( "<@{}> ({})" , author. id, author. name) ,
915- ) ;
938+ let mut card = Card :: new ( status, heading) . row ( "Suggested by" , author_label. clone ( ) ) ;
916939 card = card. row ( display_type. to_string ( ) , data. name . clone ( ) ) ;
917940 if let Some ( platform) = data. platform . clone ( ) {
918941 card = card. row ( "Platform" , platform) ;
@@ -931,34 +954,41 @@ async fn handle_suggestion_message(data: SuggestionMessageHandleData) -> Command
931954 card
932955 } ;
933956
934- let mut staff_card = build_card (
935- Status :: Info ,
936- format ! ( "New {display_type} Metadata Suggestion" ) ,
937- ) ;
938- if let Some ( url) = provider_page_url. clone ( ) {
939- staff_card = staff_card. link ( CreateButton :: new_link ( url) . label ( format ! ( "View on {provider_label}" ) ) ) ;
940- }
941- staff_card = staff_card
942- . link (
943- CreateButton :: new ( "approve" )
944- . label ( "Approve" )
945- . style ( ButtonStyle :: Success ) ,
946- )
947- . link (
948- CreateButton :: new ( "decline" )
949- . label ( "Decline" )
950- . style ( ButtonStyle :: Danger ) ,
951- )
952- . footer ( "Only bot owners can approve or decline." ) ;
957+ let message_id = match existing_message_id {
958+ Some ( id) => id,
959+ None => {
960+ let mut staff_card = build_card (
961+ Status :: Info ,
962+ format ! ( "New {display_type} Metadata Suggestion" ) ,
963+ ) ;
964+ if let Some ( url) = provider_page_url. clone ( ) {
965+ staff_card =
966+ staff_card. link ( CreateButton :: new_link ( url) . label ( format ! ( "View on {provider_label}" ) ) ) ;
967+ }
968+ staff_card = staff_card
969+ . link (
970+ CreateButton :: new ( format ! ( "approve:{}" , data. suggestion_id) )
971+ . label ( "Approve" )
972+ . style ( ButtonStyle :: Success ) ,
973+ )
974+ . link (
975+ CreateButton :: new ( format ! ( "decline:{}" , data. suggestion_id) )
976+ . label ( "Decline" )
977+ . style ( ButtonStyle :: Danger ) ,
978+ )
979+ . footer ( "Only bot owners can approve or decline." ) ;
953980
954- let message = channel_id
955- . widen ( )
956- . send_message ( http, staff_card. into_message ( ) )
957- . await ?;
981+ let message = channel_id
982+ . widen ( )
983+ . send_message ( http, staff_card. into_message ( ) )
984+ . await ?;
985+ message. id
986+ }
987+ } ;
958988
959989 let owners = data. owners . clone ( ) ;
960990 let interaction_opt = ComponentInteractionCollector :: new ( & data. serenity_ctx )
961- . message_id ( message . id )
991+ . message_id ( message_id )
962992 . timeout ( Duration :: from_secs ( 7 * 24 * 60 * 60 ) )
963993 . filter ( move |i| owners. contains ( & i. user . id ) )
964994 . await ;
@@ -970,15 +1000,22 @@ async fn handle_suggestion_message(data: SuggestionMessageHandleData) -> Command
9701000 let edit = EditMessage :: new ( )
9711001 . flags ( MessageFlags :: IS_COMPONENTS_V2 )
9721002 . components ( vec ! [ CreateComponent :: Container ( expired. into_container( ) ) ] ) ;
973- if let Err ( e) = message . clone ( ) . edit ( http, edit) . await {
1003+ if let Err ( e) = channel_id . widen ( ) . edit_message ( http, message_id , edit) . await {
9741004 error ! ( "failed to edit expired suggestion message: {e}" ) ;
9751005 }
9761006 return Ok ( ( ) ) ;
9771007 } ;
9781008
9791009 let staff_id = interaction. user . id ;
9801010
981- match interaction. data . custom_id . as_str ( ) {
1011+ let action = interaction
1012+ . data
1013+ . custom_id
1014+ . split ( ':' )
1015+ . next ( )
1016+ . unwrap_or ( "" ) ;
1017+
1018+ match action {
9821019 "approve" => {
9831020 let updated = data
9841021 . playmatch_client
@@ -1010,14 +1047,16 @@ async fn handle_suggestion_message(data: SuggestionMessageHandleData) -> Command
10101047 )
10111048 . await ?;
10121049
1013- let mut dm = Card :: new ( Status :: Success , "Suggestion Approved" )
1014- . row ( display_type. to_string ( ) , data. name . clone ( ) ) ;
1015- if matches ! ( data. r#type, SuggestionType :: Game ) {
1016- dm = dm. row ( "ROMs updated" , updated. updated . to_string ( ) ) ;
1017- }
1018- dm = dm. text ( "Thanks for contributing." ) ;
1019- if let Err ( e) = author. id . dm ( http, dm. into_message ( ) ) . await {
1020- error ! ( "failed to DM submitter on approval: {e}" ) ;
1050+ if let Some ( dm_id) = dm_target {
1051+ let mut dm = Card :: new ( Status :: Success , "Suggestion Approved" )
1052+ . row ( display_type. to_string ( ) , data. name . clone ( ) ) ;
1053+ if matches ! ( data. r#type, SuggestionType :: Game ) {
1054+ dm = dm. row ( "ROMs updated" , updated. updated . to_string ( ) ) ;
1055+ }
1056+ dm = dm. text ( "Thanks for contributing." ) ;
1057+ if let Err ( e) = dm_id. dm ( http, dm. into_message ( ) ) . await {
1058+ error ! ( "failed to DM submitter on approval: {e}" ) ;
1059+ }
10211060 }
10221061 }
10231062 "decline" => {
@@ -1047,15 +1086,20 @@ async fn handle_suggestion_message(data: SuggestionMessageHandleData) -> Command
10471086 )
10481087 . await ?;
10491088
1050- let dm = Card :: new ( Status :: Error , "Suggestion Declined" )
1051- . row ( display_type. to_string ( ) , data. name . clone ( ) )
1052- . text ( "If you'd like context, reach out to the Playmatch team." ) ;
1053- if let Err ( e) = author. id . dm ( http, dm. into_message ( ) ) . await {
1054- error ! ( "failed to DM submitter on decline: {e}" ) ;
1089+ if let Some ( dm_id) = dm_target {
1090+ let dm = Card :: new ( Status :: Error , "Suggestion Declined" )
1091+ . row ( display_type. to_string ( ) , data. name . clone ( ) )
1092+ . text ( "If you'd like context, reach out to the Playmatch team." ) ;
1093+ if let Err ( e) = dm_id. dm ( http, dm. into_message ( ) ) . await {
1094+ error ! ( "failed to DM submitter on decline: {e}" ) ;
1095+ }
10551096 }
10561097 }
10571098 _ => {
1058- warn ! ( "Unexpected button interaction" ) ;
1099+ warn ! (
1100+ "Unexpected button interaction custom_id: {}" ,
1101+ interaction. data. custom_id
1102+ ) ;
10591103 }
10601104 }
10611105
0 commit comments