Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(onboarding): update onboarding to match new docs #208

Merged
merged 1 commit into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.seailz.discordjar.action.guild.onboarding;

import com.seailz.discordjar.DiscordJar;
import com.seailz.discordjar.model.guild.Guild;
import com.seailz.discordjar.utils.URLS;
import com.seailz.discordjar.utils.rest.DiscordRequest;
import com.seailz.discordjar.utils.rest.DiscordResponse;
import com.seailz.discordjar.utils.rest.Response;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.HashMap;
import java.util.List;

public class ModifyOnboardingGuild {

private final Guild guild;
private final DiscordJar discordJar;
private List<Guild.Onboarding.Prompt> prompts;
private List<String> defaultChannelIds;
private int enabled = -1;
private Guild.Onboarding.Mode mode;

public ModifyOnboardingGuild(Guild guild, DiscordJar discordJar) {
this.guild = guild;
this.discordJar = discordJar;
}

public ModifyOnboardingGuild setDefaultChannelIds(List<String> defaultChannelIds) {
this.defaultChannelIds = defaultChannelIds;
return this;
}

public ModifyOnboardingGuild setEnabled(boolean enabled) {
this.enabled = enabled ? 1 : 0;
return this;
}

public ModifyOnboardingGuild setMode(Guild.Onboarding.Mode mode) {
this.mode = mode;
return this;
}

public ModifyOnboardingGuild setPrompts(List<Guild.Onboarding.Prompt> prompts) {
this.prompts = prompts;
return this;
}

public Response<Guild.Onboarding> run() {
Response<Guild.Onboarding> res = new Response<>();
new Thread(() -> {
JSONObject body = new JSONObject();
if (prompts != null) {
JSONArray promptsJson = new JSONArray();
for (Guild.Onboarding.Prompt prompt : prompts) {
promptsJson.put(prompt.compile());
}
body.put("prompts", promptsJson);
}

if (defaultChannelIds != null) {
JSONArray defaultChannelIdsJson = new JSONArray();
for (String defaultChannelId : defaultChannelIds) {
defaultChannelIdsJson.put(defaultChannelId);
}
body.put("default_channel_ids", defaultChannelIdsJson);
}

if (enabled != -1) {
body.put("enabled", enabled == 1);
}

if (mode != null) {
body.put("mode", mode.value());
}

DiscordRequest req = new DiscordRequest(
body,
new HashMap<>(),
URLS.PUT.GUILD.MODIFY_GUILD_ONBOARDING
.replace("{guild.id}", guild.id()),
discordJar,
URLS.PUT.GUILD.MODIFY_GUILD_ONBOARDING,
RequestMethod.PUT
);

try {
DiscordResponse response = req.invoke();
res.complete(Guild.Onboarding.decompile(response.body(), guild, discordJar));
} catch (DiscordRequest.UnhandledDiscordAPIErrorException e) {
res.completeError(new Response.Error(
e.getCode(),
e.getMessage(),
e.getBody()
));
}
}).start();
return res;
}
}
188 changes: 144 additions & 44 deletions src/main/java/com/seailz/discordjar/model/guild/Guild.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
import com.seailz.discordjar.action.automod.AutomodRuleModifyAction;
import com.seailz.discordjar.action.guild.channel.CreateGuildChannelAction;
import com.seailz.discordjar.action.guild.members.RequestGuildMembersAction;
import com.seailz.discordjar.action.guild.onboarding.ModifyOnboardingGuild;
import com.seailz.discordjar.action.sticker.ModifyStickerAction;
import com.seailz.discordjar.cache.JsonCache;
import com.seailz.discordjar.core.Compilerable;
import com.seailz.discordjar.model.application.Intent;
import com.seailz.discordjar.model.automod.AutomodRule;
import com.seailz.discordjar.model.channel.Channel;
import com.seailz.discordjar.model.channel.GuildChannel;
import com.seailz.discordjar.model.channel.MessagingChannel;
import com.seailz.discordjar.model.channel.VoiceChannel;
import com.seailz.discordjar.model.channel.thread.Thread;
import com.seailz.discordjar.model.channel.utils.ChannelType;
import com.seailz.discordjar.model.emoji.Emoji;
Expand All @@ -25,12 +24,10 @@
import com.seailz.discordjar.model.guild.welcome.WelcomeScreen;
import com.seailz.discordjar.model.invite.Invite;
import com.seailz.discordjar.model.invite.InviteMetadata;
import com.seailz.discordjar.model.invite.internal.InviteImpl;
import com.seailz.discordjar.model.invite.internal.InviteMetadataImpl;
import com.seailz.discordjar.model.role.Role;
import com.seailz.discordjar.model.user.User;
import com.seailz.discordjar.utils.*;
import com.seailz.discordjar.cache.JsonCache;
import com.seailz.discordjar.utils.rest.DiscordRequest;
import com.seailz.discordjar.utils.rest.DiscordResponse;
import org.jetbrains.annotations.Contract;
Expand Down Expand Up @@ -1657,6 +1654,9 @@ public String getWidgetImageURL(String style) {
}
}

