diff --git a/config.example.yml b/config.example.yml index 7df8e9b9a..b2107c828 100644 --- a/config.example.yml +++ b/config.example.yml @@ -111,4 +111,8 @@ haste: web: # The secret to use when authenticating with the site/wrapper - secret_key: \ No newline at end of file + secret_key: + +patreon: + url: '' + key: '' \ No newline at end of file diff --git a/src/main/java/org/cascadebot/cascadebot/CascadeBot.java b/src/main/java/org/cascadebot/cascadebot/CascadeBot.java index 6058e7eb8..2f9e9a1c2 100644 --- a/src/main/java/org/cascadebot/cascadebot/CascadeBot.java +++ b/src/main/java/org/cascadebot/cascadebot/CascadeBot.java @@ -29,12 +29,15 @@ import org.cascadebot.cascadebot.commandmeta.CommandManager; import org.cascadebot.cascadebot.data.Config; import org.cascadebot.cascadebot.data.database.DatabaseManager; +import org.cascadebot.cascadebot.data.managers.CascadeUserDataManager; import org.cascadebot.cascadebot.data.managers.GuildDataManager; +import org.cascadebot.cascadebot.data.objects.donation.Tier; import org.cascadebot.cascadebot.data.managers.ScheduledActionManager; import org.cascadebot.cascadebot.events.ButtonEventListener; import org.cascadebot.cascadebot.events.CommandListener; import org.cascadebot.cascadebot.events.GeneralEventListener; import org.cascadebot.cascadebot.events.JDAEventMetricsListener; +import org.cascadebot.cascadebot.events.UserPatreonListener; import org.cascadebot.cascadebot.events.VoiceEventListener; import org.cascadebot.cascadebot.metrics.Metrics; import org.cascadebot.cascadebot.moderation.ModerationManager; @@ -182,6 +185,7 @@ private void init() { .addEventListeners(new ButtonEventListener()) .addEventListeners(new VoiceEventListener()) .addEventListeners(new JDAEventMetricsListener()) + .addEventListeners(new UserPatreonListener()) .addEventListeners(eventWaiter) .setToken(Config.INS.getBotToken()) .setShardsTotal(-1) @@ -202,6 +206,8 @@ private void init() { defaultShardManagerBuilder.setAudioSendFactory(new NativeAudioSendFactory()); } + Tier.Companion.parseTiers(); + shardManager = defaultShardManagerBuilder.build(); } catch (LoginException e) { LOGGER.error("Error building JDA", e); @@ -218,6 +224,7 @@ private void init() { ScheduledActionManager.loadAndRegister(); Metrics.INS.cacheMetrics.addCache("guilds", GuildDataManager.getGuilds()); + Metrics.INS.cacheMetrics.addCache("users", CascadeUserDataManager.getUsers()); Thread.setDefaultUncaughtExceptionHandler(((t, e) -> LOGGER.error("Uncaught exception in thread " + t, MDCException.from(e)))); Thread.currentThread() diff --git a/src/main/java/org/cascadebot/cascadebot/commandmeta/CommandManager.java b/src/main/java/org/cascadebot/cascadebot/commandmeta/CommandManager.java index 09f1431d7..68adb2a9d 100644 --- a/src/main/java/org/cascadebot/cascadebot/commandmeta/CommandManager.java +++ b/src/main/java/org/cascadebot/cascadebot/commandmeta/CommandManager.java @@ -8,7 +8,7 @@ import lombok.Getter; import org.apache.commons.lang3.reflect.ConstructorUtils; import org.cascadebot.cascadebot.ShutdownHandler; -import org.cascadebot.cascadebot.data.objects.GuildData; +import org.cascadebot.cascadebot.data.objects.guild.GuildData; import org.cascadebot.cascadebot.utils.ReflectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/cascadebot/cascadebot/commandmeta/ICommandExecutable.java b/src/main/java/org/cascadebot/cascadebot/commandmeta/ICommandExecutable.java index e8f1d8e35..007a1534f 100644 --- a/src/main/java/org/cascadebot/cascadebot/commandmeta/ICommandExecutable.java +++ b/src/main/java/org/cascadebot/cascadebot/commandmeta/ICommandExecutable.java @@ -8,7 +8,6 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.data.language.Language; import org.cascadebot.cascadebot.data.language.Locale; -import org.cascadebot.cascadebot.data.objects.Flag; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.utils.pagination.Page; @@ -64,8 +63,8 @@ default boolean deleteMessages() { return true; } - default Set getFlags() { - return Set.of(); + default String getRequiredFlag() { + return null; } default List additionalUsagePages() { diff --git a/src/main/java/org/cascadebot/cascadebot/commands/core/DonateCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/core/DonateCommand.java new file mode 100644 index 000000000..b0c4bca46 --- /dev/null +++ b/src/main/java/org/cascadebot/cascadebot/commands/core/DonateCommand.java @@ -0,0 +1,49 @@ +package org.cascadebot.cascadebot.commands.core; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Member; +import org.apache.commons.lang3.StringUtils; +import org.cascadebot.cascadebot.commandmeta.CommandContext; +import org.cascadebot.cascadebot.commandmeta.ICommandCore; +import org.cascadebot.cascadebot.data.objects.donation.Tier; +import org.cascadebot.cascadebot.messaging.MessagingObjects; +import org.cascadebot.cascadebot.utils.pagination.Page; +import org.cascadebot.cascadebot.utils.pagination.PageObjects; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class DonateCommand implements ICommandCore { + + @Override + public void onCommand(Member sender, CommandContext context) { + EmbedBuilder builder = MessagingObjects.getClearThreadLocalEmbedBuilder(); + List pages = new ArrayList<>(); + + builder.setTitle(context.i18n("commands.donate.embed_title")); + builder.setDescription(context.i18n("commands.donate.embed_description")); + builder.setFooter(context.i18n("commands.donate.embed_footer"), context.getSelfUser().getAvatarUrl()); + builder.addField("Patreon", context.i18n("commands.donate.embed_patreon"), true); + + pages.add(new PageObjects.EmbedPage(builder)); + for (Map.Entry tier : Tier.Companion.getTiers().entrySet()) { + if (tier.getKey().equals("default") || tier.getKey().equals("nitro")) { + continue; + } + String title = tier.getKey(); + pages.add(new PageObjects.EmbedPage(new EmbedBuilder() + .setDescription((tier.getValue().getGuildTierString(context.getLocale(), null))) + .setTitle(StringUtils.capitalize(title)) + )); + } + + context.getUiMessaging().sendPagedMessage(pages); + } + + @Override + public String command() { + return "donate"; + } + +} \ No newline at end of file diff --git a/src/main/java/org/cascadebot/cascadebot/commands/core/PrefixCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/core/PrefixCommand.java index f9dd527b9..024757e81 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/core/PrefixCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/core/PrefixCommand.java @@ -9,6 +9,7 @@ import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ICommandCore; import org.cascadebot.cascadebot.data.Config; +import org.cascadebot.cascadebot.data.objects.donation.AmountFlag; public class PrefixCommand implements ICommandCore { @@ -32,7 +33,12 @@ public void onCommand(Member sender, CommandContext context) { return; } - if (newPrefix.length() > 5) { + AmountFlag prefixFlag = (AmountFlag) context.getData().getAllFlags().getFlag("prefix_length"); + if (prefixFlag == null) { + context.getTypedMessaging().replyDanger(context.i18n("commands.prefix.prefix_too_long")); + return; + } + if (newPrefix.length() > prefixFlag.getAmount()) { context.getTypedMessaging().replyDanger(context.i18n("commands.prefix.prefix_too_long")); return; } diff --git a/src/main/java/org/cascadebot/cascadebot/commands/developer/EvalCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/developer/EvalCommand.java index 19e6847b1..35b058b5f 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/developer/EvalCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/developer/EvalCommand.java @@ -86,6 +86,7 @@ public void onCommand(Member sender, CommandContext context) { scriptEngine.put("context", context); scriptEngine.put("channel", context.getChannel()); scriptEngine.put("guild", context.getGuild()); + scriptEngine.put("data", context.getData()); String imports = IMPORTS.stream().map(s -> "import " + s + ".*;").collect(Collectors.joining(" ")); diff --git a/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildCommand.java index 2a2d2639a..c9f798167 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildCommand.java @@ -38,7 +38,7 @@ public SecurityLevel getCommandLevel() { @Override public Set getSubCommands() { - return Set.of(new GuildSaveSubCommand(), new GuildLeaveSubCommand(), new GuildFlagSubCommand(), new GuildInfoSubCommand()); + return Set.of(new GuildSaveSubCommand(), new GuildLeaveSubCommand(), new GuildInfoSubCommand()); } @Override diff --git a/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildFlagSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildFlagSubCommand.java deleted file mode 100644 index 76b72ef98..000000000 --- a/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildFlagSubCommand.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2019 CascadeBot. All rights reserved. - * Licensed under the MIT license. - */ - -package org.cascadebot.cascadebot.commands.developer; - -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import org.apache.commons.lang3.EnumUtils; -import org.cascadebot.cascadebot.CascadeBot; -import org.cascadebot.cascadebot.commandmeta.CommandContext; -import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.managers.GuildDataManager; -import org.cascadebot.cascadebot.data.objects.Flag; -import org.cascadebot.cascadebot.data.objects.GuildData; -import org.cascadebot.cascadebot.messaging.MessagingObjects; -import org.cascadebot.cascadebot.permissions.CascadePermission; -import org.cascadebot.cascadebot.utils.FormatUtils; -import org.cascadebot.shared.Regex; - -import java.util.Arrays; -import java.util.stream.Collectors; - -public class GuildFlagSubCommand implements ISubCommand { - - @Override - public void onCommand(Member sender, CommandContext context) { - if (context.getArgs().length > 0) { - Flag flag; - if (EnumUtils.isValidEnumIgnoreCase(Flag.class, context.getArg(0))) { - flag = EnumUtils.getEnum(Flag.class, context.getArg(0).toUpperCase()); - } else { - if (context.getArg(0).equalsIgnoreCase("list")) { - EmbedBuilder embedBuilder = MessagingObjects.getClearThreadLocalEmbedBuilder(); - embedBuilder.setTitle("Flags"); - embedBuilder.setDescription(Arrays.stream(Flag.values()) - .map(e -> String.format("- `%s`", FormatUtils.formatEnum(e, context.getLocale()))) - .collect(Collectors.joining("\n"))); - context.getTypedMessaging().replyInfo(embedBuilder); - return; - } - context.getTypedMessaging().replyDanger("Invalid flag! Possible values: %s", Arrays.toString(Flag.values())); - return; - } - - Guild guild = context.getGuild(); - if (context.getArgs().length == 2) { - if (Regex.ID.matcher(context.getArg(1)).matches()) { - guild = CascadeBot.INS.getShardManager().getGuildById(context.getArg(1)); - if (guild == null) { - context.getTypedMessaging().replyDanger("Cannot find that guild!"); - return; - } - } else { - context.getTypedMessaging().replyDanger("Invalid guild ID!"); - return; - } - } - - GuildData guildData = GuildDataManager.getGuildData(guild.getIdLong()); - - if (guildData.isFlagEnabled(flag)) { - guildData.disableFlag(flag); - context.getTypedMessaging().replySuccess("Disabled flag `%s` for guild `%s (%s)`", FormatUtils.formatEnum(flag, guildData.getLocale()), guild.getName(), guild.getId()); - } else { - guildData.enableFlag(flag); - context.getTypedMessaging().replySuccess("Enabled flag `%s` for guild `%s (%s)`", FormatUtils.formatEnum(flag, guildData.getLocale()), guild.getName(), guild.getId()); - } - - } - } - - @Override - public String command() { - return "flag"; - } - - @Override - public String parent() { - return "guild"; - } - - @Override - public String description() { - return "Toggles a flag for this guild [or a different guild]."; - } - - @Override - public CascadePermission getPermission() { - return null; - } - -} diff --git a/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildInfoSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildInfoSubCommand.java index 4970d14e5..1c4aa26f2 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildInfoSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildInfoSubCommand.java @@ -14,8 +14,7 @@ import org.cascadebot.cascadebot.commandmeta.ISubCommand; import org.cascadebot.cascadebot.commandmeta.Module; import org.cascadebot.cascadebot.data.managers.GuildDataManager; -import org.cascadebot.cascadebot.data.objects.Flag; -import org.cascadebot.cascadebot.data.objects.GuildData; +import org.cascadebot.cascadebot.data.objects.guild.GuildData; import org.cascadebot.cascadebot.messaging.MessagingObjects; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.utils.FormatUtils; @@ -45,10 +44,12 @@ public void onCommand(Member sender, CommandContext context) { GuildData finalDataForList = dataForList; + /* String flags = Arrays.stream(Flag.values()) .map(flag -> FormatUtils.formatEnum(flag) + " - " + (finalDataForList.isFlagEnabled(flag) ? UnicodeConstants.TICK : UnicodeConstants.RED_CROSS)) .collect(Collectors.joining("\n")); + */ String modules = Arrays.stream(Module.values()) .map(module -> FormatUtils.formatEnum(module) + " - " + @@ -56,7 +57,7 @@ public void onCommand(Member sender, CommandContext context) { .collect(Collectors.joining("\n")); - builder.addField("Flags", flags, false); + //builder.addField("Flags", flags, false); builder.addField("Modules", modules, false); builder.addField("Join Date", FormatUtils.formatDateTime(context.getSelfMember().getTimeJoined()), false); diff --git a/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildSaveSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildSaveSubCommand.java index 55a88def6..ba9d8e1d8 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildSaveSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/developer/GuildSaveSubCommand.java @@ -9,7 +9,7 @@ import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; import org.cascadebot.cascadebot.data.managers.GuildDataManager; -import org.cascadebot.cascadebot.data.objects.GuildData; +import org.cascadebot.cascadebot.data.objects.guild.GuildData; import org.cascadebot.cascadebot.permissions.CascadePermission; public class GuildSaveSubCommand implements ISubCommand { diff --git a/src/main/java/org/cascadebot/cascadebot/commands/management/FlagsCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/management/FlagsCommand.java deleted file mode 100644 index da7445fde..000000000 --- a/src/main/java/org/cascadebot/cascadebot/commands/management/FlagsCommand.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.cascadebot.cascadebot.commands.management; - -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import org.apache.commons.lang3.StringUtils; -import org.cascadebot.cascadebot.UnicodeConstants; -import org.cascadebot.cascadebot.commandmeta.CommandContext; -import org.cascadebot.cascadebot.commandmeta.ICommandMain; -import org.cascadebot.cascadebot.commandmeta.Module; -import org.cascadebot.cascadebot.data.objects.Flag; -import org.cascadebot.cascadebot.data.objects.GuildData; -import org.cascadebot.cascadebot.messaging.MessagingObjects; -import org.cascadebot.cascadebot.permissions.CascadePermission; -import org.cascadebot.cascadebot.utils.FormatUtils; - -import java.util.Arrays; -import java.util.stream.Collectors; - -public class FlagsCommand implements ICommandMain { - - @Override - public void onCommand(Member sender, CommandContext context) { - GuildData dataForList = context.getData(); - Guild guildForList = context.getGuild(); - - String flags = Arrays.stream(Flag.values()) - .map(flag -> StringUtils.capitalize(FormatUtils.formatEnum(flag, context.getLocale())) + " - " + - (dataForList.isFlagEnabled(flag) ? UnicodeConstants.TICK : UnicodeConstants.RED_CROSS)) - .collect(Collectors.joining("\n")); - - EmbedBuilder builder = MessagingObjects.getClearThreadLocalEmbedBuilder(); - builder.setTitle(guildForList.getName()); - builder.setThumbnail(guildForList.getIconUrl()); - - builder.addField(context.i18n("words.flags"), flags, false); - - context.getTypedMessaging().replyInfo(builder); - } - - @Override - public Module getModule() { - return Module.MANAGEMENT; - } - - @Override - public String command() { - return "flags"; - } - - @Override - public CascadePermission getPermission() { - return CascadePermission.of("flags", false); - } - -} diff --git a/src/main/java/org/cascadebot/cascadebot/commands/management/SettingsCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/management/SettingsCommand.java index a33f9f1a5..136be4a47 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/management/SettingsCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/management/SettingsCommand.java @@ -48,10 +48,12 @@ public void onCommand(Member sender, CommandContext context) { try { Setting settingAnnotation = field.getAnnotation(Setting.class); if (settingAnnotation != null) { - if (!context.getData().getEnabledFlags().containsAll(Arrays.asList(settingAnnotation.flagRequired()))) { - String niceName = Language.i18n(context.getGuild().getIdLong(), "settings." + field.getDeclaringClass().getAnnotation(SettingsContainer.class).module().name().toLowerCase() + "." + field.getName() + ".nice_name"); - context.getTypedMessaging().replyDanger(context.i18n("commands.settings.cannot_edit", niceName)); - return; + for (String flag : settingAnnotation.flagsRequired()) { + if (!context.getData().getAllFlags().hasFlag(flag)) { + String niceName = Language.i18n(context.getGuild().getIdLong(), "settings." + field.getDeclaringClass().getAnnotation(SettingsContainer.class).module().name().toLowerCase() + "." + field.getName() + ".nice_name"); + context.getTypedMessaging().replyDanger(context.i18n("commands.settings.cannot_edit", niceName)); + return; + } } } diff --git a/src/main/java/org/cascadebot/cascadebot/commands/management/TagCategorySubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/management/TagCategorySubCommand.java index 4f8ffaa36..b77708070 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/management/TagCategorySubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/management/TagCategorySubCommand.java @@ -8,7 +8,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.Tag; +import org.cascadebot.cascadebot.data.objects.guild.Tag; import org.cascadebot.cascadebot.permissions.CascadePermission; public class TagCategorySubCommand implements ISubCommand { diff --git a/src/main/java/org/cascadebot/cascadebot/commands/management/TagCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/management/TagCommand.java index 7311ed2db..424af3bf2 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/management/TagCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/management/TagCommand.java @@ -10,7 +10,7 @@ import org.cascadebot.cascadebot.commandmeta.ICommandMain; import org.cascadebot.cascadebot.commandmeta.ISubCommand; import org.cascadebot.cascadebot.commandmeta.Module; -import org.cascadebot.cascadebot.data.objects.Tag; +import org.cascadebot.cascadebot.data.objects.guild.Tag; import org.cascadebot.cascadebot.permissions.CascadePermission; import java.util.Set; diff --git a/src/main/java/org/cascadebot/cascadebot/commands/management/TagCreateSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/management/TagCreateSubCommand.java index 56e322a1e..8f2eca9ea 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/management/TagCreateSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/management/TagCreateSubCommand.java @@ -8,7 +8,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.Tag; +import org.cascadebot.cascadebot.data.objects.guild.Tag; import org.cascadebot.cascadebot.permissions.CascadePermission; public class TagCreateSubCommand implements ISubCommand { diff --git a/src/main/java/org/cascadebot/cascadebot/commands/management/TagEditSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/management/TagEditSubCommand.java index 95d014d54..d0faa633b 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/management/TagEditSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/management/TagEditSubCommand.java @@ -8,7 +8,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.Tag; +import org.cascadebot.cascadebot.data.objects.guild.Tag; import org.cascadebot.cascadebot.permissions.CascadePermission; public class TagEditSubCommand implements ISubCommand { diff --git a/src/main/java/org/cascadebot/cascadebot/commands/management/TagListSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/management/TagListSubCommand.java index e9623e72d..63cf64260 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/management/TagListSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/management/TagListSubCommand.java @@ -8,7 +8,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.Tag; +import org.cascadebot.cascadebot.data.objects.guild.Tag; import org.cascadebot.cascadebot.permissions.CascadePermission; import java.util.Map; diff --git a/src/main/java/org/cascadebot/cascadebot/commands/management/TagRawSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/management/TagRawSubCommand.java index 1c4fd77cd..c19653bbd 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/management/TagRawSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/management/TagRawSubCommand.java @@ -9,7 +9,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.Tag; +import org.cascadebot.cascadebot.data.objects.guild.Tag; import org.cascadebot.cascadebot.messaging.MessagingObjects; import org.cascadebot.cascadebot.permissions.CascadePermission; diff --git a/src/main/java/org/cascadebot/cascadebot/commands/management/permission/GroupPermissionListSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/management/permission/GroupPermissionListSubCommand.java index cc95bfee8..e5e5ecc76 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/management/permission/GroupPermissionListSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/management/permission/GroupPermissionListSubCommand.java @@ -10,7 +10,6 @@ import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; import org.cascadebot.cascadebot.commandmeta.Module; -import org.cascadebot.cascadebot.data.objects.GuildPermissions; import org.cascadebot.cascadebot.data.objects.PermissionMode; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.permissions.objects.Group; diff --git a/src/main/java/org/cascadebot/cascadebot/commands/management/permission/GroupPermissionMoveSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/management/permission/GroupPermissionMoveSubCommand.java index dcc0e284a..9af398fb5 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/management/permission/GroupPermissionMoveSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/management/permission/GroupPermissionMoveSubCommand.java @@ -10,7 +10,6 @@ import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; import org.cascadebot.cascadebot.commandmeta.Module; -import org.cascadebot.cascadebot.data.objects.GuildPermissions; import org.cascadebot.cascadebot.data.objects.PermissionMode; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.permissions.objects.Group; diff --git a/src/main/java/org/cascadebot/cascadebot/commands/music/EqualizerCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/music/EqualizerCommand.java index 18b663d6a..c03c78c87 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/music/EqualizerCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/music/EqualizerCommand.java @@ -228,4 +228,10 @@ public CascadePermission getPermission() { public Set getSubCommands() { return Set.of(new EqualizerResetSubCommand()); } + + @Override + public String getRequiredFlag() { + return "music_controls"; + } + } diff --git a/src/main/java/org/cascadebot/cascadebot/commands/music/EqualizerResetSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/music/EqualizerResetSubCommand.java index a4b35d66e..49c3e1679 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/music/EqualizerResetSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/music/EqualizerResetSubCommand.java @@ -54,4 +54,9 @@ public CascadePermission getPermission() { return CascadePermission.of("equalizer.reset", true); } + @Override + public String getRequiredFlag() { + return "music_controls"; + } + } diff --git a/src/main/java/org/cascadebot/cascadebot/commands/music/PlayCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/music/PlayCommand.java index 1ca0af0ef..14bcc9cc6 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/music/PlayCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/music/PlayCommand.java @@ -26,7 +26,7 @@ public void onCommand(Member sender, CommandContext context) { context.getTypedMessaging().replyException(context.i18n("commands.play.encountered_error"), exception); }, tracks -> { context.getUiMessaging().checkPlaylistOrSong(context.getArg(0), tracks, context, false); - }); + }, context.getData().getAllFlags().hasFlag("music_services")); } else { CascadeBot.INS.getMusicHandler().searchTracks(context.getMessage(0), context.getChannel(), searchResults -> { if (searchResults.isEmpty()) { @@ -38,7 +38,7 @@ public void onCommand(Member sender, CommandContext context) { }, tracks -> { context.getMusicPlayer().addTracks(tracks); context.getUiMessaging().sendTracksFound(tracks); - }); + }, context.getData().getAllFlags().hasFlag("music_services")); } }); } diff --git a/src/main/java/org/cascadebot/cascadebot/commands/music/PlayTopCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/music/PlayTopCommand.java index 9d4d7e4ab..c38ac080d 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/music/PlayTopCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/music/PlayTopCommand.java @@ -31,7 +31,7 @@ public void onCommand(Member sender, CommandContext context) { context.getTypedMessaging().replyException(context.i18n("commands.play.encountered_error"), exception); }, tracks -> { context.getUiMessaging().checkPlaylistOrSong(context.getArg(0), tracks, context, true); - }); + }, context.getData().getAllFlags().hasFlag("music_services")); } else { CascadeBot.INS.getMusicHandler().searchTracks(context.getMessage(0), context.getChannel(), searchResults -> { if (searchResults.isEmpty()) { @@ -47,7 +47,7 @@ public void onCommand(Member sender, CommandContext context) { context.getMusicPlayer().setQueue(new LinkedList<>(currentQueue)); context.getMusicPlayer().playTrack(topTrack); context.getUiMessaging().sendTracksFound(tracks); - }); + }, context.getData().getAllFlags().hasFlag("music_services")); } }); } diff --git a/src/main/java/org/cascadebot/cascadebot/commands/music/PlayingCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/music/PlayingCommand.java index f84312bea..5f459b290 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/music/PlayingCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/music/PlayingCommand.java @@ -15,7 +15,6 @@ import org.cascadebot.cascadebot.data.Config; import org.cascadebot.cascadebot.data.language.Language; import org.cascadebot.cascadebot.data.managers.GuildDataManager; -import org.cascadebot.cascadebot.data.objects.Flag; import org.cascadebot.cascadebot.data.objects.LoopMode; import org.cascadebot.cascadebot.messaging.MessagingObjects; import org.cascadebot.cascadebot.music.CascadePlayer; @@ -71,8 +70,8 @@ public void onCommand(Member sender, CommandContext context) { context.getTypedMessaging().replyWarning(context.i18n("commands.playing.no_music_playing")); return; } - ButtonGroup buttonGroup = new ButtonGroup(sender.getIdLong(), context.getChannel().getIdLong(), context.getGuild().getIdLong()); - if (context.getData().isFlagEnabled(Flag.MUSIC_SERVICES)) { + ButtonGroup buttonGroup = new ButtonGroup(sender.getUser().getIdLong(), context.getChannel().getIdLong(), context.getGuild().getIdLong()); + if (context.getData().getAllFlags().hasFlag("music_controls")) { buttonGroup.addButton(new Button.UnicodeButton(UnicodeConstants.VOLUME_DOWN, (runner, channel, message) -> { if (context.hasPermission(runner, "volume")) { int volume = context.getMusicPlayer().getVolume(); diff --git a/src/main/java/org/cascadebot/cascadebot/commands/music/QueueLoadSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/music/QueueLoadSubCommand.java index 6ff71b2eb..1f050a6a4 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/music/QueueLoadSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/music/QueueLoadSubCommand.java @@ -41,7 +41,7 @@ public void onCommand(Member sender, CommandContext context) { message.delete().queue(null, DiscordUtils.handleExpectedErrors(ErrorResponse.UNKNOWN_MESSAGE)); context.getMusicPlayer().loadPlaylist(context.getArg(0), new TrackData(sender.getIdLong(), context.getChannel().getIdLong(), context.getGuild().getIdLong()), ((loadPlaylistResult, newTracks) -> { context.getUiMessaging().sendTracksFound(newTracks); - })); + }), context.getData().getAllFlags().hasFlag("music_services")); }))); buttonGroup.addButton(new Button.UnicodeButton(UnicodeConstants.TWO, ((runner, channel, message) -> { if (!runner.equals(buttonGroup.getOwner())) { @@ -50,7 +50,7 @@ public void onCommand(Member sender, CommandContext context) { message.delete().queue(null, DiscordUtils.handleExpectedErrors(ErrorResponse.UNKNOWN_MESSAGE)); context.getMusicPlayer().loadPlaylist(context.getArg(0), new TrackData(sender.getIdLong(), context.getChannel().getIdLong(), context.getGuild().getIdLong()), PlaylistType.GUILD, ((loadPlaylistResult, newTracks) -> { context.getUiMessaging().sendTracksFound(newTracks); - })); + }), context.getData().getAllFlags().hasFlag("music_services")); }))); context.getUiMessaging().sendButtonedMessage(context.i18n("commands.queue.load.load_track"), buttonGroup); break; @@ -58,7 +58,7 @@ public void onCommand(Member sender, CommandContext context) { context.getTypedMessaging().replyDanger(context.i18n("commands.queue.load.cannot_find_playlist", context.getArg(0))); break; } - }); + }, context.getData().getAllFlags().hasFlag("music_services")); } @Override diff --git a/src/main/java/org/cascadebot/cascadebot/commands/music/SearchCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/music/SearchCommand.java index 6d006ed63..15fc91b22 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/music/SearchCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/music/SearchCommand.java @@ -61,7 +61,7 @@ public void onCommand(Member sender, CommandContext context) { }, audioTracks -> { context.getMusicPlayer().addTracks(audioTracks); context.getUiMessaging().sendTracksFound(audioTracks); - }); + }, context.getData().getAllFlags().hasFlag("music_services")); })); messageBuilder.append(unicode).append("\u20E3").append(" - ").append(StringsUtil.truncate(result.getTitle(), 60)).append(" - "); switch (result.getType()) { @@ -100,7 +100,7 @@ public void onCommand(Member sender, CommandContext context) { }, audioTracks -> { context.getMusicPlayer().addTracks(audioTracks); context.getUiMessaging().sendTracksFound(audioTracks); - }); + }, context.getData().getAllFlags().hasFlag("music_services")); }, String.valueOf(index + 1)); } CascadeBot.INS.getEventWaiter().waitForResponse(context.getUser(), context.getChannel(), 30, TimeUnit.SECONDS, () -> { diff --git a/src/main/java/org/cascadebot/cascadebot/commands/music/VolumeCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/music/VolumeCommand.java index 5e3005d4d..735a95089 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/music/VolumeCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/music/VolumeCommand.java @@ -4,13 +4,11 @@ import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ICommandMain; import org.cascadebot.cascadebot.commandmeta.Module; -import org.cascadebot.cascadebot.data.objects.Flag; import org.cascadebot.cascadebot.messaging.MessageType; import org.cascadebot.cascadebot.music.CascadePlayer; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.utils.ConfirmUtils; -import java.util.Set; import java.util.concurrent.TimeUnit; public class VolumeCommand implements ICommandMain { @@ -92,8 +90,7 @@ public CascadePermission getPermission() { } @Override - public Set getFlags() { - return Set.of(Flag.MUSIC_SERVICES); + public String getRequiredFlag() { + return "music_controls"; } - } diff --git a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoAddSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoAddSubCommand.java index 805217129..91c0da28c 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoAddSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoAddSubCommand.java @@ -4,7 +4,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.TodoList; +import org.cascadebot.cascadebot.data.objects.guild.TodoList; import org.cascadebot.cascadebot.messaging.MessagingObjects; import org.cascadebot.cascadebot.permissions.CascadePermission; diff --git a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoAddUserSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoAddUserSubCommand.java index 7cad18551..9dab7b1b0 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoAddUserSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoAddUserSubCommand.java @@ -3,7 +3,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.TodoList; +import org.cascadebot.cascadebot.data.objects.guild.TodoList; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.utils.DiscordUtils; diff --git a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoCreateSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoCreateSubCommand.java index 9ea3045ef..87e07ed60 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoCreateSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoCreateSubCommand.java @@ -3,7 +3,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.TodoList; +import org.cascadebot.cascadebot.data.objects.guild.TodoList; import org.cascadebot.cascadebot.permissions.CascadePermission; public class TodoCreateSubCommand implements ISubCommand { diff --git a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoRemoveSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoRemoveSubCommand.java index c3f208230..fc5e49031 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoRemoveSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoRemoveSubCommand.java @@ -4,7 +4,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.TodoList; +import org.cascadebot.cascadebot.data.objects.guild.TodoList; import org.cascadebot.cascadebot.messaging.MessagingObjects; import org.cascadebot.cascadebot.permissions.CascadePermission; diff --git a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoRemoveUserSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoRemoveUserSubCommand.java index bf39ddf1d..32920d6ca 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoRemoveUserSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoRemoveUserSubCommand.java @@ -3,7 +3,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.TodoList; +import org.cascadebot.cascadebot.data.objects.guild.TodoList; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.utils.DiscordUtils; diff --git a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoSendSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoSendSubCommand.java index 787e03db4..704dfeab7 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoSendSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoSendSubCommand.java @@ -4,7 +4,7 @@ import net.dv8tion.jda.api.entities.TextChannel; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.TodoList; +import org.cascadebot.cascadebot.data.objects.guild.TodoList; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.utils.DiscordUtils; diff --git a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoViewSubCommand.java b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoViewSubCommand.java index 0b1bea025..b296eabfb 100644 --- a/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoViewSubCommand.java +++ b/src/main/java/org/cascadebot/cascadebot/commands/useful/TodoViewSubCommand.java @@ -4,7 +4,7 @@ import net.dv8tion.jda.api.entities.Member; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.ISubCommand; -import org.cascadebot.cascadebot.data.objects.TodoList; +import org.cascadebot.cascadebot.data.objects.guild.TodoList; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.utils.pagination.Page; import org.cascadebot.cascadebot.utils.pagination.PageObjects; diff --git a/src/main/java/org/cascadebot/cascadebot/data/Config.java b/src/main/java/org/cascadebot/cascadebot/data/Config.java index 4742462a6..ad0afed76 100644 --- a/src/main/java/org/cascadebot/cascadebot/data/Config.java +++ b/src/main/java/org/cascadebot/cascadebot/data/Config.java @@ -83,6 +83,9 @@ public class Config { private List musicNodes = new ArrayList<>(); + public String patreonServiceUrl; + public String patreonServiceKey; + private Config(String file) throws IOException { config = new File(file); initConfig(); @@ -241,6 +244,9 @@ private void initConfig() throws IOException { youtubeKey = config.getString("music_keys.youtube"); + patreonServiceUrl = warnOnDefault(config, "patreon.url", null); + patreonServiceKey = config.getString("patreon.key"); + LOG.info("Finished loading configuration!"); } diff --git a/src/main/java/org/cascadebot/cascadebot/data/managers/CascadeUserDataManager.java b/src/main/java/org/cascadebot/cascadebot/data/managers/CascadeUserDataManager.java new file mode 100644 index 000000000..39a52eafe --- /dev/null +++ b/src/main/java/org/cascadebot/cascadebot/data/managers/CascadeUserDataManager.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 CascadeBot. All rights reserved. + * Licensed under the MIT license. + */ + +package org.cascadebot.cascadebot.data.managers; + +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import org.bson.conversions.Bson; +import org.cascadebot.cascadebot.CascadeBot; +import org.cascadebot.cascadebot.data.database.DebugLogCallback; +import org.cascadebot.cascadebot.data.objects.user.CascadeUser; + +import java.util.concurrent.TimeUnit; + +import static com.mongodb.client.model.Filters.eq; + +public class CascadeUserDataManager { + + private static final String COLLECTION = "bot_users"; + + private static LoadingCache users = Caffeine.newBuilder() + .expireAfterAccess(5, TimeUnit.MINUTES) + .recordStats() + .build(id -> { + CascadeUser user = CascadeBot.INS.getDatabaseManager().getDatabase().getCollection(COLLECTION, CascadeUser.class).find(eq("_id", id)).first(); + if (user == null) { + user = new CascadeUser(id); + insert(id, user); + } + + CascadeBot.LOGGER.debug("Loaded data from database for user ID: " + id); + return user; + }); + + public static void update(long id, Bson update) { + CascadeBot.INS.getDatabaseManager().runAsyncTask(database -> { + database.getCollection(COLLECTION, CascadeUser.class).updateOne(eq("_id", id), update, new DebugLogCallback<>("Updated User ID " + id + ":", update)); + }); + } + + public static void insert(long id, CascadeUser data) { + CascadeBot.INS.getDatabaseManager().runAsyncTask(database -> { + database.getCollection(COLLECTION, CascadeUser.class).insertOne(data, new DebugLogCallback<>("Inserted User ID " + id)); + }); + } + + public static void replace(long id, CascadeUser data) { + CascadeBot.INS.getDatabaseManager().runAsyncTask(database -> { + database.getCollection(COLLECTION, CascadeUser.class).replaceOne(eq("_id", id), data, new DebugLogCallback<>("Replaced User ID " + id)); + }); + } + + public static void replaceSync(long id, CascadeUser data) { + CascadeBot.INS.getDatabaseManager().runTask(database -> { + database.getCollection(COLLECTION, CascadeUser.class).replaceOne(eq("_id", id), data); + }); + } + + public static CascadeUser getUser(long id) { + return users.get(id); + } + + public static LoadingCache getUsers() { + return users; + } + +} diff --git a/src/main/java/org/cascadebot/cascadebot/data/managers/GuildDataManager.java b/src/main/java/org/cascadebot/cascadebot/data/managers/GuildDataManager.java index 3283ec775..bf9663d29 100644 --- a/src/main/java/org/cascadebot/cascadebot/data/managers/GuildDataManager.java +++ b/src/main/java/org/cascadebot/cascadebot/data/managers/GuildDataManager.java @@ -10,7 +10,7 @@ import org.bson.conversions.Bson; import org.cascadebot.cascadebot.CascadeBot; import org.cascadebot.cascadebot.data.database.DebugLogCallback; -import org.cascadebot.cascadebot.data.objects.GuildData; +import org.cascadebot.cascadebot.data.objects.guild.GuildData; import org.cascadebot.cascadebot.events.GuildSaveListener; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/org/cascadebot/cascadebot/data/objects/Flag.java b/src/main/java/org/cascadebot/cascadebot/data/objects/Flag.java deleted file mode 100644 index 27c3e2608..000000000 --- a/src/main/java/org/cascadebot/cascadebot/data/objects/Flag.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2019 CascadeBot. All rights reserved. - * Licensed under the MIT license. - */ - -package org.cascadebot.cascadebot.data.objects; - -public enum Flag { - - BETA, - SPOTIFY, - MUSIC_SERVICES - -} diff --git a/src/main/java/org/cascadebot/cascadebot/data/objects/GuildModeration.java b/src/main/java/org/cascadebot/cascadebot/data/objects/GuildModeration.java deleted file mode 100644 index 84cedc1fe..000000000 --- a/src/main/java/org/cascadebot/cascadebot/data/objects/GuildModeration.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2019 CascadeBot. All rights reserved. - * Licensed under the MIT license. - */ - -package org.cascadebot.cascadebot.data.objects; - -public class GuildModeration { - - -} diff --git a/src/main/java/org/cascadebot/cascadebot/data/objects/Setting.java b/src/main/java/org/cascadebot/cascadebot/data/objects/Setting.java index 6912ceb48..848e110a2 100644 --- a/src/main/java/org/cascadebot/cascadebot/data/objects/Setting.java +++ b/src/main/java/org/cascadebot/cascadebot/data/objects/Setting.java @@ -18,6 +18,6 @@ /** * The flag(s) required to have access to change this setting. */ - Flag[] flagRequired() default {}; + String[] flagsRequired() default {}; } diff --git a/src/main/java/org/cascadebot/cascadebot/data/objects/GuildPermissions.java b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/GuildPermissions.java similarity index 98% rename from src/main/java/org/cascadebot/cascadebot/data/objects/GuildPermissions.java rename to src/main/java/org/cascadebot/cascadebot/data/objects/guild/GuildPermissions.java index 09c38d6ab..4ca22aec5 100644 --- a/src/main/java/org/cascadebot/cascadebot/data/objects/GuildPermissions.java +++ b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/GuildPermissions.java @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -package org.cascadebot.cascadebot.data.objects; +package org.cascadebot.cascadebot.data.objects.guild; import lombok.Getter; import lombok.Setter; @@ -13,6 +13,8 @@ import net.dv8tion.jda.internal.utils.Checks; import org.cascadebot.cascadebot.CascadeBot; import org.cascadebot.cascadebot.Environment; +import org.cascadebot.cascadebot.data.objects.PermissionAction; +import org.cascadebot.cascadebot.data.objects.PermissionMode; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.permissions.Security; import org.cascadebot.cascadebot.permissions.objects.Group; diff --git a/src/main/java/org/cascadebot/cascadebot/data/objects/GuildSettingsModeration.java b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsModeration.java similarity index 73% rename from src/main/java/org/cascadebot/cascadebot/data/objects/GuildSettingsModeration.java rename to src/main/java/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsModeration.java index 9bdd94f6d..c659939d4 100644 --- a/src/main/java/org/cascadebot/cascadebot/data/objects/GuildSettingsModeration.java +++ b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsModeration.java @@ -3,13 +3,15 @@ * Licensed under the MIT license. */ -package org.cascadebot.cascadebot.data.objects; +package org.cascadebot.cascadebot.data.objects.guild; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.cascadebot.cascadebot.commandmeta.Module; +import org.cascadebot.cascadebot.data.objects.Setting; +import org.cascadebot.cascadebot.data.objects.SettingsContainer; @SettingsContainer(module = Module.MODERATION) @Getter diff --git a/src/main/java/org/cascadebot/cascadebot/data/objects/GuildSettingsUseful.java b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsUseful.java similarity index 90% rename from src/main/java/org/cascadebot/cascadebot/data/objects/GuildSettingsUseful.java rename to src/main/java/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsUseful.java index 71e36a387..d9fdc51ab 100644 --- a/src/main/java/org/cascadebot/cascadebot/data/objects/GuildSettingsUseful.java +++ b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsUseful.java @@ -1,6 +1,7 @@ -package org.cascadebot.cascadebot.data.objects; +package org.cascadebot.cascadebot.data.objects.guild; import org.cascadebot.cascadebot.commandmeta.Module; +import org.cascadebot.cascadebot.data.objects.SettingsContainer; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; diff --git a/src/main/java/org/cascadebot/cascadebot/data/objects/PerGuildPermissionsManager.java b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/PerGuildPermissionsManager.java similarity index 94% rename from src/main/java/org/cascadebot/cascadebot/data/objects/PerGuildPermissionsManager.java rename to src/main/java/org/cascadebot/cascadebot/data/objects/guild/PerGuildPermissionsManager.java index 68ae3e808..dd0e4b21f 100644 --- a/src/main/java/org/cascadebot/cascadebot/data/objects/PerGuildPermissionsManager.java +++ b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/PerGuildPermissionsManager.java @@ -3,24 +3,19 @@ * Licensed under the MIT license. */ -package org.cascadebot.cascadebot.data.objects; +package org.cascadebot.cascadebot.data.objects.guild; import com.google.common.collect.ImmutableSet; -import net.dv8tion.jda.api.entities.Guild; import org.cascadebot.cascadebot.CascadeBot; import org.cascadebot.cascadebot.commandmeta.Module; -import org.cascadebot.cascadebot.data.managers.GuildDataManager; import org.cascadebot.cascadebot.permissions.CascadePermission; import org.cascadebot.cascadebot.permissions.PermissionNode; import org.cascadebot.cascadebot.permissions.PermissionsManager; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; public class PerGuildPermissionsManager { diff --git a/src/main/java/org/cascadebot/cascadebot/data/objects/PermissionObject.java b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/PermissionObject.java similarity index 91% rename from src/main/java/org/cascadebot/cascadebot/data/objects/PermissionObject.java rename to src/main/java/org/cascadebot/cascadebot/data/objects/guild/PermissionObject.java index d451ebaea..f4e97ac9a 100644 --- a/src/main/java/org/cascadebot/cascadebot/data/objects/PermissionObject.java +++ b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/PermissionObject.java @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -package org.cascadebot.cascadebot.data.objects; +package org.cascadebot.cascadebot.data.objects.guild; import org.cascadebot.cascadebot.commandmeta.Module; import org.cascadebot.cascadebot.permissions.CascadePermission; diff --git a/src/main/java/org/cascadebot/cascadebot/data/objects/Tag.java b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/Tag.java similarity index 90% rename from src/main/java/org/cascadebot/cascadebot/data/objects/Tag.java rename to src/main/java/org/cascadebot/cascadebot/data/objects/guild/Tag.java index 845a532c9..62ea44fee 100644 --- a/src/main/java/org/cascadebot/cascadebot/data/objects/Tag.java +++ b/src/main/java/org/cascadebot/cascadebot/data/objects/guild/Tag.java @@ -3,7 +3,7 @@ * Licensed under the MIT license. */ -package org.cascadebot.cascadebot.data.objects; +package org.cascadebot.cascadebot.data.objects.guild; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -13,6 +13,8 @@ import org.apache.commons.lang3.EnumUtils; import org.cascadebot.cascadebot.commandmeta.CommandContext; import org.cascadebot.cascadebot.commandmeta.Module; +import org.cascadebot.cascadebot.data.objects.Placeholder; +import org.cascadebot.cascadebot.data.objects.guild.PermissionObject; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/java/org/cascadebot/cascadebot/events/ButtonEventListener.java b/src/main/java/org/cascadebot/cascadebot/events/ButtonEventListener.java index 1d0847206..e04657516 100644 --- a/src/main/java/org/cascadebot/cascadebot/events/ButtonEventListener.java +++ b/src/main/java/org/cascadebot/cascadebot/events/ButtonEventListener.java @@ -13,7 +13,7 @@ import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.cascadebot.cascadebot.data.managers.GuildDataManager; -import org.cascadebot.cascadebot.data.objects.GuildData; +import org.cascadebot.cascadebot.data.objects.guild.GuildData; import org.cascadebot.cascadebot.metrics.Metrics; import org.cascadebot.cascadebot.utils.buttons.ButtonGroup; import org.cascadebot.cascadebot.utils.buttons.ButtonsCache; diff --git a/src/main/java/org/cascadebot/cascadebot/events/CommandListener.java b/src/main/java/org/cascadebot/cascadebot/events/CommandListener.java index 61dc1908c..9653cdf6d 100644 --- a/src/main/java/org/cascadebot/cascadebot/events/CommandListener.java +++ b/src/main/java/org/cascadebot/cascadebot/events/CommandListener.java @@ -12,6 +12,7 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.requests.ErrorResponse; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; import org.cascadebot.cascadebot.CascadeBot; import org.cascadebot.cascadebot.Environment; import org.cascadebot.cascadebot.MDCException; @@ -22,8 +23,8 @@ import org.cascadebot.cascadebot.data.Config; import org.cascadebot.cascadebot.data.language.Language; import org.cascadebot.cascadebot.data.managers.GuildDataManager; -import org.cascadebot.cascadebot.data.objects.GuildData; -import org.cascadebot.cascadebot.data.objects.Tag; +import org.cascadebot.cascadebot.data.objects.guild.Tag; +import org.cascadebot.cascadebot.data.objects.guild.GuildData; import org.cascadebot.cascadebot.messaging.MessageType; import org.cascadebot.cascadebot.messaging.Messaging; import org.cascadebot.cascadebot.messaging.MessagingObjects; @@ -114,6 +115,14 @@ private void processCommands(GuildMessageReceivedEvent event, GuildData guildDat ICommandMain cmd = CascadeBot.INS.getCommandManager().getCommand(trigger, guildData); CommandContext context = new CommandContext(cmd, event.getJDA(), event.getChannel(), event.getMessage(), event.getGuild(), guildData, args, event.getMember(), trigger, isMention); if (cmd != null) { + if (!StringUtils.isBlank(cmd.getRequiredFlag())) { + if (!guildData.getAllFlags().hasFlag(cmd.getRequiredFlag())) { + EmbedBuilder builder = MessagingObjects.getMessageTypeEmbedBuilder(org.cascadebot.cascadebot.messaging.MessageType.WARNING, event.getAuthor()); + builder.appendDescription(Language.i18n(guildData.getLocale(), "command_meta.donate", guildData.getCore().getPrefix())); + event.getChannel().sendMessage(builder.build()).queue(); + return; + } + } Metrics.INS.commandsSubmitted.labels(cmd.getClass().getSimpleName()).inc(); if (!cmd.getModule().isPrivate() && !guildData.getCore().isModuleEnabled(cmd.getModule())) { if (guildData.getCore().getShowModuleErrors() || Environment.isDevelopment()) { @@ -153,6 +162,14 @@ private boolean processSubCommands(ICommandMain cmd, String[] args, CommandConte if (!isAuthorised(cmd, subCommandContext)) { return false; } + if (!StringUtils.isBlank(subCommand.getRequiredFlag())) { + if (!parentCommandContext.getData().getAllFlags().hasFlag(subCommand.getRequiredFlag())) { + EmbedBuilder builder = MessagingObjects.getMessageTypeEmbedBuilder(org.cascadebot.cascadebot.messaging.MessageType.WARNING, parentCommandContext.getUser()); + builder.appendDescription(Language.i18n(parentCommandContext.getData().getLocale(), "command_meta.donate", parentCommandContext.getData().getCore().getPrefix())); + parentCommandContext.getChannel().sendMessage(builder.build()).queue(); + return false; + } + } return dispatchCommand(subCommand, subCommandContext); } } diff --git a/src/main/java/org/cascadebot/cascadebot/events/GuildSaveListener.java b/src/main/java/org/cascadebot/cascadebot/events/GuildSaveListener.java index 8d97f5e5a..513efaf23 100644 --- a/src/main/java/org/cascadebot/cascadebot/events/GuildSaveListener.java +++ b/src/main/java/org/cascadebot/cascadebot/events/GuildSaveListener.java @@ -9,7 +9,7 @@ import com.github.benmanes.caffeine.cache.RemovalListener; import org.cascadebot.cascadebot.CascadeBot; import org.cascadebot.cascadebot.data.managers.GuildDataManager; -import org.cascadebot.cascadebot.data.objects.GuildData; +import org.cascadebot.cascadebot.data.objects.guild.GuildData; import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/src/main/java/org/cascadebot/cascadebot/events/UserPatreonListener.java b/src/main/java/org/cascadebot/cascadebot/events/UserPatreonListener.java new file mode 100644 index 000000000..fb63b9997 --- /dev/null +++ b/src/main/java/org/cascadebot/cascadebot/events/UserPatreonListener.java @@ -0,0 +1,26 @@ +package org.cascadebot.cascadebot.events; + +import net.dv8tion.jda.api.events.guild.member.GuildMemberLeaveEvent; +import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleAddEvent; +import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.cascadebot.cascadebot.data.managers.CascadeUserDataManager; + +public class UserPatreonListener extends ListenerAdapter { + + //TODO maybe add more checks + @Override + public void onGuildMemberLeave(GuildMemberLeaveEvent event) { + CascadeUserDataManager.getUser(event.getMember().getIdLong()).update(); + } + + @Override + public void onGuildMemberRoleAdd(GuildMemberRoleAddEvent event) { + CascadeUserDataManager.getUser(event.getMember().getIdLong()).update(); + } + + @Override + public void onGuildMemberRoleRemove(GuildMemberRoleRemoveEvent event) { + CascadeUserDataManager.getUser(event.getMember().getIdLong()).update(); + } +} diff --git a/src/main/java/org/cascadebot/cascadebot/music/CascadePlayer.java b/src/main/java/org/cascadebot/cascadebot/music/CascadePlayer.java index 9cbd77c4c..0c3306938 100644 --- a/src/main/java/org/cascadebot/cascadebot/music/CascadePlayer.java +++ b/src/main/java/org/cascadebot/cascadebot/music/CascadePlayer.java @@ -136,10 +136,16 @@ default void stop() { stopTrack(); } - default void loadLink(String input, TrackData trackData, Consumer noMatchConsumer, Consumer exceptionConsumer, Consumer> resultTracks) { + default void loadLink(String input, TrackData trackData, Consumer noMatchConsumer, Consumer exceptionConsumer, Consumer> resultTracks, boolean allServices) { CascadeBot.INS.getMusicHandler().getPlayerManager().loadItem(input, new AudioLoadResultHandler() { @Override public void trackLoaded(AudioTrack audioTrack) { + if (!allServices) { + if (!audioTrack.getSourceManager().getSourceName().equals(CascadeBot.INS.getMusicHandler().getYoutubeSourceName())) { + noMatchConsumer.accept("Cannot load non-youtube tracks"); + return; + } + } audioTrack.setUserData(trackData); resultTracks.accept(Collections.singletonList(audioTrack)); } @@ -148,6 +154,12 @@ public void trackLoaded(AudioTrack audioTrack) { public void playlistLoaded(AudioPlaylist audioPlaylist) { List tracks = new ArrayList<>(); for (AudioTrack track : audioPlaylist.getTracks()) { + if (!allServices) { + if (!track.getSourceManager().getSourceName().equals(CascadeBot.INS.getMusicHandler().getYoutubeSourceName())) { + noMatchConsumer.accept("Cannot load non-youtube tracks"); + break; + } + } track.setUserData(track); tracks.add(track); } @@ -166,7 +178,7 @@ public void loadFailed(FriendlyException e) { }); } - default void loadPlaylist(String name, TrackData trackData, BiConsumer> consumer) { + default void loadPlaylist(String name, TrackData trackData, BiConsumer> consumer, boolean allServices) { Playlist guild = PlaylistManager.getPlaylistByName(getGuild().getIdLong(), PlaylistType.GUILD, name); Playlist user = PlaylistManager.getPlaylistByName(trackData.getUserId(), PlaylistType.USER, name); if (guild != null && user != null) { @@ -174,17 +186,17 @@ default void loadPlaylist(String name, TrackData trackData, BiConsumer { consumer.accept(LoadPlaylistResult.LOADED_GUILD, tracks); - }); + }, allServices); } else if (user != null) { loadLoadedPlaylist(user, trackData, tracks -> { consumer.accept(LoadPlaylistResult.LOADED_USER, tracks); - }); + }, allServices); } else { consumer.accept(LoadPlaylistResult.DOESNT_EXIST, null); } } - default void loadPlaylist(String name, TrackData trackData, PlaylistType scope, BiConsumer> consumer) { + default void loadPlaylist(String name, TrackData trackData, PlaylistType scope, BiConsumer> consumer, boolean allServices) { LoadPlaylistResult result = LoadPlaylistResult.DOESNT_EXIST; long owner = 0; switch (scope) { @@ -206,10 +218,10 @@ default void loadPlaylist(String name, TrackData trackData, PlaylistType scope, LoadPlaylistResult loadPlaylistResult = result; loadLoadedPlaylist(playlist, trackData, tracks -> { consumer.accept(loadPlaylistResult, tracks); - }); + }, allServices); } - default void loadLoadedPlaylist(Playlist playlist, TrackData trackData, Consumer> loadedConsumer) { + default void loadLoadedPlaylist(Playlist playlist, TrackData trackData, Consumer> loadedConsumer, boolean allServices) { List tracks = new ArrayList<>(); for (String url : playlist.getTracks()) { loadLink(url, trackData, noMatch -> { @@ -221,7 +233,7 @@ default void loadLoadedPlaylist(Playlist playlist, TrackData trackData, Consumer if (tracks.size() == playlist.getTracks().size()) { loadedConsumer.accept(tracks); } - }); + }, allServices); } } diff --git a/src/main/java/org/cascadebot/cascadebot/permissions/PermissionsManager.java b/src/main/java/org/cascadebot/cascadebot/permissions/PermissionsManager.java index 08ef63c09..e7535961d 100644 --- a/src/main/java/org/cascadebot/cascadebot/permissions/PermissionsManager.java +++ b/src/main/java/org/cascadebot/cascadebot/permissions/PermissionsManager.java @@ -17,7 +17,7 @@ import org.cascadebot.cascadebot.commandmeta.Module; import org.cascadebot.cascadebot.data.language.Language; import org.cascadebot.cascadebot.data.language.Locale; -import org.cascadebot.cascadebot.data.objects.GuildData; +import org.cascadebot.cascadebot.data.objects.guild.GuildData; import org.cascadebot.cascadebot.utils.DiscordUtils; import org.cascadebot.shared.SecurityLevel; import org.slf4j.Logger; diff --git a/src/main/java/org/cascadebot/cascadebot/utils/ConfirmUtils.java b/src/main/java/org/cascadebot/cascadebot/utils/ConfirmUtils.java index 584323730..f5ee8a706 100644 --- a/src/main/java/org/cascadebot/cascadebot/utils/ConfirmUtils.java +++ b/src/main/java/org/cascadebot/cascadebot/utils/ConfirmUtils.java @@ -15,7 +15,7 @@ import org.cascadebot.cascadebot.CascadeBot; import org.cascadebot.cascadebot.UnicodeConstants; import org.cascadebot.cascadebot.data.managers.GuildDataManager; -import org.cascadebot.cascadebot.data.objects.GuildData; +import org.cascadebot.cascadebot.data.objects.guild.GuildData; import org.cascadebot.cascadebot.messaging.MessageType; import org.cascadebot.cascadebot.messaging.Messaging; import org.cascadebot.cascadebot.tasks.Task; diff --git a/src/main/java/org/cascadebot/cascadebot/utils/pagination/PageObjects.java b/src/main/java/org/cascadebot/cascadebot/utils/pagination/PageObjects.java index 0ada06f8b..926ad0afd 100644 --- a/src/main/java/org/cascadebot/cascadebot/utils/pagination/PageObjects.java +++ b/src/main/java/org/cascadebot/cascadebot/utils/pagination/PageObjects.java @@ -14,7 +14,7 @@ import net.dv8tion.jda.api.entities.Message; import org.cascadebot.cascadebot.data.language.Language; import org.cascadebot.cascadebot.data.managers.GuildDataManager; -import org.cascadebot.cascadebot.data.objects.GuildData; +import org.cascadebot.cascadebot.data.objects.guild.GuildData; import org.cascadebot.cascadebot.utils.FormatUtils; import org.cascadebot.cascadebot.utils.Table; diff --git a/src/main/kotlin/org/cascadebot/cascadebot/commandmeta/CommandContext.kt b/src/main/kotlin/org/cascadebot/cascadebot/commandmeta/CommandContext.kt index 13ec4853b..8b9acc734 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/commandmeta/CommandContext.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/commandmeta/CommandContext.kt @@ -18,8 +18,8 @@ import org.cascadebot.cascadebot.data.Config import org.cascadebot.cascadebot.data.language.Language import org.cascadebot.cascadebot.data.language.Locale import org.cascadebot.cascadebot.data.objects.ArgumentType -import org.cascadebot.cascadebot.data.objects.GuildData -import org.cascadebot.cascadebot.data.objects.GuildSettingsCore +import org.cascadebot.cascadebot.data.objects.guild.GuildData +import org.cascadebot.cascadebot.data.objects.guild.GuildSettingsCore import org.cascadebot.cascadebot.messaging.MessagingDirectMessage import org.cascadebot.cascadebot.messaging.MessagingTimed import org.cascadebot.cascadebot.messaging.MessagingTyped diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt deleted file mode 100644 index b3fa549ab..000000000 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildData.kt +++ /dev/null @@ -1,108 +0,0 @@ -package org.cascadebot.cascadebot.data.objects - -import com.google.common.collect.Sets -import de.bild.codec.annotations.Id -import de.bild.codec.annotations.Transient -import net.dv8tion.jda.api.entities.Message -import net.dv8tion.jda.api.entities.MessageChannel -import org.cascadebot.cascadebot.CascadeBot -import org.cascadebot.cascadebot.data.language.Locale -import org.cascadebot.cascadebot.music.CascadeLavalinkPlayer -import org.cascadebot.cascadebot.utils.buttons.ButtonGroup -import org.cascadebot.cascadebot.utils.buttons.ButtonsCache -import org.cascadebot.cascadebot.utils.buttons.PersistentButtonGroup -import org.cascadebot.cascadebot.utils.pagination.PageCache -import java.util.Date - -class GuildData(@field:Id val guildId: Long) { - - private constructor() : this(0L) { - // Private constructor for MongoDB - } - - //region Meta information - private val creationDate = Date() - //endregion - - val enabledFlags: MutableSet = Sets.newConcurrentHashSet() - - // TODO: Keep this here or remove it? It just serves as an accessor for the actual locale - val locale: Locale - get() = core.locale - - //region Guild data containers - val core = GuildSettingsCore() - val useful = GuildSettingsUseful() - val moderation = GuildSettingsModeration() - val management = GuildSettingsManagement() - val music = GuildSettingsMusic() - //endregion - - //region Transient fields - @Transient - val buttonsCache = ButtonsCache(5) - - @Transient - val pageCache = PageCache() - - @Transient - val permissionsManager = PerGuildPermissionsManager() - //endregion - - val persistentButtons = HashMap>() - - //endregion - //region Data Loaded Methods - fun onGuildLoaded() { - loadMusicSettings() - permissionsManager.registerPermissions(this) - } - - private fun loadMusicSettings() { - val player = CascadeBot.INS.musicHandler.getPlayer(guildId)!! - if (music.preserveVolume) { - player.volume = music.volume - } - if (music.preserveEqualizer) { - if (CascadeBot.INS.musicHandler.lavalinkEnabled) { - if (player is CascadeLavalinkPlayer) { - player.setBands(music.equalizerBands) - } - } - } - } - - fun enableFlag(flag: Flag): Boolean { - return enabledFlags.add(flag) - } - - fun disableFlag(flag: Flag): Boolean { - return enabledFlags.remove(flag) - } - - fun isFlagEnabled(flag: Flag): Boolean { - return enabledFlags.contains(flag) - } - - fun addButtonGroup(channel: MessageChannel, message: Message, group: ButtonGroup) { - group.setMessage(message.idLong) - if (group is PersistentButtonGroup) { - putPersistentButtonGroup(channel.idLong, message.idLong, group) - } else { - buttonsCache.put(channel.idLong, message.idLong, group) - } - } - - private fun putPersistentButtonGroup(channelId: Long, messageId: Long, buttonGroup: PersistentButtonGroup) { - if (persistentButtons.containsKey(channelId) && persistentButtons[channelId] != null) { - persistentButtons[channelId]!![messageId] = buttonGroup - } else { - persistentButtons[channelId] = HashMap() - persistentButtons[channelId]!![messageId] = buttonGroup - } - } - - //endregion - - -} diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/AmountFlag.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/AmountFlag.kt new file mode 100644 index 000000000..c5d52a6af --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/AmountFlag.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 CascadeBot. All rights reserved. + * Licensed under the MIT license. + */ +package org.cascadebot.cascadebot.data.objects.donation + +import com.google.gson.JsonObject +import org.cascadebot.cascadebot.data.language.Language.i18n +import org.cascadebot.cascadebot.data.language.Locale + +class AmountFlag : DataFlag { + var amount = 0 + + private constructor() : super() + constructor(id: String, scope: FlagScope) : super(id, scope) + + override fun parseFlagData(flagDataObject: JsonObject): DataFlag { + amount = flagDataObject["amount"].asInt + return this + } + + override fun toString(): String { + return "AmountFlag(id=$id, amount=$amount)" + } + + override fun getDescription(locale: Locale): String { + return i18n(locale, "flags.$id.description", amount) + } + + override fun compareTo(flag: DataFlag): Int { + if (flag !is AmountFlag) { + throw UnsupportedOperationException("Cannot compare different types of flags") + } + return amount.compareTo(flag.amount); + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/DataFlag.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/DataFlag.kt new file mode 100644 index 000000000..8d785b487 --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/DataFlag.kt @@ -0,0 +1,14 @@ +package org.cascadebot.cascadebot.data.objects.donation + +import com.google.gson.JsonObject +import org.cascadebot.cascadebot.data.language.Locale + +abstract class DataFlag : Flag { + constructor(id: String, scope: FlagScope) : super(id, scope) + protected constructor() : super() + + abstract fun parseFlagData(flagDataObject: JsonObject): DataFlag + abstract override fun getDescription(locale: Locale): String + + abstract operator fun compareTo(flag: DataFlag): Int +} \ No newline at end of file diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/Flag.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/Flag.kt new file mode 100644 index 000000000..c29c57701 --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/Flag.kt @@ -0,0 +1,24 @@ +package org.cascadebot.cascadebot.data.objects.donation + +import org.cascadebot.cascadebot.data.language.Language.getLanguage +import org.cascadebot.cascadebot.data.language.Locale + +open class Flag ( + val id: String, + val scope: FlagScope +) { + + constructor() : this ("", FlagScope.GUILD) + + fun getName(locale: Locale): String { + return getLanguage(locale)!!.getString("flags.$id.name").orElse("No language string defined") + } + + open fun getDescription(locale: Locale): String { + return getLanguage(locale)!!.getString("flags.$id.description").orElse("No language string defined") + } + + enum class FlagScope { + USER, GUILD + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/FlagContainer.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/FlagContainer.kt new file mode 100644 index 000000000..4ff9121df --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/FlagContainer.kt @@ -0,0 +1,19 @@ +package org.cascadebot.cascadebot.data.objects.donation + +open class FlagContainer { + var flags: MutableSet = mutableSetOf(); + + constructor() + + constructor(flags: MutableSet) { + this.flags = flags + } + + open fun getFlag(id: String): Flag? { + return flags.stream().filter { flag: Flag -> flag.id == id }.findFirst().orElse(null) + } + + fun hasFlag(id: String): Boolean { + return getFlag(id) != null + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/Tier.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/Tier.kt new file mode 100644 index 000000000..f0afa2d46 --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/Tier.kt @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2019 CascadeBot. All rights reserved. + * Licensed under the MIT license. + */ +package org.cascadebot.cascadebot.data.objects.donation + +import com.google.gson.JsonArray +import io.github.binaryoverload.JSONConfig +import org.apache.commons.lang3.StringUtils +import org.cascadebot.cascadebot.CascadeBot +import org.cascadebot.cascadebot.data.language.Language.getLanguage +import org.cascadebot.cascadebot.data.language.Locale +import org.cascadebot.cascadebot.data.objects.donation.Flag.FlagScope +import java.util.HashMap +import kotlin.collections.set + +class Tier : FlagContainer { + var parent: String? = null + var extras: MutableList = mutableListOf() + + private constructor() + + constructor(flags: MutableSet) : + this( + null, + flags, + ArrayList() + ) + + constructor(parent: String?, flags: MutableSet, extras: MutableList) { + this.parent = parent + this.flags = flags + this.extras = extras + } + + fun addFlag(flag: Flag) { + flags.add(flag) + } + + fun getParent(): Tier? { + return if (parent == null) null else tiers[parent] + } + + fun getAllFlags(): Set { + val flags = flags.toMutableSet() + if (getParent() != null) { + flags.addAll(getParent()!!.getAllFlags()) + } + return flags + } + + override fun getFlag(id: String): Flag? { + var returnFlag = flags.stream().filter { flag: Flag -> flag.id == id }.findFirst().orElse(null) + if (parent != null && returnFlag == null) { + returnFlag = tiers[parent]!!.getFlag(id) + } + return returnFlag + } + + fun isTierParent(tier: String): Boolean { + if (StringUtils.isBlank(parent)) { + return false + } + return if (parent == tier) { + true + } else tiers[parent]!!.isTierParent(tier) + } + + /** + * Returns the benefits gave in this tier to a guild. + * + * @param locale The locale to use for translations + * @param idsUsed This parameter should be null. It's used for when calling parent method. It stores flags that have been used already. + * @return The guild benefits gave in this tier + */ + fun getGuildTierString(locale: Locale, idsUsed: MutableList?): String { + val tierStringBuilder = StringBuilder() + var localIds = idsUsed + if (localIds == null) { + localIds = ArrayList() + } + for (flag in flags) { + if (!localIds.contains(flag.id)) { + if (flag.scope == FlagScope.GUILD) { + localIds.add(flag.id) + tierStringBuilder.append(" - **").append(flag.getName(locale)).append(":** ").append(flag.getDescription(locale)).append('\n') + } + } + } + for (extra in extras) { + if (extra.scope == FlagScope.GUILD) { //Ignore t-shirt related extra stuff as that isn't a guild thing. + val extraStr = getLanguage(locale)!!.getString(extra.path).orElse("No language string defined") + tierStringBuilder.append(" - ").append(extraStr).append('\n') + } + } + if (parent != null && parent != "default") { + tierStringBuilder.apply { + append('\n') + append("**__Inherited from ").append(parent).append(":__**\n") + append(tiers[parent]!!.getGuildTierString(locale, idsUsed)) + } + } + return tierStringBuilder.toString() + } + + class TierExtra { + val path: String? + val scope: FlagScope? + + private constructor() { + path = null + scope = null + } + + constructor(path: String?, scope: FlagScope?) { + this.path = path + this.scope = scope + } + } + + companion object { + val tiers: MutableMap = HashMap() + fun parseTiers() { + val config: JSONConfig + config = try { + JSONConfig(CascadeBot::class.java.classLoader.getResourceAsStream("./default_tiers.json")) + } catch (e: Exception) { + // We have no default tiers :( + CascadeBot.LOGGER.warn("The default tiers file was unable to be loaded!", e) + return + } + for (tierName in config.getKeys(false)) { + if (tierName.equals("example", ignoreCase = true)) continue + tiers[tierName] = parseTier(config.getSubConfig(tierName).orElseThrow()) + } + } + + private fun parseTier(config: JSONConfig): Tier { + val parent = config.getString("parent").orElse(null) + val extras: MutableList = ArrayList() + val extrasElement = config.getElement("extras").orElse(JsonArray()) + if (extrasElement.isJsonArray) { + for (element in extrasElement.asJsonArray) { + val `object` = element.asJsonObject + val path = `object`["path"].asString + val scopeStr = `object`["scope"].asString + var scope: FlagScope? = null + when (scopeStr) { + "user" -> scope = FlagScope.USER + "guild" -> scope = FlagScope.GUILD + } + extras.add(TierExtra(path, scope)) + } + } + val flagsEle = config.getElement("flags").orElse(JsonArray()) + val flags: MutableSet = HashSet() + if (flagsEle.isJsonArray) { + for (jsonElement in flagsEle.asJsonArray) { + val jsonObject = jsonElement.asJsonObject + val name = jsonObject["name"].asString + val scope = when (jsonObject["scope"].asString) { + "user" -> FlagScope.USER + "guild" -> FlagScope.GUILD + else -> FlagScope.USER + } + if (jsonObject.has("type")) { + when (jsonObject["type"].asString) { + "amount" -> flags.add(AmountFlag(name, scope).parseFlagData(jsonObject["data"].asJsonObject)) + "time" -> flags.add(TimeFlag(name, scope).parseFlagData(jsonObject["data"].asJsonObject)) + } + } else { + flags.add(Flag(name, scope)) + } + } + } + return Tier(parent, flags, extras) + } + + fun getTier(id: String): Tier? { + return tiers[id] + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/TimeFlag.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/TimeFlag.kt new file mode 100644 index 000000000..aa394d32d --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/donation/TimeFlag.kt @@ -0,0 +1,33 @@ +package org.cascadebot.cascadebot.data.objects.donation + +import com.google.gson.JsonObject +import org.cascadebot.cascadebot.data.language.Language.i18n +import org.cascadebot.cascadebot.data.language.Locale +import org.cascadebot.cascadebot.utils.FormatUtils + +class TimeFlag : DataFlag { + private var mills: Long = 0 + + private constructor() : super() + constructor(id: String, scope: FlagScope) : super(id, scope) + + override fun parseFlagData(flagDataObject: JsonObject): DataFlag { + mills = flagDataObject["time"].asLong + return this + } + + override fun toString(): String { + return "TimeFlag(id=$id, time=$mills)" + } + + override fun getDescription(locale: Locale): String { + return i18n(locale, "flags.$id.description", FormatUtils.formatLongTimeMills(mills)) + } + + override fun compareTo(flag: DataFlag): Int { + if (flag !is TimeFlag) { + throw UnsupportedOperationException("Cannot compare different types of flags") + } + return mills.compareTo(flag.mills) + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildCommandInfo.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildCommandInfo.kt similarity index 92% rename from src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildCommandInfo.kt rename to src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildCommandInfo.kt index 4db2e6fd4..743061f7b 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildCommandInfo.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildCommandInfo.kt @@ -1,4 +1,4 @@ -package org.cascadebot.cascadebot.data.objects +package org.cascadebot.cascadebot.data.objects.guild import org.cascadebot.cascadebot.commandmeta.ICommandMain import org.cascadebot.cascadebot.data.language.Locale diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildData.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildData.kt new file mode 100644 index 000000000..4abde1bc2 --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildData.kt @@ -0,0 +1,325 @@ +package org.cascadebot.cascadebot.data.objects.guild + +import com.google.common.collect.Sets +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import de.bild.codec.annotations.Id +import de.bild.codec.annotations.Transient +import net.dv8tion.jda.api.entities.Message +import net.dv8tion.jda.api.entities.MessageChannel +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import org.cascadebot.cascadebot.CascadeBot +import org.cascadebot.cascadebot.data.Config +import org.cascadebot.cascadebot.data.language.Locale +import org.cascadebot.cascadebot.data.managers.CascadeUserDataManager +import org.cascadebot.cascadebot.data.objects.donation.DataFlag +import org.cascadebot.cascadebot.data.objects.donation.Flag +import org.cascadebot.cascadebot.data.objects.donation.FlagContainer +import org.cascadebot.cascadebot.data.objects.donation.Tier +import org.cascadebot.cascadebot.data.objects.user.CascadeUser +import org.cascadebot.cascadebot.music.CascadeLavalinkPlayer +import org.cascadebot.cascadebot.utils.buttons.ButtonGroup +import org.cascadebot.cascadebot.utils.buttons.ButtonsCache +import org.cascadebot.cascadebot.utils.buttons.PersistentButtonGroup +import org.cascadebot.cascadebot.utils.pagination.PageCache +import java.util.Date + +class GuildData(@field:Id val guildId: Long) { + + private constructor() : this(0L) { + // Private constructor for MongoDB + } + + //region Meta information + private val creationDate = Date() + //endregion + + val enabledFlags: MutableSet = Sets.newConcurrentHashSet() + + // TODO: Keep this here or remove it? It just serves as an accessor for the actual locale + val locale: Locale + get() = core.locale + + //region Guild data containers + val core = GuildSettingsCore() + val useful = GuildSettingsUseful() + val moderation = GuildSettingsModeration() + val management = GuildSettingsManagement() + val music = GuildSettingsMusic() + //endregion + + //region Transient fields + @Transient + val buttonsCache = ButtonsCache(5) + + @Transient + val pageCache = PageCache() + + @Transient + val permissionsManager = PerGuildPermissionsManager() + //endregion + + val persistentButtons = HashMap>() + + //endregion + + private val supporters: MutableSet = mutableSetOf() + private val flags: MutableSet = mutableSetOf() + + //region Data Loaded Methods + fun onGuildLoaded() { + loadMusicSettings() + permissionsManager.registerPermissions(this) + } + + private fun loadMusicSettings() { + val player = CascadeBot.INS.musicHandler.getPlayer(guildId)!! + if (music.preserveVolume) { + player.volume = music.volume + } + if (music.preserveEqualizer) { + if (CascadeBot.INS.musicHandler.lavalinkEnabled) { + if (player is CascadeLavalinkPlayer) { + player.setBands(music.equalizerBands) + } + } + } + } + + fun enableFlag(flag: Flag): Boolean { + return enabledFlags.add(flag) + } + + fun disableFlag(flag: Flag): Boolean { + return enabledFlags.remove(flag) + } + + fun isFlagEnabled(flag: Flag): Boolean { + return enabledFlags.contains(flag) + } + + fun addButtonGroup(channel: MessageChannel, message: Message, group: ButtonGroup) { + group.setMessage(message.idLong) + if (group is PersistentButtonGroup) { + putPersistentButtonGroup(channel.idLong, message.idLong, group) + } else { + buttonsCache.put(channel.idLong, message.idLong, group) + } + } + + private fun putPersistentButtonGroup(channelId: Long, messageId: Long, buttonGroup: PersistentButtonGroup) { + if (persistentButtons.containsKey(channelId) && persistentButtons[channelId] != null) { + persistentButtons[channelId]!![messageId] = buttonGroup + } else { + persistentButtons[channelId] = HashMap() + persistentButtons[channelId]!![messageId] = buttonGroup + } + } + + //endregion + + fun getGuildTierName(): String? { + if (supporters.isEmpty()) { + return "default" + } + var highestTierName = "default" + for (id in supporters) { + val user = CascadeUserDataManager.getUser(id) + if (user.tier.isTierParent(highestTierName)) { + highestTierName = user.tierName + } + } + return highestTierName + } + + fun getAllFlags(): FlagContainer { + val flags = ArrayList(getGuildTier()?.getAllFlags()!!.toList()) + for (guildFlag in this.flags) { + if (guildFlag !is DataFlag) { + continue + } + if (getGuildTier()?.hasFlag(guildFlag.id)!!) { + val compareFlag: Flag? = getGuildTier()?.getFlag(guildFlag.id) + if (compareFlag !is DataFlag) { + continue + } + if (guildFlag > compareFlag) { + flags.remove(compareFlag) + flags.add(guildFlag) + } + } else { + flags.add(guildFlag) + } + } + + for (id in supporters) { + val user = CascadeUserDataManager.getUser(id) + if (user.blackList.contains(guildId)) { + continue + } + for (userFlag in user.flags) { + if (userFlag !is DataFlag) { + continue + } + if (getGuildTier()?.hasFlag(userFlag.id)!!) { + val compareFlag: Flag? = getGuildTier()?.getFlag(userFlag.id) + if (compareFlag !is DataFlag) { + continue + } + if (userFlag > compareFlag) { + flags.remove(compareFlag) + flags.add(userFlag) + } + } else { + flags.add(userFlag) + } + } + } + + return FlagContainer(HashSet(flags)) + } + + fun optOutUser(user: CascadeUser): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/user/" + user.userId + "/guilds/" + guildId) + .method("DELETE", null) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + user.blackList.add(guildId) + } + } + + fun optInUser(user: CascadeUser): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/user/" + user.userId + "/guilds/" + guildId) + .method("POST", null) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + user.blackList.remove(guildId) + } + } + + //region Guild Flags + fun addFlag(flag: Flag): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val jsonObject = JsonObject() + val addFlags = JsonArray() + addFlags.add(flag.id) + jsonObject.add("add", addFlags) + val requestBody = CascadeBot.getGSON().toJson(jsonObject).toRequestBody() + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/guild/" + guildId + "/flags") + .method("PATCH", requestBody) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + flags.add(flag) + } + } + + fun removeFlag(flag: Flag): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val jsonObject = JsonObject() + val removeFlags = JsonArray() + removeFlags.add(flag.id) + jsonObject.add("remove", removeFlags) + val requestBody = CascadeBot.getGSON().toJson(jsonObject).toRequestBody() + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/guild/" + guildId + "/flags") + .method("PATCH", requestBody) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + flags.remove(flag) + } + } + + fun addFlags(flags: List): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val jsonObject = JsonObject() + val addFlags = CascadeBot.getGSON().toJsonTree(flags); + jsonObject.add("add", addFlags) + val requestBody = CascadeBot.getGSON().toJson(jsonObject).toRequestBody() + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/guild/" + guildId + "/flags") + .method("PATCH", requestBody) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + this.flags.addAll(flags) + } + } + + fun removeFlags(flags: List): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val jsonObject = JsonObject() + val removeFlags = CascadeBot.getGSON().toJsonTree(flags); + jsonObject.add("remove", removeFlags) + val requestBody = CascadeBot.getGSON().toJson(jsonObject).toRequestBody() + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/guild/" + guildId + "/flags") + .method("PATCH", requestBody) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + this.flags.removeAll(flags) + } + } + + fun clearFlags(): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val jsonObject = JsonObject() + jsonObject.add("clear", JsonPrimitive(true)) + val requestBody = CascadeBot.getGSON().toJson(jsonObject).toRequestBody() + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/guild/" + guildId + "/flags") + .method("PATCH", requestBody) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + flags.clear() + true + } + } + //endregion + + private fun getGuildTier(): Tier? { + if (supporters.isEmpty()) { + return Tier.getTier("default") + } + var highest = Tier.getTier("default") + var highestTierName = "default" + for (id in supporters) { + val user = CascadeUserDataManager.getUser(id) + if (user.blackList.contains(guildId)) { + continue + } + if (user.tier.isTierParent(highestTierName)) { + highest = user.tier + highestTierName = user.tierName + } + } + return highest + } + +} diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildSettingsCore.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsCore.kt similarity index 94% rename from src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildSettingsCore.kt rename to src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsCore.kt index cde99d9a8..15b54a264 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildSettingsCore.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsCore.kt @@ -1,4 +1,4 @@ -package org.cascadebot.cascadebot.data.objects +package org.cascadebot.cascadebot.data.objects.guild import com.google.common.collect.Sets import org.cascadebot.cascadebot.CascadeBot @@ -6,6 +6,9 @@ import org.cascadebot.cascadebot.commandmeta.ICommandMain import org.cascadebot.cascadebot.commandmeta.Module import org.cascadebot.cascadebot.data.Config import org.cascadebot.cascadebot.data.language.Locale +import org.cascadebot.cascadebot.data.objects.ModuleFlag +import org.cascadebot.cascadebot.data.objects.Setting +import org.cascadebot.cascadebot.data.objects.SettingsContainer import java.util.concurrent.ConcurrentHashMap diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildSettingsManagement.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsManagement.kt similarity index 79% rename from src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildSettingsManagement.kt rename to src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsManagement.kt index 0be9e59b4..28eec772a 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildSettingsManagement.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsManagement.kt @@ -1,6 +1,8 @@ -package org.cascadebot.cascadebot.data.objects +package org.cascadebot.cascadebot.data.objects.guild import org.cascadebot.cascadebot.commandmeta.Module +import org.cascadebot.cascadebot.data.objects.Setting +import org.cascadebot.cascadebot.data.objects.SettingsContainer import java.util.concurrent.ConcurrentHashMap @SettingsContainer(module = Module.MANAGEMENT) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildSettingsMusic.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsMusic.kt similarity index 70% rename from src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildSettingsMusic.kt rename to src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsMusic.kt index 443c7be56..61902f744 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/GuildSettingsMusic.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/GuildSettingsMusic.kt @@ -1,6 +1,8 @@ -package org.cascadebot.cascadebot.data.objects +package org.cascadebot.cascadebot.data.objects.guild import org.cascadebot.cascadebot.commandmeta.Module +import org.cascadebot.cascadebot.data.objects.Setting +import org.cascadebot.cascadebot.data.objects.SettingsContainer import java.util.concurrent.ConcurrentHashMap @SettingsContainer(module = Module.MUSIC) diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/TodoList.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/TodoList.kt similarity index 76% rename from src/main/kotlin/org/cascadebot/cascadebot/data/objects/TodoList.kt rename to src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/TodoList.kt index 50fb79398..d9bc897c0 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/TodoList.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/guild/TodoList.kt @@ -1,4 +1,4 @@ -package org.cascadebot.cascadebot.data.objects +package org.cascadebot.cascadebot.data.objects.guild import net.dv8tion.jda.api.entities.Member import net.dv8tion.jda.api.entities.Message @@ -12,24 +12,22 @@ import org.cascadebot.cascadebot.messaging.Messaging.sendButtonedMessage import org.cascadebot.cascadebot.messaging.MessagingObjects import org.cascadebot.cascadebot.utils.buttons.PersistentButton import org.cascadebot.cascadebot.utils.buttons.PersistentButtonGroup -import java.util.ArrayList -class TodoList(ownerId: Long) { +class TodoList(var ownerId: Long) { - val items: MutableList = ArrayList() + val items: MutableList = mutableListOf() var messageId: Long = -1 var channelId: Long = -1 var currentItem = 0 - var ownerId: Long = 0 //List of users id who are able to access this list - private val users: MutableList = ArrayList() + private val users: MutableList = mutableListOf() private constructor() : this(0) { //Constructor for mongodb } - fun addTodoItem(text: String?): Int { + fun addTodoItem(text: String): Int { val item = TodoListItem(text) items.add(item) return items.indexOf(item) @@ -69,17 +67,14 @@ class TodoList(ownerId: Long) { fun edit(context: CommandContext) { if (messageId == -1L || channelId == -1L) return val originalChannel = context.guild.getTextChannelById(channelId) - if (originalChannel != null && originalChannel.idLong == channelId) { - val message = originalChannel.retrieveMessageById(messageId).complete() - if (message != null) { - message.editMessage(todoListMessage).queue() - doCheckToggle(message) + originalChannel?.let { + if (it.idLong == channelId) { + it.retrieveMessageById(messageId).complete()?.editMessage(todoListMessage)?.queue() } } } - fun send(context: CommandContext, channel: TextChannel?) { - requireNotNull(channel) { "The channel should exist :(" } + fun send(context: CommandContext, channel: TextChannel) { val buttonGroup = generateButtons(context.member.idLong, channel.idLong, context.guild.idLong) currentItem = 0 sendButtonedMessage(channel, todoListMessage, buttonGroup).thenAccept { @@ -89,16 +84,16 @@ class TodoList(ownerId: Long) { } private fun generateButtons(memberId: Long, channelId: Long, guildId: Long): PersistentButtonGroup { - val buttonGroup = PersistentButtonGroup(memberId, channelId, guildId) - buttonGroup.addPersistentButton(PersistentButton.TODO_BUTTON_NAVIGATE_LEFT) - buttonGroup.addPersistentButton(PersistentButton.TODO_BUTTON_NAVIGATE_UP) - buttonGroup.addPersistentButton(PersistentButton.TODO_BUTTON_NAVIGATE_DOWN) - buttonGroup.addPersistentButton(PersistentButton.TODO_BUTTON_NAVIGATE_RIGHT) - buttonGroup.addPersistentButton(PersistentButton.TODO_BUTTON_CHECK) - return buttonGroup + return PersistentButtonGroup(memberId, channelId, guildId).apply { + addPersistentButton(PersistentButton.TODO_BUTTON_NAVIGATE_LEFT) + addPersistentButton(PersistentButton.TODO_BUTTON_NAVIGATE_UP) + addPersistentButton(PersistentButton.TODO_BUTTON_NAVIGATE_DOWN) + addPersistentButton(PersistentButton.TODO_BUTTON_NAVIGATE_RIGHT) + addPersistentButton(PersistentButton.TODO_BUTTON_CHECK) + } } - fun addUncheckButton(message: Message?) { + fun addUncheckButton(message: Message) { val channel = CascadeBot.INS.client.getTextChannelById(channelId) if (channel != null) { val data = GuildDataManager.getGuildData(channel.guild.idLong) @@ -108,7 +103,7 @@ class TodoList(ownerId: Long) { } } - fun addCheckButton(message: Message?) { + fun addCheckButton(message: Message) { val channel = CascadeBot.INS.client.getTextChannelById(channelId) if (channel != null) { val data = GuildDataManager.getGuildData(channel.guild.idLong) @@ -118,7 +113,7 @@ class TodoList(ownerId: Long) { } } - fun doCheckToggle(message: Message?) { + fun doCheckToggle(message: Message) { val item = items[this.currentItem] if (item.done) { addUncheckButton(message) @@ -139,7 +134,7 @@ class TodoList(ownerId: Long) { if (i >= this.items.size) { break } - val item: TodoListItem = this.items.get(i) + val item: TodoListItem = this.items[i] if (i == pos) { pageBuilder.append(UnicodeConstants.SMALL_ORANGE_DIAMOND).append(" ") } else { diff --git a/src/main/kotlin/org/cascadebot/cascadebot/data/objects/user/CascadeUser.kt b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/user/CascadeUser.kt new file mode 100644 index 000000000..9783cb9f6 --- /dev/null +++ b/src/main/kotlin/org/cascadebot/cascadebot/data/objects/user/CascadeUser.kt @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2019 CascadeBot. All rights reserved. + * Licensed under the MIT license. + */ +package org.cascadebot.cascadebot.data.objects.user + +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import de.bild.codec.annotations.Id +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import org.cascadebot.cascadebot.CascadeBot +import org.cascadebot.cascadebot.data.Config +import org.cascadebot.cascadebot.data.objects.donation.Flag +import org.cascadebot.cascadebot.data.objects.donation.Tier + +class CascadeUser(@field:Id val userId: Long) { + + private constructor() : this(0L) + + val tierName = "default" + val tier: Tier + get() = Tier.getTier(tierName)!! + + val blackList: MutableList = mutableListOf(); + val flags: MutableList = mutableListOf(); + + fun update(): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/user/" + userId + "/update") + .method("POST", null) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + // Ignore for now + false + } + } + + //region User Flags + fun addFlag(flag: Flag): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val jsonObject = JsonObject() + val addFlags = JsonArray() + addFlags.add(flag.id) + jsonObject.add("add", addFlags) + val requestBody = CascadeBot.getGSON().toJson(jsonObject).toRequestBody() + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/user/" + userId + "/flags") + .method("PATCH", requestBody) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + flags.add(flag) + } + } + + fun removeFlag(flag: Flag): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val jsonObject = JsonObject() + val removeFlags = JsonArray() + removeFlags.add(flag.id) + jsonObject.add("remove", removeFlags) + val requestBody = CascadeBot.getGSON().toJson(jsonObject).toRequestBody() + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/user/" + userId + "/flags") + .method("PATCH", requestBody) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + flags.remove(flag) + } + } + + fun addFlags(flags: List): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val jsonObject = JsonObject() + val addFlags = CascadeBot.getGSON().toJsonTree(flags); + jsonObject.add("add", addFlags) + val requestBody = CascadeBot.getGSON().toJson(jsonObject).toRequestBody() + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/user/" + userId + "/flags") + .method("PATCH", requestBody) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + this.flags.addAll(flags) + } + } + + fun removeFlags(flags: List): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val jsonObject = JsonObject() + val removeFlags = CascadeBot.getGSON().toJsonTree(flags); + jsonObject.add("remove", removeFlags) + val requestBody = CascadeBot.getGSON().toJson(jsonObject).toRequestBody() + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/user/" + userId + "/flags") + .method("PATCH", requestBody) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + this.flags.addAll(flags) + } + } + + fun clearFlags(): Boolean { + return if (Config.INS.patreonServiceUrl != null) { + val jsonObject = JsonObject() + jsonObject.add("clear", JsonPrimitive(true)) + val requestBody = CascadeBot.getGSON().toJson(jsonObject).toRequestBody() + val request = Request.Builder() + .url(Config.INS.patreonServiceUrl + "/user/" + userId + "/flags") + .method("PATCH", requestBody) + .addHeader("Authorization", "Bearer " + Config.INS.patreonServiceKey) + .build() + val response = CascadeBot.INS.httpClient.newCall(request).execute() + response.code == 200 + } else { + flags.clear(); + true + } + } + //endregion + +} \ No newline at end of file diff --git a/src/main/kotlin/org/cascadebot/cascadebot/music/MusicHandler.kt b/src/main/kotlin/org/cascadebot/cascadebot/music/MusicHandler.kt index 5f86c7dc3..d4c3e2c9f 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/music/MusicHandler.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/music/MusicHandler.kt @@ -23,8 +23,6 @@ import org.apache.http.client.config.RequestConfig import org.cascadebot.cascadebot.CascadeBot import org.cascadebot.cascadebot.data.Config import org.cascadebot.cascadebot.data.language.Language -import org.cascadebot.cascadebot.data.managers.GuildDataManager -import org.cascadebot.cascadebot.data.objects.Flag import org.cascadebot.cascadebot.data.objects.SearchResultType import org.cascadebot.cascadebot.events.PlayerListener import org.cascadebot.cascadebot.messaging.MessageType @@ -107,7 +105,7 @@ class MusicHandler { fun purgeDisconnectedPlayers() { // Removes all players that are not connected to a channel unless they have supported us on Patreon - players.entries.removeIf { it.value.connectedChannel == null && !GuildDataManager.getGuildData(it.key).isFlagEnabled(Flag.MUSIC_SERVICES) } + //players.entries.removeIf { it.value.connectedChannel == null && !GuildDataManager.getGuildData(it.key).isFlagEnabled(Flag.MUSIC_SERVICES) } } /** diff --git a/src/main/kotlin/org/cascadebot/cascadebot/utils/buttons/Button.kt b/src/main/kotlin/org/cascadebot/cascadebot/utils/buttons/Button.kt index d8eec5fc4..8f87689b1 100644 --- a/src/main/kotlin/org/cascadebot/cascadebot/utils/buttons/Button.kt +++ b/src/main/kotlin/org/cascadebot/cascadebot/utils/buttons/Button.kt @@ -2,7 +2,6 @@ package org.cascadebot.cascadebot.utils.buttons import net.dv8tion.jda.api.entities.Message import org.cascadebot.cascadebot.CascadeBot -import java.util.function.Consumer abstract class Button private constructor(var runnable: IButtonRunnable) { abstract fun addReaction(message: Message) diff --git a/src/main/resources/default_tiers.json b/src/main/resources/default_tiers.json new file mode 100644 index 000000000..6812c7890 --- /dev/null +++ b/src/main/resources/default_tiers.json @@ -0,0 +1,186 @@ +{ + "default": { + "flags": [ + { + "name": "custom_commands", + "type": "amount", + "scope": "guild", + "data": { + "amount": 3 + } + }, + { + "name": "prefix_length", + "type": "amount", + "scope": "guild", + "data": { + "amount": 5 + } + }, + { + "name": "dashboard_modlog_time", + "type": "time", + "scope": "guild", + "data": { + "time": 604800000 + } + } + ] + }, + "boost": { + "flags": [ + { + "name": "beta", + "scope": "guild" + }, + { + "name": "boost_badge", + "scope": "user" + } + ], + "parent": "default" + }, + "cheap": { + "extras": [ + { + "path": "tiers.extra.supporter_role", + "scope": "user" + }, + { + "path": "tiers.extra.primary_support", + "scope": "user" + } + ], + "flags": [ + { + "name": "custom_commands", + "type": "amount", + "scope": "guild", + "data": { + "amount": 10 + } + }, + { + "name": "dashboard_modlog_time", + "type": "time", + "scope": "guild", + "data": { + "time": 1209600000 + } + }, + { + "name": "supporter_badge", + "scope": "user" + }, + { + "name": "more_background", + "scope": "user" + }, + { + "name": "custom_footer", + "scope": "guild" + }, + { + "name": "beta", + "scope": "guild" + } + ], + "parent": "default" + }, + "medium": { + "flags": [ + { + "name": "custom_commands", + "type": "amount", + "scope": "guild", + "data": { + "amount": 20 + } + }, + { + "name": "prefix_length", + "type": "amount", + "scope": "guild", + "data": { + "amount": 1900 + } + }, + { + "name": "dashboard_modlog_time", + "type": "time", + "scope": "guild", + "data": { + "time": 2592000000 + } + }, + { + "name": "music_services", + "scope": "guild" + }, + { + "name": "music_controls", + "scope": "guild" + }, + { + "name": "music_spotify", + "scope": "user" + }, + { + "name": "music_donator_node", + "scope": "guild" + }, + { + "name": "music_stay", + "scope": "guild" + }, + { + "name": "custom_custom_backgrounds", + "scope": "user" + }, + { + "name": "planner_agenda", + "scope": "guild" + }, + { + "name": "medium_badge", + "scope": "user" + } + ], + "parent": "cheap" + }, + "hardcode": { + "flags": [ + { + "name": "custom_commands", + "type": "amount", + "scope": "guild", + "data": { + "amount": 50 + } + }, + { + "name": "dashboard_modlog_time", + "type": "time", + "scope": "guild", + "data": { + "time": 15768000000 + } + }, + { + "name": "cascade_hosting", + "scope": "user" + }, + { + "name": "hardcode_badge", + "scope": "user" + } + ], + "extras": [ + { + "path": "tiers.extra.tshirt", + "scope": "user" + } + ], + "parent": "medium" + } +} diff --git a/src/main/resources/lang/en-GB.json b/src/main/resources/lang/en-GB.json index 7c98de6e8..b51392d99 100644 --- a/src/main/resources/lang/en-GB.json +++ b/src/main/resources/lang/en-GB.json @@ -1,5 +1,17 @@ { + "command_meta": { + "donate": "This command is a donator-only feature.\nPlease consider donating to Cascade over on [Patreon](https://www.patreon.com/cascadebot/).\nTo find out more run `{0}donate`." + }, "commands": { + "donate": { + "command": "donate", + "description": "Provides information for donating to Cascade.", + "embed_title": "Donate to Cascade!", + "embed_description": "Thanks for your interest in donating to Cascade! Us developers work hard to ensure that you receive the best content, however we could do with a coffee every once in a while! Please find information below for donating.", + "embed_patreon": "When donating via Patreon, you will automatically receive perks for your bot, including music services! Donating via Patreon is a monthly donation. You can find our Patreon page here: **https://www.patreon.com/cascadebot/creators**", + "embed_paypal": "If you don't feel like donating monthly to support the bot, you can always donate via PayPal. Although you won't automatically receive perks, you can join our Support Discord server with proof of donation, and we can certainly sort things out for you. Our PayPal email is: **cascadediscordbot@gmail.com**", + "embed_footer": "Thanks for your interest in donating!" + }, "invite": { "command": "invite", "description": "Returns the bot invite link, to invite the bot to other Discord guilds." @@ -1124,6 +1136,20 @@ "description": "Lists all flags." } }, + "tiers": { + "names": { + "default": "Default", + "cheap": "Cheep", + "medium": "Medium", + "hardcode": "Hardcode", + "boost": "Guild booster" + }, + "extra": { + "supporter_role": "'Supporter' Role in discord", + "primary_support": "Access to primary support channel", + "tshirt": "If donation is keep up for 6 months we'll send you a donator only t-shirt!" + } + }, "utils": { "permission_command": { "no_group_found": "No group found with name or id `{0}`!", @@ -1293,5 +1319,75 @@ "yellowgreen": "Yellowgreen" } } + }, + "flags": { + "custom_commands": { + "name": "Custom commands", + "description": "Gives {0} custom commands." + }, + "prefix_length": { + "name": "Prefix length", + "description": "Increases the prefix length to {0} chars." + }, + "dashboard_modlog_time": { + "name": "Dashboard modlog persistence", + "description": "Modlog items will persist on the dashboard for {0}" + }, + "supporter_badge": { + "name": "Supporter badge", + "description": "A badge on your Cascade profile showing that you support Cascade." + }, + "more_backgrounds": { + "name": "More profile backgrounds", + "description": "You'll unlock more background you can use for your Cascade profile." + }, + "custom_footer": { + "name": "Custom footer", + "description": "You can set up a custom footer that will appear on all messages from the bot." + }, + "beta": { + "name": "Beta features", + "description": "Access to upcoming bot features early" + }, + "music_services": { + "name": "Music services", + "description": "You can now play music from mixer, bandcamp, twich, soundcloud" + }, + "music_controls": { + "name": "Extended music controls", + "description": "You'll get access to more controls for music like volume" + }, + "music_spotify": { + "name": "Spotify to youtube", + "description": "Due to spotify terms of service we can't play directly from spotify, but with this we'll do our best to convert your spotify playlists to youtube." + }, + "music_donator_node": { + "name": "Donator audio node", + "description": "Access to donator only audio nodes for smoother audio." + }, + "custom_backgrounds": { + "name": "Custom profile background", + "description": "You can upload a custom background to be used for your Cascade profile" + }, + "planner_agenda": { + "name": "Meeting planer agendas", + "description": "You can attach a todo list to a meeting via the meeting planer to be sent automatically to a specified channel when the meeting starts." + }, + "medium_badge": { + "name": "Medium supporter badge", + "description": "A badge on your Cascade profile showing that you support Cascade." + }, + "cascade_hosting": { + "name": "Cascade hosting", + "description": "We'll host CascadeBot on your token so you can have custom branding" + }, + "hardcode_badge": { + "name": "Hardcode supporter badge", + "description": "A badge on your Cascade profile showing that you support Cascade." + }, + "boost_badge": { + "name": "Guild booster badge", + "description": "A badge on your Cascade profile showing that you boosted the Cascade guild." + } } }