4848import org .jetbrains .annotations .VisibleForTesting ;
4949import org .slf4j .Logger ;
5050import org .slf4j .LoggerFactory ;
51+ import org .w3c .dom .Document ;
5152
53+ import javax .xml .parsers .DocumentBuilder ;
54+ import javax .xml .parsers .DocumentBuilderFactory ;
55+ import java .io .ByteArrayInputStream ;
5256import java .time .Instant ;
5357import java .util .ArrayList ;
5458import java .util .Arrays ;
5559import java .util .List ;
60+ import java .util .Map ;
5661import java .util .concurrent .atomic .AtomicBoolean ;
5762import java .util .concurrent .atomic .AtomicInteger ;
63+ import java .util .stream .Collectors ;
5864
5965public class CmdCodeMC extends BotCommand {
6066
@@ -76,7 +82,8 @@ public CmdCodeMC(CodeMCBot bot) {
7682 new ChangePassword (bot ),
7783 new CreateUser (bot ),
7884 new DeleteUser (bot ),
79- new MyStatus (bot )
85+ new MyStatus (bot ),
86+ new Help (bot )
8087 };
8188 }
8289
@@ -420,48 +427,194 @@ public void withHookReply(InteractionHook hook, SlashCommandEvent event, Guild g
420427 @ VisibleForTesting
421428 @ NotNull
422429 MessageEmbed build (String username ) {
423- int totalUsers = JenkinsAPI .getAllJenkinsUsers ().size ();
424- int totalRepositories = NexusAPI .getRepositories ().size ();
430+ try {
431+ int totalUsers = JenkinsAPI .getAllJenkinsUsers ().size ();
432+ int totalRepositories = NexusAPI .getRepositories ().size ();
433+
434+ String jenkinsUrl = bot .getConfigHandler ().getString ("jenkins" , "url" );
435+ String nexusUrl = bot .getConfigHandler ().getString ("nexus" , "url" );
436+
437+
438+ EmbedBuilder embed = CommandUtil .getEmbed ()
439+ .setTitle ("CodeMC Account Status for " + username )
440+ .setDescription ("Total Jenkins Users: " + totalUsers + "\n Total Nexus Repositories: " + totalRepositories )
441+ .setTimestamp (Instant .now ());
442+
443+ boolean jenkinsExists = JenkinsAPI .existsUser (username );
444+ if (jenkinsExists ) {
445+ String config = JenkinsAPI .getJenkinsUser (username );
446+ embed .addField ("Jenkins Account" , jenkinsUrl + "/job/" + username , true );
447+
448+ if (config .contains ("com.cloudbees.hudson.plugins.folder.properties.AuthorizationMatrixProperty" )) {
449+ embed .addField ("Jenkins Permissions" , "Contains Authorization Matrix" , true );
450+ } else {
451+ embed .addField ("Jenkins Permissions" , MarkdownUtil .underline ("Missing Authorization Matrix" ), true );
452+ }
453+
454+ if (config .contains ("<id>nexus-repository</id>" )) {
455+ embed .addField ("Jenkins Nexus Credentials" , "Nexus Repository Credentials Added" , true );
456+ } else {
457+ embed .addField ("Jenkins Nexus Credentials" , MarkdownUtil .underline ("Nexus Repository Not Linked" ), true );
458+ }
459+ } else {
460+ embed .addField ("Jenkins Account" , MarkdownUtil .underline ("Does Not Exist" ), true );
461+ }
462+
463+ JsonObject nexusInfo = NexusAPI .getNexusRepository (username );
464+ boolean nexusExists = nexusInfo != null && !nexusInfo .isEmpty ();
465+
466+ if (nexusExists ) {
467+ embed .addField ("Nexus Repository" , nexusUrl + "/#browse/browse:" + username .toLowerCase (), true );
468+
469+ JsonObject user = NexusAPI .getNexusUser (username .toLowerCase ());
470+ String userId = ((JsonPrimitive ) user .get ("userId" )).getContent ();
471+ String roles = ((JsonArray ) user .get ("roles" ))
472+ .stream ()
473+ .map (role -> ((JsonPrimitive ) role ).getContent ())
474+ .collect (Collectors .joining ("\n - " , "- " , "" ));
475+
476+ embed .addField ("Nexus User ID" , userId , true );
477+ embed .addField ("Nexus Roles" , roles , false );
478+
479+ JsonObject role = NexusAPI .getNexusRole (username .toLowerCase ());
480+ String privileges = ((JsonArray ) role .get ("privileges" ))
481+ .stream ()
482+ .map (priv -> ((JsonPrimitive ) priv ).getContent ())
483+ .collect (Collectors .joining ("\n - " , "- " , "" ));
484+
485+ embed .addField ("Nexus Privileges" , privileges , false );
486+ } else embed .addField ("Nexus Repository" , MarkdownUtil .underline ("Does Not Exist" ), true );
487+
488+ return embed .build ();
489+ } catch (Exception e ) {
490+ LOGGER .error ("Failed to build MyStatus embed for user '{}'" , username , e );
491+ return CommandUtil .getEmbed ()
492+ .setTitle ("CodeMC Account Status for " + username )
493+ .setDescription ("An error occurred while fetching your account status." )
494+ .setTimestamp (Instant .now ())
495+ .build ();
496+ }
497+ }
498+ }
425499
426- String jenkinsUrl = bot . getConfigHandler (). getString ( "jenkins" , "url" );
427- String nexusUrl = bot . getConfigHandler (). getString ( "nexus" , "url" );
500+ @ VisibleForTesting
501+ static class Help extends BotCommand {
428502
429- boolean jenkinsExists = JenkinsAPI .existsUser (username );
503+ public Help (CodeMCBot bot ) {
504+ super (bot );
430505
431- JsonObject nexusInfo = NexusAPI .getNexusRepository (username );
432- boolean nexusExists = nexusInfo != null && !nexusInfo .isEmpty ();
506+ this .name = "help" ;
507+ this .help = "Displays help information for CodeMC commands." ;
508+ }
509+
510+ @ Override
511+ public void withModalReply (SlashCommandEvent event ) {
512+ }
513+
514+ @ Override
515+ public void withHookReply (InteractionHook hook , SlashCommandEvent event , Guild guild , Member member ) {
516+ List <Role > roles = member .getRoles ();
517+ boolean isAuthor = roles .stream ()
518+ .anyMatch (role -> role .getIdLong () == bot .getConfigHandler ().getLong ("author_role" ));
519+
520+ List <Long > reviewerRoles = bot .getConfigHandler ().getLongList ("allowed_roles" , "commands" , "application" );
521+ boolean isReviewer = roles .stream ()
522+ .anyMatch (role -> reviewerRoles .contains (role .getIdLong ()));
523+
524+ List <Long > adminRoles = bot .getConfigHandler ().getLongList ("allowed_roles" , "commands" , "codemc" );
525+ boolean isAdmin = roles .stream ()
526+ .anyMatch (role -> adminRoles .contains (role .getIdLong ()));
433527
434528 EmbedBuilder embed = CommandUtil .getEmbed ()
435- .setTitle ("CodeMC Account Status for " + username )
436- .setDescription ("Total Jenkins Users: " + totalUsers + "\n Total Nexus Repositories: " + totalRepositories )
437- .setTimestamp (Instant .now ());
529+ .setTitle ("CodeMC Command Help" )
530+ .setDescription ("Here is a list of available commands:" );
438531
439- if (jenkinsExists ) embed .addField ("Jenkins Account" , jenkinsUrl + "/job/" + username , true );
440- else embed .addField ("Jenkins Account" , MarkdownUtil .underline ("Does Not Exist" ), true );
441-
442- if (nexusExists ) {
443- embed .addField ("Nexus Repository" , nexusUrl + "/#browse/browse:" + username .toLowerCase (), true );
444-
445- JsonObject user = NexusAPI .getNexusUser (username .toLowerCase ());
446- String userId = ((JsonPrimitive ) user .get ("userId" )).getContent ();
447- String roles = ((JsonArray ) user .get ("roles" ))
448- .stream ()
449- .map (role -> ((JsonPrimitive ) role ).getContent ())
450- .reduce ((a , b ) -> "- " + a + "\n - " + b )
451- .orElse ("None" );
452- embed .addField ("Nexus User ID" , userId , true );
453- embed .addField ("Nexus Roles" , roles , false );
454-
455- JsonObject role = NexusAPI .getNexusRole (username .toLowerCase ());
456- String privileges = ((JsonArray ) role .get ("privileges" ))
457- .stream ()
458- .map (priv -> ((JsonPrimitive ) priv ).getContent ())
459- .reduce ((a , b ) -> "- " + a + "\n - " + b )
460- .orElse ("None" );
461- embed .addField ("Nexus Privileges" , privileges , false );
462- } else embed .addField ("Nexus Repository" , MarkdownUtil .underline ("Does Not Exist" ), true );
532+ userHelp (embed );
463533
464- return embed .build ();
534+ if (isReviewer ) {
535+ reviewerHelp (embed );
536+ }
537+
538+ if (isAuthor ) {
539+ authorHelp (embed );
540+ }
541+
542+ if (isAdmin ) {
543+ adminHelp (embed );
544+ }
545+
546+ embed .setTimestamp (Instant .now ());
547+
548+ hook .sendMessageEmbeds (embed .build ())
549+ .setEphemeral (true )
550+ .queue ();
551+ }
552+
553+ @ VisibleForTesting
554+ void userHelp (EmbedBuilder builder ) {
555+ Map <String , String > commands = Map .of (
556+ "/codemc help" , "Displays this help message." ,
557+ "/codemc jenkins" , "Fetch information about a Jenkins Author." ,
558+ "/codemc nexus" , "Fetch information about a Nexus Repository."
559+ );
560+
561+ for (Map .Entry <String , String > entry : commands .entrySet ()) {
562+ builder .addField (entry .getKey (), entry .getValue (), false );
563+ }
564+
565+ builder .setFooter ("User View" );
566+ }
567+
568+ @ VisibleForTesting
569+ void authorHelp (EmbedBuilder builder ) {
570+ builder .addBlankField (false );
571+
572+ Map <String , String > commands = Map .of (
573+ "/codemc my-status" , "Check the status of your CodeMC Jenkins and Nexus accounts. This will usually report any issues with your accounts, and will help administrators with diagnosing issues." ,
574+ "/codemc change-password" , "Regenerates your Nexus Credentials. Useful if you suspect they have been compromised, or if they are not working."
575+ );
576+
577+ for (Map .Entry <String , String > entry : commands .entrySet ()) {
578+ builder .addField (entry .getKey (), entry .getValue (), false );
579+ }
580+
581+ builder .setFooter ("Author View" );
582+ }
583+
584+ @ VisibleForTesting
585+ void reviewerHelp (EmbedBuilder builder ) {
586+ builder .addBlankField (false );
587+
588+ Map <String , String > commands = Map .of (
589+ "/application accept" , "Accepts a user's application for Author status." ,
590+ "/application deny" , "Denies a user's application for Author status."
591+ );
592+
593+ for (Map .Entry <String , String > entry : commands .entrySet ()) {
594+ builder .addField (entry .getKey (), entry .getValue (), false );
595+ }
596+
597+ builder .setFooter ("Reviewer View" );
598+ }
599+
600+ @ VisibleForTesting
601+ void adminHelp (EmbedBuilder builder ) {
602+ builder .addBlankField (false );
603+
604+ Map <String , String > commands = Map .of (
605+ "/codemc validate" , "Performs a validation check on all or a specific user's existing jenkins credentials. Useful for regenerating credentials for a user." ,
606+ "/codemc remove" , "Removes a user from the CodeMC Services, and revokes their Author role." ,
607+ "/codemc link" , "Links a Discord User to a Jenkins/Nexus User. If it currently exists, it will be overridden." ,
608+ "/codemc unlink" , "Unlinks a discord user from their Jenkins/Nexus account." ,
609+ "/codemc createuser" , "Creates a new user in the Jenkins/Nexus services. Useful if user configuration is corrupted and recreation is necesssary. You can specify a user to link it to." ,
610+ "/codemc deluser" , "Deletes a user in the Jenkins/Nexus services. Useful if user configuration is corrupted and recreation is necesssary. Does not affect discord roles."
611+ );
612+
613+ for (Map .Entry <String , String > entry : commands .entrySet ()) {
614+ builder .addField (entry .getKey (), entry .getValue (), false );
615+ }
616+
617+ builder .setFooter ("Administrator View" );
465618 }
466619 }
467620
0 commit comments