22
33import net .dv8tion .jda .api .EmbedBuilder ;
44import net .dv8tion .jda .api .entities .Guild ;
5+ import net .dv8tion .jda .api .entities .Message ;
56import net .dv8tion .jda .api .entities .MessageEmbed ;
67import net .dv8tion .jda .api .entities .Role ;
78import net .dv8tion .jda .api .entities .User ;
89import net .dv8tion .jda .api .events .interaction .command .SlashCommandInteractionEvent ;
910import net .dv8tion .jda .api .interactions .commands .OptionMapping ;
1011import net .dv8tion .jda .api .interactions .commands .OptionType ;
1112import net .dv8tion .jda .api .interactions .commands .build .SubcommandData ;
13+ import net .dv8tion .jda .api .requests .restaction .WebhookMessageCreateAction ;
14+ import net .dv8tion .jda .api .utils .FileUpload ;
15+ import net .javadiscord .javabot .data .config .BotConfig ;
1216import net .javadiscord .javabot .data .h2db .DbActions ;
1317import net .javadiscord .javabot .systems .help .HelpExperienceService ;
18+ import net .javadiscord .javabot .systems .help .dao .HelpTransactionRepository ;
1419import net .javadiscord .javabot .systems .help .model .HelpAccount ;
20+ import net .javadiscord .javabot .util .Checks ;
1521import net .javadiscord .javabot .util .ExceptionLogger ;
1622import net .javadiscord .javabot .util .Pair ;
23+ import net .javadiscord .javabot .util .Plotter ;
1724import net .javadiscord .javabot .util .Responses ;
1825import net .javadiscord .javabot .util .StringUtils ;
26+
27+ import java .awt .image .BufferedImage ;
28+ import java .io .ByteArrayOutputStream ;
29+ import java .io .IOException ;
30+ import java .time .LocalDate ;
31+ import java .util .ArrayList ;
32+ import java .util .List ;
33+
34+ import javax .imageio .ImageIO ;
35+
1936import org .jetbrains .annotations .NotNull ;
2037import org .springframework .dao .DataAccessException ;
2138import xyz .dynxsty .dih4jda .interactions .commands .application .SlashCommand ;
2744 */
2845public class HelpAccountSubcommand extends SlashCommand .Subcommand {
2946
47+ private final BotConfig botConfig ;
3048 private final DbActions dbActions ;
3149 private final HelpExperienceService helpExperienceService ;
50+ private final HelpTransactionRepository transactionRepository ;
3251
3352 /**
3453 * The constructor of this class, which sets the corresponding {@link SubcommandData}.
3554 *
55+ * @param botConfig The bot configuration
3656 * @param dbActions An object responsible for various database actions
3757 * @param helpExperienceService Service object that handles Help Experience Transactions.
58+ * @param transactionRepository DAO for help XP transactions
3859 */
39- public HelpAccountSubcommand (DbActions dbActions , HelpExperienceService helpExperienceService ) {
60+ public HelpAccountSubcommand (BotConfig botConfig , DbActions dbActions , HelpExperienceService helpExperienceService , HelpTransactionRepository transactionRepository ) {
4061 this .dbActions = dbActions ;
4162 this .helpExperienceService = helpExperienceService ;
63+ this .botConfig = botConfig ;
64+ this .transactionRepository = transactionRepository ;
4265 setCommandData (new SubcommandData ("account" , "Shows an overview of your Help Account." )
4366 .addOption (OptionType .USER , "user" , "If set, show the Help Account of the specified user instead." , false )
67+ .addOption (OptionType .BOOLEAN , "plot" , "generate a plot of help XP history" , false )
4468 );
4569 }
4670
4771 @ Override
4872 public void execute (@ NotNull SlashCommandInteractionEvent event ) {
4973 User user = event .getOption ("user" , event ::getUser , OptionMapping ::getAsUser );
74+ boolean plot = event .getOption ("plot" , false , OptionMapping ::getAsBoolean );
75+
76+ if (plot && user .getIdLong ()!=event .getUser ().getIdLong () && !Checks .hasStaffRole (botConfig , event .getMember ())) {
77+ Responses .error (event , "You can only plot your own help XP history." ).queue ();
78+ return ;
79+ }
80+
5081 long totalThanks = dbActions .count (
5182 "SELECT COUNT(id) FROM help_channel_thanks WHERE helper_id = ?" ,
5283 s -> s .setLong (1 , user .getIdLong ())
@@ -55,15 +86,59 @@ public void execute(@NotNull SlashCommandInteractionEvent event) {
5586 "SELECT COUNT(id) FROM help_channel_thanks WHERE helper_id = ? AND thanked_at > DATEADD('week', -1, CURRENT_TIMESTAMP(0))" ,
5687 s -> s .setLong (1 , user .getIdLong ())
5788 );
89+
90+ event .deferReply ().queue ();
91+
92+ FileUpload upload = null ;
93+ if (plot ) {
94+ upload = generatePlot (user );
95+ }
96+
5897 try {
5998 HelpAccount account = helpExperienceService .getOrCreateAccount (user .getIdLong ());
60- event .replyEmbeds (buildHelpAccountEmbed (account , user , event .getGuild (), totalThanks , weekThanks )).queue ();
99+ WebhookMessageCreateAction <Message > reply = event .getHook ().sendMessageEmbeds (buildHelpAccountEmbed (account , user , event .getGuild (), totalThanks , weekThanks ));
100+ if (upload !=null ) {
101+ reply .addFiles (upload );
102+ }
103+ reply .queue ();
61104 } catch (DataAccessException e ) {
62105 ExceptionLogger .capture (e , getClass ().getSimpleName ());
63106 Responses .error (event , e .getMessage ()).queue ();
64107 }
65108 }
66109
110+ private FileUpload generatePlot (User user ) {
111+ List <Pair <Pair <Integer ,Integer >,Double >> xpData = transactionRepository .getTotalTransactionWeightByMonth (user .getIdLong (), LocalDate .now ().withDayOfMonth (1 ).minusYears (1 ).atStartOfDay ());
112+
113+ if (xpData .isEmpty ()) {
114+ return null ;
115+ }
116+
117+ List <Pair <String , Double >> plotData = new ArrayList <>();
118+
119+ int i = 0 ;
120+ for (LocalDate position = LocalDate .now ().minusYears (1 ); position .isBefore (LocalDate .now ().plusDays (1 )); position =position .plusMonths (1 )) {
121+ double value = 0.0 ;
122+ if (i <xpData .size ()) {
123+ Pair <Pair <Integer , Integer >, Double > entry = xpData .get (i );
124+ if (entry .first ().first () == position .getMonthValue () && entry .first ().second () == position .getYear ()) {
125+ value = Math .round (entry .second ()*100 )/100.0 ;
126+ i ++;
127+ }
128+ }
129+ plotData .add (new Pair <>(position .getMonth () + " " + position .getYear (), value ));
130+ }
131+
132+ BufferedImage plt = new Plotter (plotData ).plot ();
133+ try (ByteArrayOutputStream os = new ByteArrayOutputStream ()){
134+ ImageIO .write (plt , "png" , os );
135+ return FileUpload .fromData (os .toByteArray (), "image.png" );
136+ } catch (IOException e ) {
137+ ExceptionLogger .capture (e , "Cannot create XP plot" );
138+ }
139+ return null ;
140+ }
141+
67142 private @ NotNull MessageEmbed buildHelpAccountEmbed (HelpAccount account , @ NotNull User user , Guild guild , long totalThanks , long weekThanks ) {
68143 return new EmbedBuilder ()
69144 .setAuthor (user .getAsTag (), null , user .getEffectiveAvatarUrl ())
0 commit comments