Skip to content

Commit 6ac33cd

Browse files
Tais993nltbee
authored andcommitted
Added WhoIs command
1 parent 16d66b5 commit 6ac33cd

File tree

2 files changed

+263
-0
lines changed

2 files changed

+263
-0
lines changed

application/src/main/java/org/togetherjava/tjbot/commands/Features.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public enum Features {
8787
features.add(new RoleSelectCommand());
8888
features.add(new NoteCommand(actionsStore, config));
8989
features.add(new RemindCommand(database));
90+
features.add(new WhoIsCommand());
9091

9192
// Mixtures
9293
features.add(new FreeCommand(config));
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
package org.togetherjava.tjbot.commands.moderation;
2+
3+
import net.dv8tion.jda.api.EmbedBuilder;
4+
import net.dv8tion.jda.api.entities.GuildVoiceState;
5+
import net.dv8tion.jda.api.entities.Member;
6+
import net.dv8tion.jda.api.entities.Role;
7+
import net.dv8tion.jda.api.entities.User;
8+
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
9+
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
10+
import net.dv8tion.jda.api.interactions.commands.OptionType;
11+
import net.dv8tion.jda.api.interactions.components.Button;
12+
import net.dv8tion.jda.api.interactions.components.ButtonStyle;
13+
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyAction;
14+
import org.jetbrains.annotations.NotNull;
15+
import org.togetherjava.tjbot.commands.SlashCommandAdapter;
16+
import org.togetherjava.tjbot.commands.SlashCommandVisibility;
17+
import org.togetherjava.tjbot.commands.utils.DiscordClientAction;
18+
19+
import javax.annotation.CheckReturnValue;
20+
import java.awt.*;
21+
import java.time.Instant;
22+
import java.time.OffsetDateTime;
23+
import java.time.format.DateTimeFormatter;
24+
import java.util.Collection;
25+
import java.util.Objects;
26+
import java.util.stream.Collectors;
27+
28+
/**
29+
* This command allows you to look up user (or member) info.
30+
*/
31+
@SuppressWarnings("ClassWithoutLogger")
32+
public final class WhoIsCommand extends SlashCommandAdapter {
33+
private static final String USER_OPTION = "user";
34+
private static final String SHOW_SERVER_INFO_OPTION = "show_server_specific_info";
35+
36+
private static final String USER_PROFILE_PICTURE_SIZE = "4096";
37+
38+
// Sun, December 11, 2016, 13:36:30
39+
private static final DateTimeFormatter DATE_TIME_FORMAT =
40+
DateTimeFormatter.ofPattern("E, MMMM d, u, HH:mm:ss");
41+
42+
/**
43+
* Creates an instance.
44+
*/
45+
public WhoIsCommand() {
46+
super("whois", "Provides info about the given user", SlashCommandVisibility.GUILD);
47+
48+
getData().addOption(OptionType.USER, USER_OPTION, "the user to look up", true)
49+
.addOption(OptionType.BOOLEAN, SHOW_SERVER_INFO_OPTION,
50+
"Whenever to show info that is specific to this server, such as their roles. This is true by default.",
51+
false);
52+
}
53+
54+
@Override
55+
public void onSlashCommand(@NotNull final SlashCommandEvent event) {
56+
OptionMapping userOption = Objects.requireNonNull(event.getOption(USER_OPTION),
57+
"The given user option cannot be null");
58+
OptionMapping showServerSpecificInfoOption = event.getOption(SHOW_SERVER_INFO_OPTION);
59+
60+
User user = userOption.getAsUser();
61+
Member member = userOption.getAsMember();
62+
63+
boolean showServerSpecificInfo = null != member && (null == showServerSpecificInfoOption
64+
|| showServerSpecificInfoOption.getAsBoolean());
65+
66+
user.retrieveProfile().flatMap((User.Profile profile) -> {
67+
if (showServerSpecificInfo) {
68+
return handleWhoIsMember(event, member, profile);
69+
} else {
70+
return handleWhoIsUser(event, user, profile);
71+
}
72+
}).queue();
73+
}
74+
75+
@CheckReturnValue
76+
private static @NotNull ReplyAction handleWhoIsUser(final @NotNull SlashCommandEvent event,
77+
final @NotNull User user, final @NotNull User.Profile profile) {
78+
79+
StringBuilder descriptionBuilder =
80+
new StringBuilder().append(userIdentificationToStringItem(user))
81+
.append("\n**Is bot:** ")
82+
.append(user.isBot())
83+
.append(userFlagsToStringItem(user.getFlags()))
84+
.append("\n**Registration date:** ")
85+
.append(DATE_TIME_FORMAT.format(user.getTimeCreated()));
86+
87+
EmbedBuilder embedBuilder =
88+
generateEmbedBuilder(event, user, profile, profile.getAccentColor()).setAuthor(
89+
user.getName(), user.getEffectiveAvatarUrl(), user.getEffectiveAvatarUrl())
90+
.setDescription(descriptionBuilder);
91+
92+
return event.replyEmbeds(embedBuilder.build())
93+
.addActionRow(Button.of(ButtonStyle.LINK, "discord://-/users/" + user.getId(),
94+
"Click to see profile"));
95+
}
96+
97+
@CheckReturnValue
98+
private static @NotNull ReplyAction handleWhoIsMember(final @NotNull SlashCommandEvent event,
99+
final @NotNull Member member, final @NotNull User.Profile profile) {
100+
User user = member.getUser();
101+
102+
Color memberColor = member.getColor();
103+
Color effectiveColor = (null == memberColor) ? profile.getAccentColor() : memberColor;
104+
105+
StringBuilder descriptionBuilder =
106+
new StringBuilder().append(userIdentificationToStringItem(user))
107+
.append(voiceStateToStringItem(member))
108+
.append("\n**Is bot:** ")
109+
.append(user.isBot())
110+
.append(possibleBoosterToStringItem(member))
111+
.append(userFlagsToStringItem(user.getFlags()))
112+
.append("\n**Join date:** ")
113+
.append(DATE_TIME_FORMAT.format(member.getTimeJoined()))
114+
.append("\n**Registration date:** ")
115+
.append(DATE_TIME_FORMAT.format(user.getTimeCreated()))
116+
.append("\n**Roles:** ")
117+
.append(formatRoles(member));
118+
119+
EmbedBuilder embedBuilder = generateEmbedBuilder(event, user, profile, effectiveColor)
120+
.setAuthor(member.getEffectiveName(), member.getEffectiveAvatarUrl(),
121+
member.getEffectiveAvatarUrl())
122+
.setDescription(descriptionBuilder);
123+
124+
return event.replyEmbeds(embedBuilder.build())
125+
.addActionRow(DiscordClientAction.General.USER.asLinkButton("Click to see profile!", user.getId()));
126+
}
127+
128+
private static @NotNull String voiceStateToStringItem(@NotNull final Member member) {
129+
GuildVoiceState voiceState = Objects.requireNonNull(member.getVoiceState(),
130+
"The given voiceState cannot be null");
131+
if (voiceState.inVoiceChannel()) {
132+
return "\n**In voicechannel:** " + (voiceState.getChannel().getAsMention());
133+
} else {
134+
return "";
135+
}
136+
}
137+
138+
139+
/**
140+
* Generates whois embed based on the given parameters.
141+
*
142+
* @param event the {@link SlashCommandEvent}
143+
* @param user the {@link User} getting whois'd
144+
* @param profile the {@link net.dv8tion.jda.api.entities.User.Profile} of the whois'd user
145+
* @param effectiveColor the {@link Color} that the embed will become
146+
* @return the generated {@link EmbedBuilder}
147+
*/
148+
private static @NotNull EmbedBuilder generateEmbedBuilder(
149+
@NotNull final SlashCommandEvent event, @NotNull final User user,
150+
final @NotNull User.Profile profile, final Color effectiveColor) {
151+
152+
EmbedBuilder embedBuilder = new EmbedBuilder().setThumbnail(user.getEffectiveAvatarUrl())
153+
.setColor(effectiveColor)
154+
.setFooter("Requested by " + event.getUser().getAsTag(),
155+
event.getMember().getEffectiveAvatarUrl())
156+
.setTimestamp(Instant.now());
157+
158+
if (null != profile.getBannerId()) {
159+
embedBuilder.setImage(profile.getBannerUrl() + "?size=" + USER_PROFILE_PICTURE_SIZE);
160+
}
161+
162+
return embedBuilder;
163+
}
164+
165+
/**
166+
* Handles boosting properties of a {@link Member}
167+
*
168+
* @param member the {@link Member} to take the booster properties from
169+
* @return user readable {@link String}
170+
*/
171+
private static @NotNull String possibleBoosterToStringItem(final @NotNull Member member) {
172+
OffsetDateTime timeBoosted = member.getTimeBoosted();
173+
if (null != timeBoosted) {
174+
return "\n**Is booster:** true \n**Boosting since:** "
175+
+ DATE_TIME_FORMAT.format(timeBoosted);
176+
} else {
177+
return "\n**Is booster:** false";
178+
}
179+
}
180+
181+
/**
182+
* Handles the user's identifying properties (such as ID, tag)
183+
*
184+
* @param user the {@link User} to take the identifiers from
185+
* @return user readable {@link StringBuilder}
186+
*/
187+
private static @NotNull StringBuilder userIdentificationToStringItem(final @NotNull User user) {
188+
return new StringBuilder("**Mention:** ").append(user.getAsMention())
189+
.append("\n**Tag:** ")
190+
.append(user.getAsTag())
191+
.append("\n**ID:** ")
192+
.append(user.getId());
193+
}
194+
195+
/**
196+
* Formats the roles into a user readable {@link String}
197+
*
198+
* @param member member to take the Roles from
199+
* @return user readable {@link String} of the roles
200+
*/
201+
private static String formatRoles(final @NotNull Member member) {
202+
return member.getRoles().stream().map(Role::getAsMention).collect(Collectors.joining(", "));
203+
}
204+
205+
/**
206+
* Formats Hypesquad and the flags
207+
*
208+
* @param flags the {@link Collection} of {@link net.dv8tion.jda.api.entities.User.UserFlag}
209+
* (recommend {@link java.util.EnumSet}
210+
* @return user readable {@link StringBuilder}
211+
*/
212+
private static @NotNull StringBuilder userFlagsToStringItem(
213+
final @NotNull Collection<User.UserFlag> flags) {
214+
String formattedFlags = formatUserFlags(flags);
215+
216+
if (formattedFlags.isBlank()) {
217+
return hypeSquadToStringItem(flags);
218+
} else {
219+
return hypeSquadToStringItem(flags).append("\n**Flags:** ")
220+
.append(formatUserFlags(flags));
221+
}
222+
}
223+
224+
/**
225+
* Formats user readable Hypesquad item
226+
*
227+
* @param flags the {@link Collection} of {@link net.dv8tion.jda.api.entities.User.UserFlag}
228+
* (recommend {@link java.util.EnumSet}
229+
* @return user readable {@link StringBuilder}
230+
*/
231+
private static @NotNull StringBuilder hypeSquadToStringItem(
232+
final @NotNull Collection<User.UserFlag> flags) {
233+
StringBuilder stringBuilder = new StringBuilder("**\nHypesquad:** ");
234+
235+
if (flags.contains(User.UserFlag.HYPESQUAD_BALANCE)) {
236+
stringBuilder.append(User.UserFlag.HYPESQUAD_BALANCE.getName());
237+
} else if (flags.contains(User.UserFlag.HYPESQUAD_BRAVERY)) {
238+
stringBuilder.append(User.UserFlag.HYPESQUAD_BRAVERY.getName());
239+
} else if (flags.contains(User.UserFlag.HYPESQUAD_BRILLIANCE)) {
240+
stringBuilder.append(User.UserFlag.HYPESQUAD_BRILLIANCE.getName());
241+
} else {
242+
stringBuilder.append("joined none");
243+
}
244+
245+
return stringBuilder;
246+
}
247+
248+
/**
249+
* Formats the flags into a user readable {@link String}, filters Hypesquad relating flags
250+
*
251+
* @param flags the {@link Collection} of {@link net.dv8tion.jda.api.entities.User.UserFlag}
252+
* (recommend {@link java.util.EnumSet}
253+
* @return the user readable string
254+
*/
255+
@NotNull
256+
private static String formatUserFlags(final @NotNull Collection<User.UserFlag> flags) {
257+
return flags.stream()
258+
.map(User.UserFlag::getName)
259+
.filter(name -> (name.contains("Hypesquad")))
260+
.collect(Collectors.joining(", "));
261+
}
262+
}

0 commit comments

Comments
 (0)