Skip to content

Commit 697a56c

Browse files
authored
Merge pull request ib-ai#79 from ib-ai/button-roles
Button roles
2 parents cef3075 + b77ea17 commit 697a56c

File tree

14 files changed

+535
-4
lines changed

14 files changed

+535
-4
lines changed

Dockerfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Using maven base image for building with maven.
2-
FROM maven:latest AS builder
2+
FROM maven:3.8.1-openjdk-11 AS builder
33

44
LABEL "repository"="https://github.com/ib-ai/IB.ai/"
55
LABEL "homepage"="https://discord.gg/IBO/"
@@ -14,7 +14,8 @@ RUN mvn dependency:go-offline
1414

1515
# Build from source into ./target/*.jar
1616
COPY src ./src
17-
RUN mvn -e -B package
17+
# We don't want checkstyle in development...
18+
RUN mvn -e -B package -Dcheckstyle.skip
1819

1920
# Using Java JDK 10 base image
2021
FROM openjdk:10

lang/en/command_aliases.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
"avatar": ["avatar", "av"],
99
"blacklist": ["blacklist", "hackban"],
10+
"buttonroles": ["buttonrole", "br"],
1011
"cassowary": ["cassowary", "casso"],
1112
"catpic": ["catpic", "cat"],
1213
"channelorder": ["channelorder", "co"],

lang/en/error.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"blacklist_fail": "Blacklist failed. Is the ID correct and valid?",
99
"blacklist_id": "You need to specify a valid number ID.",
1010
"blacklist_present": "You cannot blacklist someone who is already on the server. If you would like to get rid of them please ban them manually.",
11+
"buttonrole_integrity": "One of the integrity constraints were violated. Need a non-empty array, each element consisting of colour (primary|secondary|success|danger), ?emoji, ?row, label (80) and a non-empty array of roles. More than 4 roles per element is not allowed.",
1112
"cassowary_id": "One or more of the role IDs you entered was invalid.",
1213
"category_invalid": "The category provided is invalid or does not exist.",
1314
"embed_field_format": "Please provide the field in the following form: `\"Title\" \"Value\"`",

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@
185185
<dependency>
186186
<groupId>net.dv8tion</groupId>
187187
<artifactId>JDA</artifactId>
188-
<version>4.2.1_256</version>
188+
<version>4.2.1_266</version>
189189
</dependency>
190190
<dependency>
191191
<groupId>ch.qos.logback</groupId>