public ModifyOnboardingGuild modifyOnboarding() {
return new ModifyOnboardingGuild(this, discordJar);
}

/**
* Represents the <a href="https://support.discord.com/hc/en-us/articles/11074987197975-Community-Onboarding-FAQ">onboarding</a> flow for a guild.
Expand All @@ -1669,9 +1669,34 @@ public record Onboarding(
Guild guild,
List<Prompt> prompts,
List<String> defaultChannelIds,
boolean enabled
boolean enabled,
Mode mode
) implements Compilerable {

public enum Mode {
ONBOARDING_DEFAULT(0),
ONBOARDING_ADVANCED(1),
UNKNOWN(-1)
;

private int value;

Mode(int value) {
this.value = value;
}

public int value() {
return value;
}

public static Mode fromValue(int value) {
for (Mode mode : values()) {
if (mode.value == value) return mode;
}
return UNKNOWN;
}
}

@NotNull
@Override
public JSONObject compile() {
Expand All @@ -1680,6 +1705,7 @@ public JSONObject compile() {
obj.put("default_channel_ids", defaultChannelIds);
obj.put("prompts", prompts.stream().map(Prompt::compile).collect(Collectors.toList()));
obj.put("guild_id", guild.id());
obj.put("mode", mode.value());
return obj;
}

Expand All @@ -1688,41 +1714,84 @@ public JSONObject compile() {
public static Onboarding decompile(@NotNull JSONObject obj, @NotNull Guild guild, @NotNull DiscordJar djar) {
return new Onboarding(
guild,
obj.getJSONArray("prompts").toList().stream().map(o -> Prompt.decompile((JSONObject) o, djar)).collect(Collectors.toList()),
obj.getJSONArray("prompts").toList().stream().map(o -> {
HashMap<String, Object> map = (HashMap<String, Object>) o;
JSONObject promptObj = new JSONObject(map);
return Prompt.decompile(promptObj, djar);
}).collect(Collectors.toList()),
obj.getJSONArray("default_channel_ids").toList().stream().map(o -> (String) o).collect(Collectors.toList()),
obj.getBoolean("enabled")
obj.getBoolean("enabled"),
Mode.fromValue(obj.getInt("mode"))
);
}

/**
* Represents a prompt shown during onboarding and in customize community.
*
* @param id ID of the prompt
* @param type Type of prompt
* @param options Options available within the prompt
* @param title Title of the prompt
* @param singleSelect Indicates whether users are limited to selecting one option for the prompt
* @param required Indicates whether the prompt is required before a user completes the onboarding flow
* @param inOnboarding Indicates whether the prompt is present in the onboarding flow. If `false`, the prompt will only appear
* in the Channels & Roles tab.
*/
public record Prompt(
String id,
Type type,
List<Option> options,
String title,
boolean singleSelect,
boolean required,
boolean inOnboarding
) implements Compilerable {
public static class Prompt implements Compilerable {
private String id;
private Type type;
private List<Option> options;
private String title;
private boolean singleSelect;
private boolean required;
private boolean inOnboarding;

private Prompt(String id, Type type, List<Option> options, String title, boolean singleSelect, boolean required, boolean inOnboarding) {
this.id = id;
this.type = type;
this.options = options;
this.title = title;
this.singleSelect = singleSelect;
this.required = required;
this.inOnboarding = inOnboarding;
}

public Prompt(String id, Type type, List<Option> options, String title) {
this(id, type, options, title, false, false, false);
}

public Prompt(String id, Type type, List<Option> options, String title, boolean inOnboarding) {
this(id, type, options, title, false, false, inOnboarding);
}

public void setInOnboarding(boolean inOnboarding) {
this.inOnboarding = inOnboarding;
}

public void setType(Type type) {
this.type = type;
}

public void setTitle(String title) {
this.title = title;
}

public void setSingleSelect(boolean singleSelect) {
this.singleSelect = singleSelect;
}

public void setOptions(List<Option> options) {
this.options = options;
}

public void setRequired(boolean required) {
this.required = required;
}

@NotNull
@Override
public JSONObject compile() {
JSONObject obj = new JSONObject();
obj.put("id", id);
obj.put("type", type.getCode());
obj.put("options", options.stream().map(Option::compile).collect(Collectors.toList()));
JSONArray options = new JSONArray();
if (this.options != null) {
for (Option option : this.options) {
options.put(option.compile());
}
}
obj.put("options", options);
obj.put("title", title);
obj.put("single_select", singleSelect);
obj.put("required", required);
Expand All @@ -1736,7 +1805,7 @@ public static Prompt decompile(@NotNull JSONObject obj, @NotNull DiscordJar djar
return new Prompt(
obj.getString("id"),
Type.fromCode(obj.getInt("type")),
obj.getJSONArray("options").toList().stream().map(o -> Option.decompile((JSONObject) o, djar)).collect(Collectors.toList()),
obj.getJSONArray("options").toList().stream().map(o -> Option.decompile(new JSONObject((HashMap<String, Object>) o), djar)).collect(Collectors.toList()),
obj.getString("title"),
obj.getBoolean("single_select"),
obj.getBoolean("required"),
Expand Down Expand Up @@ -1771,22 +1840,53 @@ public static Type fromCode(int code) {

/**
* Represents an option available within a prompt.
*
* @param id ID of the option
* @param channelIds IDs for channels a member is added to when the option is selected
* @param roleIds IDs for roles assigned to a member when the option is selected
* @param emoji Emoji for the option
* @param title Title of the option
* @param description Description of the option. This may be null or an empty string.
*/
public record Option(
String id,
List<String> channelIds,
List<String> roleIds,
Emoji emoji,
String title,
String description
) implements Compilerable {
public static class Option implements Compilerable {
private String id;
private List<String> channelIds;
private List<String> roleIds;
private Emoji emoji;
private String title;
private String description;

protected Option(String id, List<String> channelIds, List<String> roleIds, Emoji emoji, String title, String description) {
this.id = id;
this.channelIds = channelIds;
this.roleIds = roleIds;
this.emoji = emoji;
this.title = title;
this.description = description;
}

public Option(List<String> channelIds, List<String> roleIds, Emoji emoji, String title, String description) {
this(null, channelIds, roleIds, emoji, title, description);
}

public Option(List<String> channelIds, List<String> roleIds, Emoji emoji, String title) {
this(null, channelIds, roleIds, emoji, title, null);
}


public void setChannelIds(List<String> channelIds) {
this.channelIds = channelIds;
}

public void setDescription(String description) {
this.description = description;
}

public void setEmoji(Emoji emoji) {
this.emoji = emoji;
}

public void setRoleIds(List<String> roleIds) {
this.roleIds = roleIds;
}

public void setTitle(String title) {
this.title = title;
}

@NotNull
@Override
public JSONObject compile() {
Expand All @@ -1804,7 +1904,7 @@ public JSONObject compile() {
@Contract("_, _ -> new")
public static Option decompile(@NotNull JSONObject obj, DiscordJar discordJar) {
return new Option(
obj.getString("id"),
obj.has("id") ? obj.getString("id") : null,
obj.getJSONArray("channel_ids").toList().stream().map(o -> (String) o).collect(Collectors.toList()),
obj.getJSONArray("role_ids").toList().stream().map(o -> (String) o).collect(Collectors.toList()),
Emoji.decompile(obj.getJSONObject("emoji"), discordJar),
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/seailz/discordjar/utils/URLS.java
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,8 @@ public static class GUILD {
*/
public static final String BAN_USER = "/guilds/{guild.id}/bans/{user.id}";

public static final String MODIFY_GUILD_ONBOARDING = "/guilds/{guild.id}/onboarding";

public static class MEMBERS {
public static class ROLES {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ public DiscordResponse invokeWithFiles(File... files) {

public static class DiscordAPIErrorException extends RuntimeException {
public DiscordAPIErrorException(UnhandledDiscordAPIErrorException e) {
super("Discord API Error: " + e.getError() + " (" + e.getCode() + ") " + e.getBody());
super(ErrorTreeReader.readErrorTree(e.getBody(), e.code));
}
}

Expand Down
Loading