src/main/java/com/ibdiscord/IBai.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.ibdiscord.exceptions.JavaVersionException;
2626
import com.ibdiscord.i18n.LocaleException;
2727
import com.ibdiscord.i18n.LocaliserHandler;
28+
import com.ibdiscord.listeners.ButtonListener;
2829
import com.ibdiscord.listeners.FilterListener;
2930
import com.ibdiscord.listeners.GuildListener;
3031
import com.ibdiscord.listeners.MessageListener;
@@ -101,7 +102,9 @@ private void init() {
101102
config.getBotVersion(),
102103
config.getStaticPrefix()))
103104
)
104-
.addEventListeners(new FilterListener(),
105+
.setRawEventsEnabled(true)
106+
.addEventListeners(new ButtonListener(),
107+
new FilterListener(),
105108
new GuildListener(),
106109
new MessageListener(),
107110
new MonitorListener(),
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* Copyright 2017-2021 Arraying
2+
*
3+
* This file is part of IB.ai.
4+
*
5+
* IB.ai is free software: you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* IB.ai is distributed in the hope that it will be useful, but
11+
* WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with IB.ai. If not, see http://www.gnu.org/licenses/.
17+
*/
18+
19+
package com.ibdiscord.button;
20+
21+
import net.dv8tion.jda.api.JDA;
22+
import net.dv8tion.jda.api.utils.data.DataObject;
23+
import net.dv8tion.jda.internal.requests.Requester;
24+
import net.dv8tion.jda.internal.requests.RestActionImpl;
25+
import net.dv8tion.jda.internal.requests.Route;
26+
import okhttp3.RequestBody;
27+
28+
/**
29+
* Wrapper for an interaction callback.
30+
*/
31+
public final class ButtonCallbackAction extends RestActionImpl<Void> {
32+
33+
private final int added;
34+
private final int removed;
35+
36+
/**
37+
* Creates the callback.
38+
* @param api The API.
39+
* @param id The ID.
40+
* @param token The token.
41+
* @param added The number of roles added.
42+
* @param removed The number of roles removed.
43+
*/
44+
public ButtonCallbackAction(JDA api, String id, String token, int added, int removed) {
45+
super(api, Route.post(String.format("/interactions/%s/%s/callback", id, token)).compile());
46+
this.added = added;
47+
this.removed = removed;
48+
}
49+
50+
/**
51+
* Sends the correct payload.
52+
* @return The payload.
53+
*/
54+
@Override
55+
protected RequestBody finalizeData() {
56+
DataObject dataObject = DataObject.empty();
57+
dataObject.put("type", 4);
58+
DataObject message = DataObject.empty();
59+
String content;
60+
if (added > 0 && removed == 0) {
61+
content = "Added " + added + " role(s).";
62+
} else if (removed > 0 && added == 0) {
63+
content = "Removed " + removed + " role(s).";
64+
} else if(added > 0 && removed > 0) {
65+
content = "Added " + added + " role(s) and removed " + removed + " role(s).";
66+
} else {
67+
content = "Did not update roles";
68+
}
69+
message.put("content", content);
70+
message.put("flags", 64); // Only send to the user.
71+
dataObject.put("data", message);
72+
return RequestBody.create(Requester.MEDIA_TYPE_JSON, dataObject.toJson());
73+
}
74+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* Copyright 2017-2021 Arraying
2+
*
3+
* This file is part of IB.ai.
4+
*
5+
* IB.ai is free software: you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* IB.ai is distributed in the hope that it will be useful, but
11+
* WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with IB.ai. If not, see http://www.gnu.org/licenses/.
17+
*/
18+
19+
package com.ibdiscord.button;
20+
21+
/**
22+
* Different types a button can be.
23+
* Omitted: link.
24+
*/
25+
public enum ButtonColour {
26+
27+
/**
28+
* Discord Blue.
29+
*/
30+
PRIMARY,
31+
32+
/**
33+
* Grey.
34+
*/
35+
SECONDARY,
36+
37+
/**
38+
* Green.
39+
*/
40+
SUCCESS,
41+
42+
/**
43+
* Red.
44+
*/
45+
DANGER
46+
47+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* Copyright 2017-2021 Arraying
2+
*
3+
* This file is part of IB.ai.
4+
*
5+
* IB.ai is free software: you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* IB.ai is distributed in the hope that it will be useful, but
11+
* WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with IB.ai. If not, see http://www.gnu.org/licenses/.
17+
*/
18+
19+
package com.ibdiscord.button;
20+
21+
import lombok.RequiredArgsConstructor;
22+
import net.dv8tion.jda.api.utils.data.DataObject;
23+
24+
import java.util.regex.Pattern;
25+
26+
/**
27+
* Represents a button emoji.
28+
*/
29+
@RequiredArgsConstructor
30+
public final class ButtonEmoji {
31+
32+
private static Pattern EMOTE_PATTERN = Pattern.compile("^<(?:a)?:(\\S{2,32}):(\\d{17,20})>$");
33+
private final boolean emoji;
34+
private final String id;
35+
private final String name;
36+
private final boolean animated;
37+
38+
/**
39+
* Gets the emoji from a string.
40+
* @param input The string.
41+
* @return A possibly null emoji.
42+
*/
43+
public static ButtonEmoji parse(String input) {
44+
if (input == null) {
45+
return null;
46+
}
47+
input = input.trim();
48+
if (EMOTE_PATTERN.matcher(input).matches()) {
49+
String[] pieces = input.split(":");
50+
String animated = pieces[1];
51+
String name = pieces[1];
52+
String id = pieces[2].replaceAll("\\D", "");
53+
return new ButtonEmoji(false, id, name, animated.contains("a"));
54+
} else {
55+
return new ButtonEmoji(true, null, input, false);
56+
}
57+
}
58+
59+
/**
60+
* Wraps the emoji as JSON.
61+
* @return A JSON object.
62+
*/
63+
public DataObject get() {
64+
DataObject dataObject = DataObject.empty();
65+
if (emoji) {
66+
dataObject.putNull("id");
67+
dataObject.put("name", name);
68+
} else {
69+
dataObject.put("id", id);
70+
dataObject.put("name", name);
71+
dataObject.put("animated", animated);
72+
}
73+
return dataObject;
74+
}
75+
76+
/**
77+
* Debugging friendly representation.
78+
* @return The string.
79+
*/
80+
@Override
81+
public String toString() {
82+
return "ButtonEmoji{"
83+
+ "emoji=" + emoji
84+
+ ", id='" + id + '\''
85+
+ ", name='" + name + '\''
86+
+ ", animated=" + animated
87+
+ '}';
88+
}
89+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/* Copyright 2017-2021 Arraying
2+
*
3+
* This file is part of IB.ai.
4+
*
5+
* IB.ai is free software: you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* IB.ai is distributed in the hope that it will be useful, but
11+
* WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with IB.ai. If not, see http://www.gnu.org/licenses/.
17+
*/
18+
19+
package com.ibdiscord.button;
20+
21+
import net.dv8tion.jda.api.JDA;
22+
import net.dv8tion.jda.api.entities.MessageChannel;
23+
import net.dv8tion.jda.api.entities.TextChannel;
24+
import net.dv8tion.jda.api.utils.data.DataArray;
25+
import net.dv8tion.jda.api.utils.data.DataObject;
26+
import net.dv8tion.jda.internal.requests.Route;
27+
import net.dv8tion.jda.internal.requests.restaction.MessageActionImpl;
28+
29+
import java.util.List;
30+
31+
public final class ButtonMessageAction extends MessageActionImpl {
32+
33+
private final List<ButtonRole> buttons;
34+
35+
/**
36+
* Creates the new action.
37+
* @param api The API.
38+
* @param route The route.
39+
* @param channel The channel.
40+
* @param message The message to send.
41+
* @param buttons The buttons.
42+
*/
43+
private ButtonMessageAction(JDA api, Route.CompiledRoute route, MessageChannel channel, String message, List<ButtonRole> buttons) {
44+
super(api, route, channel, new StringBuilder().append(message));
45+
this.buttons = buttons;
46+
}
47+
48+
/**
49+
* Creates a message which has button reactions.
50+
* This will use one action row.
51+
* @param channel The channel.
52+
* @param message The message to send.
53+
* @param roles A list of button reaction roles.
54+
* @return An action, which can be queued.
55+
*/
56+
public static ButtonMessageAction create(TextChannel channel, String message, List<ButtonRole> roles) {
57+
Route.CompiledRoute route = Route.Messages.SEND_MESSAGE.compile(channel.getId());
58+
return new ButtonMessageAction(channel.getJDA(), route, channel, message, roles);
59+
}
60+
61+
/**
62+
* Gets the message as JSON.
63+
* Here, we inject the custom button stuff.
64+
* @return A data object of messages.
65+
*/
66+
@Override
67+
protected DataObject getJSON() {
68+
final DataObject dataObject = super.getJSON();
69+
final DataArray componentsOuter = DataArray.empty();
70+
for (int i = 0; i < 5; i++) {
71+
final DataObject actionRow = DataObject.empty();
72+
final DataArray componentsInner = DataArray.empty();
73+
for (ButtonRole button : buttons) {
74+
if (button.getRow() != i) {
75+
continue;
76+
}
77+
DataObject clickable = DataObject.empty();
78+
clickable.put("type", 2);
79+
clickable.put("label", button.getName());
80+
clickable.put("style", button.getColour().ordinal() + 1);
81+
clickable.put("custom_id", button.getRoles());
82+
if (button.getEmoji() != null) {
83+
clickable.put("emoji", button.getEmoji().get());
84+
}
85+
componentsInner.add(clickable);
86+
}
87+
if (componentsInner.length() > 0) {
88+
actionRow.put("type", 1);
89+
actionRow.put("components", componentsInner);
90+
componentsOuter.add(actionRow);
91+
}
92+
}
93+
dataObject.put("components", componentsOuter);
94+
return dataObject;
95+
}
96+
}

0 commit comments

Comments
 (0)