diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 403bc6a..fd298ec 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -12,7 +12,7 @@ jobs: - name: 'Set up JDK' uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'temurin' cache: 'gradle' diff --git a/.github/workflows/deploy-prod.yaml b/.github/workflows/deploy-prod.yaml index 1d83bd1..6d54336 100644 --- a/.github/workflows/deploy-prod.yaml +++ b/.github/workflows/deploy-prod.yaml @@ -69,4 +69,4 @@ jobs: key: ${{ secrets.VM_SSH_PRIVATE_KEY }} script: | cd /home/${{ secrets.SSH_USERNAME }}/capivara - DISCORD_TOKEN='${{ secrets.DISCORD_BOT_TOKEN }}' LOG_CHANNEL_ID='${{ secrets.DISCORD_LOG_CHANNEL_ID }}' CURUPIRA_RESET='true' DATABASE_DRIVER='org.postgresql.Driver' DATABASE_DIALECT='org.hibernate.dialect.PostgreSQL95Dialect' DATABASE_URL='jdbc:postgresql://host.containers.internal:5432/capivara' DATABASE_USERNAME='${{ secrets.DATABASE_USERNAME }}' DATABASE_PASSWORD='${{ secrets.DATABASE_PASSWORD }}' JAVA_ARGS='-Xmx250M' /bin/bash start-container.sh docker.io/eduardoferro/capivara:${{ github.sha }} + DISCORD_TOKEN='${{ secrets.DISCORD_BOT_TOKEN }}' LOG_CHANNEL_ID='${{ secrets.DISCORD_LOG_CHANNEL_ID }}' CURUPIRA_RESET='true' DATABASE_DRIVER='org.postgresql.Driver' DATABASE_DIALECT='org.hibernate.dialect.PostgreSQL95Dialect' DATABASE_URL='jdbc:postgresql://host.containers.internal:5432/capivara' DATABASE_USERNAME='${{ secrets.DATABASE_USERNAME }}' DATABASE_PASSWORD='${{ secrets.DATABASE_PASSWORD }}' JAVA_ARGS='-Xmx350M' /bin/bash start-container.sh docker.io/eduardoferro/capivara:${{ github.sha }} diff --git a/Dockerfile b/Dockerfile index 88ccc36..82b4c72 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/eclipse-temurin:17-jdk-alpine as builder +FROM docker.io/eclipse-temurin:21-jdk-alpine as builder WORKDIR /app ADD . /tmp @@ -11,12 +11,12 @@ RUN cd /tmp && \ mv build/libs/CapivaraBot.jar /app && \ rm -rf /tmp/* -FROM docker.io/eclipse-temurin:17-jre-alpine +FROM docker.io/eclipse-temurin:21-jre-alpine WORKDIR /app COPY --from=builder /app . -ENV JAVA_ARGS="-Xmx300M" +ENV JAVA_ARGS="-Xmx350M" ENV LOG_DIRECTORY="/app/logs" ENV SPRING_CONFIG_LOCATION="/app/main.properties" ENV DISCORD_TOKEN="invalid" diff --git a/build.gradle b/build.gradle index 22306e8..2276a29 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' id 'application' - id 'org.springframework.boot' version '2.7.0' + id 'org.springframework.boot' version '2.7.18' id 'com.github.johnrengelman.shadow' version '8.1.1' } @@ -24,7 +24,7 @@ springBoot { dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - implementation ('org.springframework.boot:spring-boot-starter-data-jpa:2.7.0') { + implementation ('org.springframework.boot:spring-boot-starter-data-jpa:2.7.18') { exclude module: 'spring-boot-starter-logging' } implementation 'org.springframework.boot:spring-boot-starter-log4j2:2.7.0' @@ -33,12 +33,13 @@ dependencies { implementation 'com.h2database:h2:2.1.212' implementation 'org.postgresql:postgresql:42.3.6' - implementation("net.dv8tion:JDA:5.0.0-beta.16") { + implementation("net.dv8tion:JDA:5.1.0") { exclude module: 'opus-java' } - implementation("com.github.Softawii:curupira:v0.3.0") - implementation("com.github.Softawii:curupira:v0.3.0:all") + implementation("com.github.Softawii:curupira:v1.0.0") { + changing = true + } } tasks.register('deploy') { @@ -65,5 +66,5 @@ test { useJUnitPlatform() } -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 +sourceCompatibility = JavaVersion.VERSION_21 +targetCompatibility = JavaVersion.VERSION_21 diff --git a/src/main/java/com/softawii/capivara/Main.java b/src/main/java/com/softawii/capivara/Main.java index 33feb53..8d9c38a 100644 --- a/src/main/java/com/softawii/capivara/Main.java +++ b/src/main/java/com/softawii/capivara/Main.java @@ -8,6 +8,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.info.BuildProperties; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.stereotype.Component; @SpringBootApplication public class Main { diff --git a/src/main/java/com/softawii/capivara/config/SpringConfig.java b/src/main/java/com/softawii/capivara/config/SpringConfig.java index 615a752..b63ae41 100644 --- a/src/main/java/com/softawii/capivara/config/SpringConfig.java +++ b/src/main/java/com/softawii/capivara/config/SpringConfig.java @@ -1,7 +1,8 @@ package com.softawii.capivara.config; -import com.softawii.capivara.utils.CapivaraExceptionHandler; -import com.softawii.curupira.core.Curupira; +import com.softawii.capivara.controller.MainExceptionController; +import com.softawii.curupira.v2.core.CurupiraBoot; +import com.softawii.curupira.v2.integration.ContextProvider; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.requests.GatewayIntent; @@ -9,7 +10,6 @@ import net.dv8tion.jda.api.utils.cache.CacheFlag; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -52,7 +52,8 @@ public LocalContainerEntityManagerFactoryBean entityManagerFactory() { em.setPackagesToScan("com.softawii.capivara.entity", "com.softawii.capivara.repository", "com.softawii.capivara.services", - "com.softawii.capivara.listeners.events"); + "com.softawii.capivara.events", + "com.softawii.capivara.controller"); JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); @@ -85,7 +86,7 @@ public JDA jda() { } @Bean - public CapivaraExceptionHandler capivaraExceptionHandler() { + public MainExceptionController capivaraExceptionHandler() { String logChannelId = env.getProperty("log.channel.id"); String logDirectory = env.getProperty("log_directory"); if (logChannelId != null) { @@ -93,23 +94,22 @@ public CapivaraExceptionHandler capivaraExceptionHandler() { if (logDirectory != null) { logPath = Path.of(logDirectory); } - return new CapivaraExceptionHandler(logChannelId, logPath); + return new MainExceptionController(logChannelId, logPath); } return null; } @Bean - public Curupira curupira(JDA jda, @Autowired(required = false) CapivaraExceptionHandler exceptionHandler) { - String pkg = "com.softawii.capivara.listeners"; + public CurupiraBoot curupira(JDA jda, ContextProvider context) { + String pkg = "com.softawii.capivara.controller"; String resetEnv = env.getProperty("curupira.reset", "false"); boolean reset = Boolean.parseBoolean(resetEnv); LOGGER.info("curupira.reset: " + reset); - return new Curupira(jda, reset, exceptionHandler, pkg); + return new CurupiraBoot(jda, context, reset, pkg); } - Properties additionalProperties() { Properties properties = new Properties(); properties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); diff --git a/src/main/java/com/softawii/capivara/config/SpringContextProvider.java b/src/main/java/com/softawii/capivara/config/SpringContextProvider.java new file mode 100644 index 0000000..bda287c --- /dev/null +++ b/src/main/java/com/softawii/capivara/config/SpringContextProvider.java @@ -0,0 +1,20 @@ +package com.softawii.capivara.config; + +import com.softawii.curupira.v2.integration.ContextProvider; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +@Component +public class SpringContextProvider implements ContextProvider { + + private final ApplicationContext context; + + public SpringContextProvider(ApplicationContext context) { + this.context = context; + } + + @Override + public T getInstance(Class aClass) { + return context.getBean(aClass); + } +} diff --git a/src/main/java/com/softawii/capivara/utils/CapivaraExceptionHandler.java b/src/main/java/com/softawii/capivara/controller/MainExceptionController.java similarity index 87% rename from src/main/java/com/softawii/capivara/utils/CapivaraExceptionHandler.java rename to src/main/java/com/softawii/capivara/controller/MainExceptionController.java index 422c592..9654e40 100644 --- a/src/main/java/com/softawii/capivara/utils/CapivaraExceptionHandler.java +++ b/src/main/java/com/softawii/capivara/controller/MainExceptionController.java @@ -1,8 +1,8 @@ -package com.softawii.capivara.utils; +package com.softawii.capivara.controller; -import com.softawii.curupira.core.ExceptionHandler; -import com.softawii.curupira.exceptions.InvalidChannelTypeException; -import com.softawii.curupira.exceptions.MissingPermissionsException; + +import com.softawii.curupira.v2.annotations.DiscordException; +import com.softawii.curupira.v2.annotations.DiscordExceptions; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.MessageEmbed; @@ -10,12 +10,12 @@ import net.dv8tion.jda.api.events.Event; import net.dv8tion.jda.api.events.channel.GenericChannelEvent; import net.dv8tion.jda.api.events.guild.GenericGuildEvent; -import net.dv8tion.jda.api.events.interaction.command.GenericCommandInteractionEvent; import net.dv8tion.jda.api.interactions.Interaction; import net.dv8tion.jda.api.requests.restaction.MessageCreateAction; import net.dv8tion.jda.api.utils.FileUpload; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.springframework.stereotype.Component; import java.awt.*; import java.io.IOException; @@ -29,30 +29,20 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; -public class CapivaraExceptionHandler implements ExceptionHandler { +@DiscordExceptions +public class MainExceptionController { - private final Logger LOGGER = LogManager.getLogger(CapivaraExceptionHandler.class); + private final Logger LOGGER = LogManager.getLogger(MainExceptionController.class); private String channelId; private Path logDirectory; - public CapivaraExceptionHandler(String channelId, Path logDirectory) { + public MainExceptionController(String channelId, Path logDirectory) { this.channelId = channelId; this.logDirectory = logDirectory; } - @Override + @DiscordException(Throwable.class) public void handle(Throwable throwable, Interaction interaction) { - if (interaction instanceof GenericCommandInteractionEvent event) { - if (throwable instanceof MissingPermissionsException) { - event.reply("You don't have permission to execute this command!").setEphemeral(true).queue(); - return; - } - else if(throwable instanceof InvalidChannelTypeException) { - event.reply("You can't execute this command in this channel!").setEphemeral(true).queue(); - return; - } - } - InputStream logFileBytes = null; if (logDirectory != null) { Path logFile = logDirectory.resolve("capivara.log"); diff --git a/src/main/java/com/softawii/capivara/controller/SocialExceptionController.java b/src/main/java/com/softawii/capivara/controller/SocialExceptionController.java new file mode 100644 index 0000000..c050eaf --- /dev/null +++ b/src/main/java/com/softawii/capivara/controller/SocialExceptionController.java @@ -0,0 +1,38 @@ +package com.softawii.capivara.controller; + +import com.softawii.capivara.exceptions.MissingPermissionsException; +import com.softawii.curupira.v2.annotations.DiscordException; +import com.softawii.curupira.v2.annotations.DiscordExceptions; +import com.softawii.curupira.v2.annotations.LocaleType; +import com.softawii.curupira.v2.localization.LocalizationManager; +import net.dv8tion.jda.api.interactions.DiscordLocale; +import net.dv8tion.jda.api.interactions.Interaction; +import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; +import org.springframework.stereotype.Component; + +@Component +@DiscordExceptions(classes = SocialTwitterGroup.class) +public class SocialExceptionController { + + private final MainExceptionController mainExceptionController; + + public SocialExceptionController(MainExceptionController mainExceptionController) { + this.mainExceptionController = mainExceptionController; + } + + @DiscordException(MissingPermissionsException.class) + public void missingPermissions(Throwable throwable, Interaction interaction, LocalizationManager localization, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localization.getLocalizedString("social.error.missing_permissions", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(Throwable.class) + public void generic(Throwable throwable, Interaction interaction, LocalizationManager localization, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localization.getLocalizedString("social.error.generic", locale)).setEphemeral(true).queue(); + } + + this.mainExceptionController.handle(throwable, interaction); + } +} diff --git a/src/main/java/com/softawii/capivara/controller/SocialTwitterGroup.java b/src/main/java/com/softawii/capivara/controller/SocialTwitterGroup.java new file mode 100644 index 0000000..f1ce515 --- /dev/null +++ b/src/main/java/com/softawii/capivara/controller/SocialTwitterGroup.java @@ -0,0 +1,62 @@ +package com.softawii.capivara.controller; + +import com.softawii.capivara.exceptions.MissingPermissionsException; +import com.softawii.capivara.services.TwitterParserConfigService; +import com.softawii.curupira.v2.annotations.DiscordController; +import com.softawii.curupira.v2.annotations.RequestInfo; +import com.softawii.curupira.v2.annotations.commands.DiscordCommand; +import com.softawii.curupira.v2.annotations.interactions.DiscordButton; +import com.softawii.curupira.v2.api.TextLocaleResponse; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.interactions.DiscordLocale; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import org.springframework.stereotype.Component; + +@Component +@DiscordController(parent = "social", value = "twitter", description = "Twitter Controller", permissions = Permission.ADMINISTRATOR, + resource = "social", locales = DiscordLocale.PORTUGUESE_BRAZILIAN) +public class SocialTwitterGroup { + public static final String deleteBotTwitterMessage = "twitter-bot-message-delete"; + private final TwitterParserConfigService service; + + public SocialTwitterGroup(TwitterParserConfigService service) { + this.service = service; + } + + public static Button generateDeleteButton(long authorId) { + return Button.danger(String.format("%s:%s", deleteBotTwitterMessage, authorId), "Apagar"); + } + + @DiscordCommand(name = "enable", description = "Enable the automatic Twitter link transformation service") + public TextLocaleResponse enable(Guild guild) { + service.enable(guild.getIdLong()); + return new TextLocaleResponse("social.twitter.enable.response", guild.getName()); + } + + @DiscordCommand(name = "disable", description = "Disable the automatic Twitter link transformation service") + public TextLocaleResponse disable(Guild guild) { + service.disable(guild.getIdLong()); + return new TextLocaleResponse("social.twitter.disable.response", guild.getName()); + } + + @DiscordButton(name = deleteBotTwitterMessage, ephemeral = true) + public TextLocaleResponse delete(ButtonInteractionEvent event, @RequestInfo Member member) throws MissingPermissionsException { + // Format: ButtonID:Owner + String ownerId = event.getComponentId().split(":")[1]; + String messageOwner = member.getId(); + + MessageChannelUnion channel = event.getChannel(); + + if (!messageOwner.equals(ownerId)) { + throw new MissingPermissionsException(); + } + + channel.deleteMessageById(event.getMessageId()).queue(); + return new TextLocaleResponse("twitter.delete.response"); + } + +} diff --git a/src/main/java/com/softawii/capivara/controller/VoiceAgentController.java b/src/main/java/com/softawii/capivara/controller/VoiceAgentController.java new file mode 100644 index 0000000..231c1a8 --- /dev/null +++ b/src/main/java/com/softawii/capivara/controller/VoiceAgentController.java @@ -0,0 +1,72 @@ +package com.softawii.capivara.controller; + +import com.softawii.capivara.core.DroneManager; +import com.softawii.capivara.exceptions.KeyNotFoundException; +import com.softawii.capivara.exceptions.MissingPermissionsException; +import com.softawii.capivara.exceptions.NotInTheDroneException; +import com.softawii.curupira.v2.annotations.DiscordController; +import com.softawii.curupira.v2.annotations.RequestInfo; +import com.softawii.curupira.v2.annotations.commands.DiscordCommand; +import com.softawii.curupira.v2.annotations.commands.DiscordParameter; +import com.softawii.curupira.v2.api.TextLocaleResponse; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; +import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel; +import net.dv8tion.jda.api.interactions.DiscordLocale; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; + +@Component +@DiscordController(value = "agent", description = "Voice Agent Controller", resource = "voice", locales = DiscordLocale.PORTUGUESE_BRAZILIAN) +public class VoiceAgentController { + private final DroneManager droneManager; + public static final long inviteDeadline = 1000L * 10L * 60L; + + public VoiceAgentController(DroneManager droneManager) { + this.droneManager = droneManager; + } + + private VoiceChannel validateMember(Member member) throws KeyNotFoundException, MissingPermissionsException, NotInTheDroneException { + if(!member.getVoiceState().inAudioChannel()) throw new NotInTheDroneException(); + + VoiceChannel channel = member.getVoiceState().getChannel().asVoiceChannel(); + + if(!droneManager.canInteract(channel, member)) throw new MissingPermissionsException(); + + return channel; + } + + @DiscordCommand(name = "invite", description = "Invite a user to join in a channel", ephemeral = true) + public TextLocaleResponse invite(@RequestInfo Member member, @DiscordParameter(name = "name", description = "User to invite") Member invited) throws NotInTheDroneException, MissingPermissionsException, KeyNotFoundException { + VoiceChannel channel = validateMember(member); + channel.createInvite().setUnique(true).deadline(System.currentTimeMillis() + inviteDeadline).queue(q -> { + channel.getManager().putPermissionOverride(invited, List.of(Permission.VIEW_CHANNEL, Permission.VOICE_CONNECT), Collections.emptyList()).queue(); + String name = member.getEffectiveName() + (member.getNickname() != null ? " (" + member.getNickname() + ")" : ""); + invited.getUser().openPrivateChannel().queue(chn -> chn.sendMessage(name + "invited you to join in a channel!\n" + q.getUrl()).queue()); + }); + + return new TextLocaleResponse("agent.invite.response", invited.getEffectiveName()); + } + + @DiscordCommand(name = "kick", description = "Kick a user from a channel", ephemeral = true) + public TextLocaleResponse kick(Guild guild, @RequestInfo Member member, @DiscordParameter(name = "name", description = "User to kick") Member kicked) throws NotInTheDroneException, MissingPermissionsException, KeyNotFoundException { + VoiceChannel channel = validateMember(member); + channel.getManager().putPermissionOverride(kicked, Collections.emptyList(), List.of(Permission.VIEW_CHANNEL, Permission.VOICE_CONNECT)).queue(); + + if (kicked.getVoiceState().getChannel() != null) { + AudioChannel to_kick_channel = kicked.getVoiceState().getChannel(); + if (to_kick_channel.getIdLong() == channel.getIdLong()) { + guild.moveVoiceMember(kicked, null).queue(); + return new TextLocaleResponse("agent.kick.response", kicked.getEffectiveName()); + } else { + return new TextLocaleResponse("agent.error.not_in_your_channel", kicked.getEffectiveName()); + } + } else { + return new TextLocaleResponse("agent.error.not_in_channel", kicked.getEffectiveName()); + } + } +} diff --git a/src/main/java/com/softawii/capivara/controller/VoiceExceptionController.java b/src/main/java/com/softawii/capivara/controller/VoiceExceptionController.java new file mode 100644 index 0000000..4c72a18 --- /dev/null +++ b/src/main/java/com/softawii/capivara/controller/VoiceExceptionController.java @@ -0,0 +1,105 @@ +package com.softawii.capivara.controller; + +import com.softawii.capivara.exceptions.*; +import com.softawii.curupira.v2.annotations.DiscordException; +import com.softawii.curupira.v2.annotations.DiscordExceptions; +import com.softawii.curupira.v2.annotations.LocaleType; +import com.softawii.curupira.v2.api.exception.CommandNotFoundException; +import com.softawii.curupira.v2.localization.LocalizationManager; +import net.dv8tion.jda.api.interactions.DiscordLocale; +import net.dv8tion.jda.api.interactions.Interaction; +import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; +import org.springframework.stereotype.Component; + +import java.security.Key; + +@Component +@DiscordExceptions(classes = {VoiceAgentController.class, VoiceMasterController.class}) +public class VoiceExceptionController { + + private final MainExceptionController mainExceptionController; + + public VoiceExceptionController(MainExceptionController mainExceptionController) { + this.mainExceptionController = mainExceptionController; + } + + @DiscordException(MissingPermissionsException.class) + public void missingPermissionsException(Throwable exception, Interaction interaction, LocalizationManager localizationManager, @LocaleType DiscordLocale locale) { + if(interaction instanceof IReplyCallback callback) { + callback.reply(localizationManager.getLocalizedString("voice.error.missing_permissions", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(CommandNotFoundException.class) + public void commandNotFoundException(Throwable exception, Interaction interaction, LocalizationManager localizationManager, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localizationManager.getLocalizedString("voice.error.command_not_found", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(ExistingDynamicCategoryException.class) + public void existingDynamicCategoryException(Throwable exception, Interaction interaction, LocalizationManager localizationManager, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localizationManager.getLocalizedString("voice.error.existing_dynamic_category", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(InvalidChannelTypeException.class) + public void invalidChannelTypeException(Throwable exception, Interaction interaction, LocalizationManager localizationManager, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localizationManager.getLocalizedString("voice.error.invalid_channel_type", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(FieldLengthException.class) + public void fieldLengthException(Throwable exception, Interaction interaction, LocalizationManager localizationManager, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localizationManager.getLocalizedString("voice.error.field_length", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(InvalidInputException.class) + public void invalidInputException(Throwable exception, Interaction interaction, LocalizationManager localizationManager, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localizationManager.getLocalizedString("voice.error.invalid_input", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(KeyNotFoundException.class) + public void keyNotFoundException(Throwable exception, Interaction interaction, LocalizationManager localizationManager, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localizationManager.getLocalizedString("voice.error.key_not_found", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(NotInTheDroneException.class) + public void notInTheDroneException(Throwable exception, Interaction interaction, LocalizationManager localizationManager, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localizationManager.getLocalizedString("voice.error.not_in_the_drone", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(OwnerInTheChannelException.class) + public void ownerInTheChannelException(Throwable exception, Interaction interaction, LocalizationManager localizationManager, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localizationManager.getLocalizedString("voice.error.owner_in_the_channel", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(UrlException.class) + public void urlException(Throwable exception, Interaction interaction, LocalizationManager localizationManager, @LocaleType DiscordLocale locale) { + if (interaction instanceof IReplyCallback callback) { + callback.reply(localizationManager.getLocalizedString("voice.error.url_not_found", locale)).setEphemeral(true).queue(); + } + } + + @DiscordException(Throwable.class) + public void throwable(Throwable throwable, Interaction interaction, LocalizationManager localization, @LocaleType DiscordLocale locale) { + if(interaction instanceof IReplyCallback callback) { + callback.reply(localization.getLocalizedString("voice.error.generic", locale)).setEphemeral(true).queue(); + } + + mainExceptionController.handle(throwable, interaction); + } + +} diff --git a/src/main/java/com/softawii/capivara/controller/VoiceMasterController.java b/src/main/java/com/softawii/capivara/controller/VoiceMasterController.java new file mode 100644 index 0000000..e9e7ea9 --- /dev/null +++ b/src/main/java/com/softawii/capivara/controller/VoiceMasterController.java @@ -0,0 +1,242 @@ +package com.softawii.capivara.controller; + +import com.softawii.capivara.core.DroneManager; +import com.softawii.capivara.core.VoiceManager; +import com.softawii.capivara.entity.VoiceHive; +import com.softawii.capivara.exceptions.*; +import com.softawii.capivara.utils.Utils; +import com.softawii.curupira.v2.annotations.DiscordController; +import com.softawii.curupira.v2.annotations.LocaleType; +import com.softawii.curupira.v2.annotations.RequestInfo; +import com.softawii.curupira.v2.annotations.commands.DiscordCommand; +import com.softawii.curupira.v2.annotations.commands.DiscordParameter; +import com.softawii.curupira.v2.annotations.interactions.DiscordButton; +import com.softawii.curupira.v2.annotations.interactions.DiscordModal; +import com.softawii.curupira.v2.api.TextLocaleResponse; +import com.softawii.curupira.v2.localization.LocalizationManager; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.entities.channel.concrete.Category; +import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; +import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; +import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion; +import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.interactions.DiscordLocale; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import net.dv8tion.jda.api.interactions.modals.Modal; +import org.springframework.stereotype.Component; + +import java.awt.*; +import java.util.List; + +@Component +@DiscordController(parent = "voice", value = "master", description = "Voice Controller", permissions = Permission.ADMINISTRATOR, resource = "voice", locales = DiscordLocale.PORTUGUESE_BRAZILIAN) +public class VoiceMasterController { + + public static final String configModal = "voice-dynamic-config-modal"; + public static final String generateConfigModal = "voice-dynamic-generate-config-modal"; + public static final String droneConfigButton = "voice-dynamic-drone-config-button"; + public static final String droneConfigModal = "voice-dynamic-drone-config-modal"; + public static final String droneHideShow = "voice-dynamic-drone-hide-show"; + public static final String dronePublicPrivate = "voice-dynamic-drone-public-private"; + public static final String dronePermTemp = "voice-dynamic-drone-permanent-temporary"; + public static final String droneClaim = "voice-dynamic-drone-claim"; + + private final VoiceManager voiceManager; + private final DroneManager droneManager; + + public VoiceMasterController(VoiceManager voiceManager, DroneManager droneManager) { + this.voiceManager = voiceManager; + this.droneManager = droneManager; + } + + @DiscordCommand(name = "set", description = "set a category for dynamic voice channels") + public void set( + SlashCommandInteractionEvent event, Guild guild, LocalizationManager localization, + @LocaleType DiscordLocale locale, @DiscordParameter(name = "category", description = "Category to add dynamic channel") GuildChannelUnion channel + ) throws ExistingDynamicCategoryException, InvalidChannelTypeException { + + if(channel.getType() != ChannelType.CATEGORY) { + throw new InvalidChannelTypeException(); + } + + Category category = channel.asCategory(); + VoiceHive hive = this.voiceManager.setDynamicCategory(category); + VoiceChannel hiveChannel = guild.getVoiceChannelById(hive.getVoiceId()); + + // Getting callback texts + String title = localization.getLocalizedString("voice.master.set.success.title", locale); + String description = localization.getLocalizedString("voice.master.set.success.description", locale, hiveChannel.getAsMention(), category.getAsMention()); + + MessageEmbed embed = Utils.simpleEmbed(title, description, Color.GREEN); + + event.replyEmbeds(embed) + .addActionRow(Button.primary(generateConfigModal + ":" + hiveChannel.getParentCategoryIdLong(), "Open Settings")) + .setEphemeral(true) + .queue(); + } + + @DiscordCommand(name = "unset", description = "unset the category for dynamic voice channels", ephemeral = true) + public TextLocaleResponse unset( + Guild guild, + @DiscordParameter(name = "category", description = "Category to add dynamic channel") GuildChannelUnion channel) throws KeyNotFoundException, InvalidChannelTypeException { + + if(channel.getType() != ChannelType.CATEGORY) { + throw new InvalidChannelTypeException(); + } + + Category category = channel.asCategory(); + this.voiceManager.unsetDynamicCategory(category); + + return new TextLocaleResponse("voice.master.unset.success", category.getAsMention()); + } + + @DiscordCommand(name = "config", description = "config a dynamic voice channel", ephemeral = true) + public Modal config( + SlashCommandInteractionEvent event, Guild guild, LocalizationManager localization, + @LocaleType DiscordLocale locale, @DiscordParameter(name = "category", description = "Category to config") GuildChannelUnion channel) throws InvalidChannelTypeException, KeyNotFoundException { + + if(channel.getType() != ChannelType.CATEGORY) { + throw new InvalidChannelTypeException(); + } + + Category category = channel.asCategory(); + Modal configModal = voiceManager.getConfigModal(category, VoiceMasterController.configModal); + + if (configModal == null) { + throw new KeyNotFoundException(); + } + + return configModal; + } + + @DiscordCommand(name = "list", description = "list dynamic voice channels", ephemeral = true) + public MessageEmbed list(Guild guild, LocalizationManager localization, @LocaleType DiscordLocale locale) { + List hives = voiceManager.findAllByGuildId(guild.getIdLong()); + + StringBuilder sb = new StringBuilder(); + for (VoiceHive hive : hives) { + VoiceChannel hiveChannel = guild.getVoiceChannelById(hive.getVoiceId()); + Category parent = hiveChannel.getParentCategory(); + + if (parent == null) { + continue; + } + + sb.append(hiveChannel.getParentCategory().getAsMention()) + .append(" : ") + .append(hiveChannel.getAsMention()) + .append("\n"); + } + String message = sb.toString(); + + String title = localization.getLocalizedString("voice.master.list.title", locale); + return Utils.simpleEmbed(title, message, Color.GREEN); + } + + @DiscordButton(name = generateConfigModal, ephemeral = true) + public Modal generateConfigModal( + ButtonInteractionEvent event, + Guild guild) throws KeyNotFoundException, InvalidChannelTypeException { + String channelId = event.getComponentId().split(":")[1]; + Category category = guild.getCategoryById(channelId); + + if(category == null) { + throw new InvalidChannelTypeException(); + } + + Modal configModal = voiceManager.getConfigModal(category, VoiceMasterController.configModal); + + if (configModal == null) { + throw new KeyNotFoundException(); + } + + return configModal; + } + + @DiscordModal(name = configModal, ephemeral = true) + public MessageEmbed configModal( + Guild guild, + LocalizationManager localization, @LocaleType DiscordLocale locale, + ModalInteractionEvent event) throws KeyNotFoundException { + + String strCategoryId = event.getModalId().split(":")[1]; + long categoryId = Long.parseLong(strCategoryId); + Category category = event.getGuild().getCategoryById(categoryId); + + if (category == null) { + throw new KeyNotFoundException(); + } + + VoiceHive hive = voiceManager.setConfigModal(event, category); + return hive.show(guild); + } + + @DiscordButton(name = droneConfigButton, ephemeral = true) + public Modal droneConfig( + ButtonInteractionEvent event, Guild guild, @RequestInfo Member member) throws KeyNotFoundException, InvalidChannelTypeException, MissingPermissionsException { + + MessageChannelUnion channel = event.getChannel(); + + if(channel.getType() != ChannelType.VOICE) { + throw new InvalidChannelTypeException(); + } + + Modal configModal = droneManager.checkConfigDrone(guild, channel, member, droneConfigModal); + + if (configModal == null) { + throw new KeyNotFoundException(); + } + + return configModal; + } + + @DiscordModal(name = droneConfigModal, ephemeral = true) + public TextLocaleResponse droneConfigModal( + ModalInteractionEvent event) throws InvalidInputException { + + droneManager.updateDrone(event); + return new TextLocaleResponse("voice.master.drone.config.success"); + } + + @DiscordButton(name = droneHideShow, ephemeral = true) + public TextLocaleResponse droneHideShow( + ButtonInteractionEvent event, Guild guild, @RequestInfo Member member) throws KeyNotFoundException, MissingPermissionsException { + + MessageChannelUnion channel = event.getChannel(); + droneManager.toggleDroneVisibility(guild, channel, member); + return new TextLocaleResponse("voice.agent.hide-show.success"); + } + + @DiscordButton(name = dronePublicPrivate, ephemeral = true) + public TextLocaleResponse dronePublicPrivate( + ButtonInteractionEvent event, Guild guild, @RequestInfo Member member) throws KeyNotFoundException, MissingPermissionsException { + + MessageChannelUnion channel = event.getChannel(); + droneManager.toggleDronePublicPrivate(guild, channel, member); + return new TextLocaleResponse("voice.agent.public-private.success"); + } + + @DiscordButton(name = dronePermTemp, ephemeral = true) + public TextLocaleResponse dronePermTemp( + ButtonInteractionEvent event, Guild guild, @RequestInfo Member member) throws KeyNotFoundException, MissingPermissionsException { + + MessageChannelUnion channel = event.getChannel(); + droneManager.toggleDronePermTemp(guild, channel, member); + return new TextLocaleResponse("voice.agent.perm-temp.success"); + } + + @DiscordButton(name = droneClaim, ephemeral = true) + public TextLocaleResponse droneClaim( + ButtonInteractionEvent event, Guild guild, @RequestInfo Member member) throws KeyNotFoundException, NotInTheDroneException, OwnerInTheChannelException { + + MessageChannelUnion channel = event.getChannel(); + droneManager.claimDrone(guild, channel, member); + return new TextLocaleResponse("voice.master.claim.success"); + } +} diff --git a/src/main/java/com/softawii/capivara/core/DroneManager.java b/src/main/java/com/softawii/capivara/core/DroneManager.java index cc94661..26e34e8 100644 --- a/src/main/java/com/softawii/capivara/core/DroneManager.java +++ b/src/main/java/com/softawii/capivara/core/DroneManager.java @@ -1,16 +1,12 @@ package com.softawii.capivara.core; +import com.softawii.capivara.controller.VoiceMasterController; import com.softawii.capivara.entity.VoiceDrone; import com.softawii.capivara.entity.VoiceHive; -import com.softawii.capivara.exceptions.InvalidInputException; -import com.softawii.capivara.exceptions.KeyNotFoundException; -import com.softawii.capivara.exceptions.NotInTheDroneException; -import com.softawii.capivara.exceptions.OwnerInTheChannelException; -import com.softawii.capivara.listeners.VoiceGroup; +import com.softawii.capivara.exceptions.*; import com.softawii.capivara.services.VoiceDroneService; import com.softawii.capivara.services.VoiceHiveService; import com.softawii.capivara.utils.Utils; -import com.softawii.curupira.exceptions.MissingPermissionsException; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.Permission; @@ -231,7 +227,7 @@ public void checkToDeleteTemporary(VoiceChannel channel, Member member, boolean } else if (member == null || member.getIdLong() == drone.getOwnerId()) { // Election Mode! MessageEmbed embed = claimChat(); - Button claim = Button.success(VoiceGroup.Dynamic.droneClaim, "Claim"); + Button claim = Button.success(VoiceMasterController.droneClaim, "Claim"); Message claimMessage; if (textChannel != null) { @@ -348,10 +344,10 @@ private void createControlPanel(VoiceChannel voiceChannel, GuildMessageChannel t // region Buttons // General Config - Button config = Button.primary(VoiceGroup.Dynamic.droneConfig, "🔧 Settings"); - Button visibility = Button.secondary(VoiceGroup.Dynamic.droneHideShow, isVisible(voiceChannel) ? "👻 Hide" : "👀 Visible"); - Button connect = Button.secondary(VoiceGroup.Dynamic.dronePublicPrivate, canConnect(voiceChannel) ? "📢 Public" : "🔒 Private"); - Button permanent = Button.danger(VoiceGroup.Dynamic.dronePermTemp, drone.isPermanent() ? "â³ Temporary" : "✨ Permanent"); + Button config = Button.primary(VoiceMasterController.droneConfigButton, "🔧 Settings"); + Button visibility = Button.secondary(VoiceMasterController.droneHideShow, isVisible(voiceChannel) ? "👻 Hide" : "👀 Visible"); + Button connect = Button.secondary(VoiceMasterController.dronePublicPrivate, canConnect(voiceChannel) ? "📢 Public" : "🔒 Private"); + Button permanent = Button.danger(VoiceMasterController.dronePermTemp, drone.isPermanent() ? "â³ Temporary" : "✨ Permanent"); ActionRow general = ActionRow.of(config, visibility, connect, permanent); // endregion @@ -509,7 +505,7 @@ public void claimDrone(Guild guild, MessageChannelUnion channel, Member member) } if (!voiceChannel.getMembers().contains(member)) { - throw new NotInTheDroneException("You are not in the drone!"); + throw new NotInTheDroneException(); } if (textChannel != null) textChannel.getManager().removePermissionOverride(drone.getOwnerId()).submit(); diff --git a/src/main/java/com/softawii/capivara/listeners/events/TwitterListener.java b/src/main/java/com/softawii/capivara/events/TwitterListener.java similarity index 93% rename from src/main/java/com/softawii/capivara/listeners/events/TwitterListener.java rename to src/main/java/com/softawii/capivara/events/TwitterListener.java index b785edc..953cebd 100644 --- a/src/main/java/com/softawii/capivara/listeners/events/TwitterListener.java +++ b/src/main/java/com/softawii/capivara/events/TwitterListener.java @@ -1,6 +1,6 @@ -package com.softawii.capivara.listeners.events; +package com.softawii.capivara.events; -import com.softawii.capivara.listeners.TwitterGroup; +import com.softawii.capivara.controller.SocialTwitterGroup; import com.softawii.capivara.services.TwitterParserConfigService; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Message; @@ -60,7 +60,7 @@ private void createTweetMessage(Long guildId, String replacementMessage, Message RestAction.allOf( originalMessage.delete(), channel.sendMessage(replacementMessage) - .addActionRow(TwitterGroup.generateDeleteButton(originalMessage.getAuthor().getIdLong())) + .addActionRow(SocialTwitterGroup.generateDeleteButton(originalMessage.getAuthor().getIdLong())) .setSuppressedNotifications(true) ).queue(); } diff --git a/src/main/java/com/softawii/capivara/listeners/events/VoiceEvents.java b/src/main/java/com/softawii/capivara/events/VoiceEvents.java similarity index 97% rename from src/main/java/com/softawii/capivara/listeners/events/VoiceEvents.java rename to src/main/java/com/softawii/capivara/events/VoiceEvents.java index c4c8456..8b42448 100644 --- a/src/main/java/com/softawii/capivara/listeners/events/VoiceEvents.java +++ b/src/main/java/com/softawii/capivara/events/VoiceEvents.java @@ -1,10 +1,10 @@ -package com.softawii.capivara.listeners.events; +package com.softawii.capivara.events; import com.softawii.capivara.core.DroneManager; import com.softawii.capivara.core.VoiceManager; import com.softawii.capivara.entity.VoiceHive; import com.softawii.capivara.exceptions.KeyNotFoundException; -import com.softawii.capivara.utils.CapivaraExceptionHandler; +import com.softawii.capivara.controller.MainExceptionController; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.ChannelType; @@ -30,9 +30,9 @@ public class VoiceEvents extends ListenerAdapter { private final DroneManager droneManager; private final Logger LOGGER = LogManager.getLogger(VoiceEvents.class); - private final CapivaraExceptionHandler exceptionHandler; + private final MainExceptionController exceptionHandler; - public VoiceEvents(JDA jda, VoiceManager voiceManager, DroneManager droneManager, CapivaraExceptionHandler exceptionHandler) { + public VoiceEvents(JDA jda, VoiceManager voiceManager, DroneManager droneManager, MainExceptionController exceptionHandler) { this.voiceManager = voiceManager; this.droneManager = droneManager; this.exceptionHandler = exceptionHandler; diff --git a/src/main/java/com/softawii/capivara/exceptions/InvalidChannelTypeException.java b/src/main/java/com/softawii/capivara/exceptions/InvalidChannelTypeException.java new file mode 100644 index 0000000..871be37 --- /dev/null +++ b/src/main/java/com/softawii/capivara/exceptions/InvalidChannelTypeException.java @@ -0,0 +1,4 @@ +package com.softawii.capivara.exceptions; + +public class InvalidChannelTypeException extends Exception { +} diff --git a/src/main/java/com/softawii/capivara/exceptions/MissingPermissionsException.java b/src/main/java/com/softawii/capivara/exceptions/MissingPermissionsException.java new file mode 100644 index 0000000..b628b27 --- /dev/null +++ b/src/main/java/com/softawii/capivara/exceptions/MissingPermissionsException.java @@ -0,0 +1,4 @@ +package com.softawii.capivara.exceptions; + +public class MissingPermissionsException extends Exception { +} diff --git a/src/main/java/com/softawii/capivara/exceptions/NotInTheDroneException.java b/src/main/java/com/softawii/capivara/exceptions/NotInTheDroneException.java index 9d4fbdb..ac55f67 100644 --- a/src/main/java/com/softawii/capivara/exceptions/NotInTheDroneException.java +++ b/src/main/java/com/softawii/capivara/exceptions/NotInTheDroneException.java @@ -1,6 +1,4 @@ package com.softawii.capivara.exceptions; public class NotInTheDroneException extends Throwable { - public NotInTheDroneException(String s) { - } } diff --git a/src/main/java/com/softawii/capivara/listeners/EchoGroup.java b/src/main/java/com/softawii/capivara/listeners/EchoGroup.java deleted file mode 100644 index b90dea4..0000000 --- a/src/main/java/com/softawii/capivara/listeners/EchoGroup.java +++ /dev/null @@ -1,590 +0,0 @@ -package com.softawii.capivara.listeners; - - -import com.softawii.capivara.core.EmbedManager; -import com.softawii.capivara.exceptions.FieldLengthException; -import com.softawii.capivara.exceptions.KeyNotFoundException; -import com.softawii.capivara.exceptions.UrlException; -import com.softawii.capivara.utils.Utils; -import com.softawii.curupira.annotations.*; -import com.softawii.curupira.core.Curupira; -import net.dv8tion.jda.api.Permission; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.channel.ChannelType; -import net.dv8tion.jda.api.entities.channel.concrete.NewsChannel; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent; -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; -import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent; -import net.dv8tion.jda.api.interactions.commands.OptionMapping; -import net.dv8tion.jda.api.interactions.commands.OptionType; -import net.dv8tion.jda.api.interactions.components.ActionRow; -import net.dv8tion.jda.api.interactions.components.buttons.Button; -import net.dv8tion.jda.api.interactions.components.selections.SelectOption; -import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu; -import net.dv8tion.jda.api.interactions.components.text.TextInputStyle; -import net.dv8tion.jda.api.interactions.modals.Modal; -import net.dv8tion.jda.api.requests.restaction.MessageCreateAction; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.awt.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -@IGroup(name = "echo", description = "Echo Group") -@Component -public class EchoGroup { - - public static final String buttonEditMessage = "echo-edit-message"; - public static final String modalEditMessage = "echo-edit-message-modal"; - //endregion - public static final String buttonRemoveMessage = "echo-remove-message"; - //region Send/Cancel Constants - private static final String buttonSend = "echo-send"; - private static final String buttonDeny = "echo-deny"; - //region Title/Description Constants - private static final String buttonTitle = "echo-title"; - - //endregion - private static final String modalTitle = "echo-title-modal"; - private static final String buttonImage = "echo-image"; - private static final String modalImage = "echo-image-modal"; - //region Fields Constants - private static final String buttonNewField = "echo-new-field"; - private static final String modalNewField = "echo-new-field-modal"; - private static final String buttonRemoveField = "echo-remove-field"; - private static final String menuRemoveField = "echo-remove-field-menu"; - //endregion Constants - - //region Message Constants - private static final String buttonEditField = "echo-edit-field"; - private static final String menuEditField = "echo-edit-field-menu"; - private static final String modalEditField = "echo-edit-field-modal"; - - //endregion - private static final Logger LOGGER = LogManager.getLogger(EchoGroup.class); - - private static EmbedManager embedManager; - private static Curupira curupira; - - @Autowired - public void setCurupira(Curupira curupira) { - EchoGroup.curupira = curupira; - } - - @Autowired - public void setEmbedManager(EmbedManager embedManager) { - EchoGroup.embedManager = embedManager; - } - - @ICommand(name = "echo", - description = "Quer enviar uma mensagem para o canal como se fosse o bot? Um anúncio? Pode me usar!", - permissions = {Permission.ADMINISTRATOR}) - @IArgument(name = "target", description = "O canal que você quer enviar a mensagem", type = OptionType.CHANNEL, - required = true) - @IArgument(name = "message", description = "Escreva uma mensagem ai pra ficar fora do Embed", - type = OptionType.STRING, required = false) - public static void echo(SlashCommandInteractionEvent event) { - // Decode - String message = event.getOption("message") != null ? event.getOption("message").getAsString() : null; - OptionMapping targetOpt = event.getOption("target"); - - List textChannels = List.of(ChannelType.TEXT, ChannelType.GUILD_PRIVATE_THREAD, ChannelType.GUILD_PUBLIC_THREAD, ChannelType.GUILD_NEWS_THREAD, ChannelType.NEWS); - if (!textChannels.contains(targetOpt.getChannelType())) { - MessageEmbed embed = Utils.simpleEmbed("Echo", "Este comando só funciona em canais de texto!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - // Generating Embed Model - Map.Entry init = embedManager.init(); - init.getValue().setMessage(message); - init.getValue().setTarget(event.getOption("target").getAsChannel().asGuildMessageChannel()); - - if (message != null) { - event.reply(message) - .addEmbeds(init.getValue().build()) - .setComponents(EchoGroup.embedEditor(init.getKey())) - .setEphemeral(true) - .queue(); - } else { - event.replyEmbeds(init.getValue().build()) - .setComponents(EchoGroup.embedEditor(init.getKey())) - .setEphemeral(true) - .queue(); - } - } - - @IButton(id = buttonSend) - public static void send(ButtonInteractionEvent event) { - // Extracting ID - /* - Format: buttonSend: - */ - String id = event.getComponentId().split(":")[1]; - - EmbedManager.EmbedHandler embedHandler; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - GuildChannel target = embedHandler.getTarget(); - - MessageCreateAction messageAction; - if (target instanceof TextChannel textChannel) { - if (embedHandler.getMessage() != null) - messageAction = textChannel.sendMessage(embedHandler.getMessage()).setEmbeds(embedHandler.build()); - else messageAction = textChannel.sendMessageEmbeds(embedHandler.build()); - } else if (target instanceof NewsChannel newsChannel) { - if (embedHandler.getMessage() != null) - messageAction = newsChannel.sendMessage(embedHandler.getMessage()).setEmbeds(embedHandler.build()); - else messageAction = newsChannel.sendMessageEmbeds(embedHandler.build()); - } else { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "O canal vinculado não é de um tipo suportado!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - if (embedHandler.getActiveRows() != null && !embedHandler.getActiveRows().isEmpty()) { - messageAction.setComponents(embedHandler.getActiveRows()); - } - messageAction.queue(); - - MessageEmbed embed = Utils.simpleEmbed("Embed enviado!", "Embed enviado com sucesso!", Color.GREEN); - event.editMessage("Tudo ok!").setEmbeds(embed).setComponents().queue(); - } - - @IButton(id = buttonDeny) - public static void deny(ButtonInteractionEvent event) { - // Extracting ID - /* - Format: buttonSend: - */ - String id = event.getComponentId().split(":")[1]; - embedManager.destroy(id); - - MessageEmbed embed = Utils.simpleEmbed("Embed cancelado!", "Embed cancelado com sucesso!", Color.GREEN); - event.editMessage("Cancelei!!").setEmbeds(embed).setComponents().queue(); - } - - //region Title / Description - - @IButton(id = buttonTitle) - public static void title(ButtonInteractionEvent event) { - // Extracting ID - // Format: buttonSend: - String id = event.getComponentId().split(":")[1]; - - EmbedManager.EmbedHandler embedHandler; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - // Generating Embed Model - Modal.Builder modal = curupira.getModal(modalTitle); - modal.setId(modal.getId() + ":" + id); - - // TODO: Fill Modal with current data - - event.replyModal(modal.build()).queue(); - } - - @IModal(id = modalTitle, title = "Vamos anunciar o que??", description = "Digite o que você quer anunciar", - textInputs = { - @IModal.ITextInput(id = "titulo", label = "Título do Anúncio!", style = TextInputStyle.SHORT, - placeholder = "Escolha um nome impactante!", required = true, minLength = 1, - maxLength = 256), - @IModal.ITextInput(id = "mensagem", label = "Mensagem do Anúncio!", - style = TextInputStyle.PARAGRAPH, - placeholder = "Que mensagem importante... digita pro seu pai...", - required = true, minLength = 1, maxLength = 4000) - }) - public static void modalTitle(ModalInteractionEvent event) { - String title = event.getValue("titulo").getAsString(); - String message = event.getValue("mensagem").getAsString(); - - // Extracting ID - // Format: echoModal: - String id = event.getModalId().split(":")[1]; - - EmbedManager.EmbedHandler embedHandler = null; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - try { - embedHandler.setTitle(title); - embedHandler.setDescription(message); - } catch (FieldLengthException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "O título ou a mensagem são muito longos!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - event.editMessageEmbeds(embedHandler.build()).setComponents(EchoGroup.embedEditor(id)).queue(); - } - - //endregion - - //region Image - - @IButton(id = buttonImage) - public static void image(ButtonInteractionEvent event) { - String id = event.getComponentId().split(":")[1]; - - EmbedManager.EmbedHandler embedHandler; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - // Generating Embed Model - Modal.Builder modal = curupira.getModal(modalImage); - modal.setId(modal.getId() + ":" + id); - - event.replyModal(modal.build()).queue(); - } - - @IModal(id = modalImage, title = "Fala sobre sua sessão ai!", - description = "Tenho certeza que é muito interessante...", textInputs = { - @IModal.ITextInput(id = "url", label = "Joga a url ai, fazendo favor!", style = TextInputStyle.SHORT, - placeholder = "https://i.pinimg.com/564x/ab/21/d5/ab21d5b71ba7b3b74947c3e5656c6aee--room-to-room-velvet.jpg/", - required = true, minLength = 1, maxLength = 256), - }) - public static void modalImagem(ModalInteractionEvent event) { - String url = event.getValue("url").getAsString(); - - // Extracting ID - // Format: modalNewField: - String id = event.getModalId().split(":")[1]; - - EmbedManager.EmbedHandler embedHandler = null; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - try { - embedHandler.setImage(url); - } catch (UrlException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "A URL não é válida!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - event.editMessageEmbeds(embedHandler.build()).setComponents(EchoGroup.embedEditor(id)).queue(); - } - - //endregion - - //region New Field - - @IButton(id = buttonNewField) - public static void newField(ButtonInteractionEvent event) { - String id = event.getComponentId().split(":")[1]; - - EmbedManager.EmbedHandler embedHandler; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - // Generating Embed Model - Modal.Builder modal = curupira.getModal(modalNewField); - modal.setId(modal.getId() + ":" + id); - - // TODO: Fill Modal with current data - - event.replyModal(modal.build()).queue(); - } - - @IModal(id = modalNewField, title = "Fala sobre sua sessão ai!", - description = "Tenho certeza que é muito interessante...", textInputs = { - @IModal.ITextInput(id = "name", label = "Título do Sessão!", style = TextInputStyle.SHORT, - placeholder = "Escolha um nome impactante!", required = true, minLength = 1, - maxLength = 256), - @IModal.ITextInput(id = "value", label = "Mensagem do Sessão!", style = TextInputStyle.PARAGRAPH, - placeholder = "Que mensagem importante... digita pro seu pai...", required = true, - minLength = 1, maxLength = 1024) - }) - public static void modalNewField(ModalInteractionEvent event) { - String name = event.getValue("name").getAsString(); - String value = event.getValue("value").getAsString(); - - // Extracting ID - // Format: modalNewField: - String id = event.getModalId().split(":")[1]; - - EmbedManager.EmbedHandler embedHandler = null; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - try { - embedHandler.addField(new MessageEmbed.Field(name, value, false)); - } catch (FieldLengthException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Vcê está tentando botar muitos campos!!!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - event.editMessageEmbeds(embedHandler.build()).setComponents(EchoGroup.embedEditor(id)).queue(); - } - - //endregion - - //region Edit Field - - @IButton(id = buttonEditField) - public static void editField(ButtonInteractionEvent event) { - String id = event.getComponentId().split(":")[1]; - - StringSelectMenu.Builder builder; - try { - builder = EchoGroup.embedField(id, menuEditField); - builder.setRequiredRange(1, 1); - builder.setPlaceholder("Escolha um campo para editar!"); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - event.editComponents(ActionRow.of(builder.build())).queue(); - } - - @IMenu(id = menuEditField) - public static void editFieldMenu(StringSelectInteractionEvent event) { - SelectOption selectOption = event.getSelectedOptions().get(0); - String id = event.getComponentId().split(":")[1]; - - int index = Integer.parseInt(selectOption.getValue()); - - if (index >= 0) { - EmbedManager.EmbedHandler embedHandler; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - Modal.Builder modal = curupira.getModal(modalEditField); - modal.setId(modal.getId() + ":" + id + ":" + index); - - event.replyModal(modal.build()).queue(); - } else { - event.editComponents(EchoGroup.embedEditor(id)).queue(); - } - } - - @IModal(id = modalEditField, title = "Fala sobre sua sessão ai!", - description = "Tenho certeza que é muito interessante...", textInputs = { - @IModal.ITextInput(id = "name", label = "Título do Sessão!", style = TextInputStyle.SHORT, - placeholder = "Escolha um nome impactante!", required = true, minLength = 1, - maxLength = 256), - @IModal.ITextInput(id = "value", label = "Mensagem do Sessão!", style = TextInputStyle.PARAGRAPH, - placeholder = "Que mensagem importante... digita pro seu pai...", required = true, - minLength = 1, maxLength = 1024) - }) - public static void modalEditField(ModalInteractionEvent event) { - - // Extracting ID - // Format: modalNewField:: - String id = event.getModalId().split(":")[1]; - int index = Integer.parseInt(event.getModalId().split(":")[2]); - - EmbedManager.EmbedHandler embedHandler = null; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - String name = event.getValue("name").getAsString(); - String value = event.getValue("value").getAsString(); - MessageEmbed.Field editedField = new MessageEmbed.Field(name, value, false); - embedHandler.setField(editedField, index); - - event.editMessageEmbeds(embedHandler.build()).setComponents(EchoGroup.embedEditor(id)).queue(); - } - - //endregion - - //region Remove Field - - @IButton(id = buttonRemoveField) - public static void removeFieldButton(ButtonInteractionEvent event) { - String id = event.getComponentId().split(":")[1]; - - StringSelectMenu.Builder builder; - try { - builder = EchoGroup.embedField(id, menuRemoveField); - builder.setRequiredRange(1, 1); - builder.setPlaceholder("Escolha um campo para remover!"); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - event.editComponents(ActionRow.of(builder.build())).queue(); - } - - @IMenu(id = menuRemoveField) - public static void removeFieldMenu(StringSelectInteractionEvent event) { - SelectOption selectOption = event.getSelectedOptions().get(0); - String id = event.getComponentId().split(":")[1]; - - int index = Integer.parseInt(selectOption.getValue()); - - if (index >= 0) { - EmbedManager.EmbedHandler embedHandler; - try { - embedHandler = embedManager.get(id); - embedHandler.removeField(index); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - event.editMessageEmbeds(embedHandler.build()).setComponents(EchoGroup.embedEditor(id)).queue(); - } else { - event.editComponents(EchoGroup.embedEditor(id)).queue(); - } - - } - - //endregion - - //region Message - - @IButton(id = buttonEditMessage) - public static void editMessage(ButtonInteractionEvent event) { - String id = event.getComponentId().split(":")[1]; - Modal.Builder builder = curupira.getModal(modalEditMessage).setId(modalEditMessage + ":" + id); - event.replyModal(builder.build()).queue(); - } - - @IModal(id = modalEditMessage, title = "Escreve sua mensagem ai!", description = "Escreve ai, bora!", textInputs = { - @IModal.ITextInput(id = "message", label = "Mensagem", style = TextInputStyle.SHORT, - placeholder = "FrasesDeEfeito.com.br", required = true, minLength = 1, maxLength = 256), - }) - public static void modalMessage(ModalInteractionEvent event) { - String message = event.getValue("message").getAsString(); - - // Extracting ID - // Format: modalEditMessage: - String id = event.getModalId().split(":")[1]; - - EmbedManager.EmbedHandler embedHandler = null; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - embedHandler.setMessage(message); - event.editMessage(message).queue(); - } - - - @IButton(id = buttonRemoveMessage) - public static void removeMessage(ButtonInteractionEvent event) { - String id = event.getComponentId().split(":")[1]; - - EmbedManager.EmbedHandler embedHandler = null; - try { - embedHandler = embedManager.get(id); - } catch (KeyNotFoundException e) { - MessageEmbed embed = Utils.simpleEmbed("Algo errado aqui! Mil perdões", "Embed não encontrado no nosso sistema, vai ter que fazer de novo!", Color.RED); - event.replyEmbeds(embed).setEphemeral(true).queue(); - return; - } - - embedHandler.setMessage(null); - - event.editMessage("Você removeu sua mensagem! (Se quiser adicionar outra só clicar no botão de editar)").queue(); - } - - //endregion - - //region Utils - public static List embedEditor(String id) { - - // Send / Cancel Row - Button send = Button.success(buttonSend + ":" + id, "Enviar Embed"); - Button deny = Button.danger(buttonDeny + ":" + id, "Cancelar Embed"); - - // Edit Title / Description Row - Button title = Button.primary(buttonTitle + ":" + id, "Editar Título ou Descrição"); - Button imageField = Button.primary(buttonImage + ":" + id, "Nova Imagem"); - - // Add Field / Remove Field / Edit Field - Button newField = Button.secondary(buttonNewField + ":" + id, "Novo Campo"); - Button deleteField = Button.secondary(buttonRemoveField + ":" + id, "Remover Campo"); - Button editField = Button.secondary(buttonEditField + ":" + id, "Editar Campo"); - - // Edit / Remove Message - Button editMessage = Button.secondary(buttonEditMessage + ":" + id, "Editar Mensagem"); - Button removeMessage = Button.secondary(buttonRemoveMessage + ":" + id, "Remover Mensagem"); - - List actionRows = new ArrayList<>(); - actionRows.add(ActionRow.of(title, imageField)); - actionRows.add(ActionRow.of(newField, deleteField, editField)); - actionRows.add(ActionRow.of(editMessage, removeMessage)); - actionRows.add(ActionRow.of(send, deny)); - - return actionRows; - } - - public static StringSelectMenu.Builder embedField(String id, String menuId) throws KeyNotFoundException { - StringSelectMenu.Builder builder = StringSelectMenu.create(menuId + ":" + id); - EmbedManager.EmbedHandler embedHandler = embedManager.get(id); - - List options = embedHandler.getFieldNames().stream().map(name -> { - if (name.length() > 100) return name.substring(0, 95) + "..."; - else return name; - }).toList(); - - builder.addOption("Nenhum", "-1"); - - for (int i = 0; i < options.size(); i++) { - builder.addOption(options.get(i), String.valueOf(i)); - } - - return builder; - } - - //endregion -} diff --git a/src/main/java/com/softawii/capivara/listeners/TwitterGroup.java b/src/main/java/com/softawii/capivara/listeners/TwitterGroup.java deleted file mode 100644 index 2f7965b..0000000 --- a/src/main/java/com/softawii/capivara/listeners/TwitterGroup.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.softawii.capivara.listeners; - -import com.softawii.capivara.services.TwitterParserConfigService; -import com.softawii.curupira.annotations.IButton; -import com.softawii.curupira.annotations.ICommand; -import com.softawii.curupira.annotations.IGroup; -import net.dv8tion.jda.api.Permission; -import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion; -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; -import net.dv8tion.jda.api.interactions.components.buttons.Button; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@IGroup(name = "twitter", description = "Transformação de links do Twitter automática", hidden = false) -@Component -public class TwitterGroup { - - public static final String deleteBotTwitterMessage = "twitter-bot-message-delete"; - private static TwitterParserConfigService service; - - @Autowired - @SuppressWarnings("unused") - public void setCurupira(TwitterParserConfigService service) { - TwitterGroup.service = service; - } - - @ICommand(name = "enable", description = "Ativa o serviço de transformação de links do Twitter automática", - permissions = {Permission.ADMINISTRATOR}) - @SuppressWarnings("unused") - public static void enable(SlashCommandInteractionEvent event) { - long guildId = event.getGuild().getIdLong(); - if (service.isEnabled(guildId)) { - event.reply("O serviço já está ativado").setEphemeral(true).queue(); - return; - } - - service.enable(guildId); - event.reply("O serviço foi está ativado").setEphemeral(true).queue(); - } - - @ICommand(name = "disable", description = "Desativa o serviço de transformação de links do Twitter automática", - permissions = {Permission.ADMINISTRATOR}) - @SuppressWarnings("unused") - public static void disable(SlashCommandInteractionEvent event) { - long guildId = event.getGuild().getIdLong(); - if (!service.isEnabled(guildId)) { - event.reply("O serviço não está ativado").setEphemeral(true).queue(); - return; - } - - service.disable(guildId); - event.reply("O serviço foi está ativado").setEphemeral(true).queue(); - } - - @IButton(id = deleteBotTwitterMessage) - @SuppressWarnings("unused") - public static void delete(ButtonInteractionEvent event) { - // Format: ButtonID:Owner - String ownerId = event.getComponentId().split(":")[1]; - String messageOwner = event.getMember().getId(); - - MessageChannelUnion channel = event.getChannel(); - - if (!messageOwner.equals(ownerId)) { - event.reply("Você não pode apagar essa mensagem").setEphemeral(true).queue(); - return; - } - - event.reply("Mensagem apagada").setEphemeral(true).queue(); - channel.deleteMessageById(event.getMessageId()).queue(); - } - - public static Button generateDeleteButton(long authorId) { - return Button.danger(String.format("%s:%s", deleteBotTwitterMessage, authorId), "Apagar"); - } -} diff --git a/src/main/java/com/softawii/capivara/listeners/VoiceGroup.java b/src/main/java/com/softawii/capivara/listeners/VoiceGroup.java deleted file mode 100644 index ce9797d..0000000 --- a/src/main/java/com/softawii/capivara/listeners/VoiceGroup.java +++ /dev/null @@ -1,560 +0,0 @@ -package com.softawii.capivara.listeners; - -import com.softawii.capivara.core.DroneManager; -import com.softawii.capivara.core.VoiceManager; -import com.softawii.capivara.entity.VoiceHive; -import com.softawii.capivara.exceptions.*; -import com.softawii.capivara.utils.Utils; -import com.softawii.curupira.annotations.*; -import com.softawii.curupira.exceptions.MissingPermissionsException; -import net.dv8tion.jda.api.Permission; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.channel.ChannelType; -import net.dv8tion.jda.api.entities.channel.concrete.Category; -import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; -import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel; -import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; -import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion; -import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent; -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import net.dv8tion.jda.api.interactions.commands.OptionType; -import net.dv8tion.jda.api.interactions.components.buttons.Button; -import net.dv8tion.jda.api.interactions.modals.Modal; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.jetbrains.annotations.Nullable; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.awt.*; -import java.util.Collections; -import java.util.List; - -@IGroup(name = "Voice", description = "Voice") -public class VoiceGroup { - - private static final Logger LOGGER = LogManager.getLogger(VoiceGroup.class); - - @ICommand(name = "invite", description = "Invite user to your channel") - @IArgument(name = "user", - description = "User to invite", - required = true, type = OptionType.USER) - @SuppressWarnings({"unused"}) - public static void invite(SlashCommandInteractionEvent event) { - Member member = event.getMember(); - Member invited = event.getOption("user").getAsMember(); - - AudioChannel channel = Dynamic.validateRequest(event, member); - if (channel == null) return; - - VoiceChannel voice = (VoiceChannel) channel; - voice.createInvite().setUnique(true).deadline(System.currentTimeMillis() + Dynamic.inviteDeadline).queue(q -> { - voice.getManager().putPermissionOverride(invited, List.of(Permission.VIEW_CHANNEL, Permission.VOICE_CONNECT), Collections.emptyList()).queue(); - String name = member.getEffectiveName() + (member.getNickname() != null ? " (" + member.getNickname() + ")" : ""); - invited.getUser().openPrivateChannel().queue(chn -> chn.sendMessage(name + "invited you to join in a channel!\n" + q.getUrl()).queue()); - event.reply("Invite sent to " + invited.getAsMention()).setEphemeral(true).queue(); - }); - } - - // User Commands - - @ICommand(name = "kick", description = "Kick user from your channel, it will remove permissions too") - @IArgument(name = "user", - description = "User to kick", - required = true, type = OptionType.USER) - @SuppressWarnings({"unused"}) - public static void kick(SlashCommandInteractionEvent event) { - Member member = event.getMember(); - Member to_kick = event.getOption("user").getAsMember(); - - AudioChannel channel = Dynamic.validateRequest(event, member); - if (channel == null) return; - - VoiceChannel voice = (VoiceChannel) channel; - voice.getManager().removePermissionOverride(to_kick).submit(); - - if (to_kick.getVoiceState().getChannel() != null) { - AudioChannel to_kick_channel = to_kick.getVoiceState().getChannel(); - if (to_kick_channel.getIdLong() == channel.getIdLong()) { - event.getGuild().moveVoiceMember(to_kick, null).and( - event.reply("Kicked " + to_kick.getAsMention()).setEphemeral(true) - ).queue(); - } else { - event.reply("User is not in your channel!").setEphemeral(true).queue(); - return; - } - } else { - event.reply("User is not in a voice channel!").setEphemeral(true).queue(); - return; - } - } - - @ICommand(name = "ban", description = "Ban user from your channel") - @IArgument(name = "user", - description = "User to kick", - required = true, type = OptionType.USER) - public static void ban(SlashCommandInteractionEvent event) { - Member member = event.getMember(); - Member to_ban = event.getOption("user").getAsMember(); - - AudioChannel channel = Dynamic.validateRequest(event, member); - if (channel == null) return; - - if (to_ban.getVoiceState().getChannel() != null) { - AudioChannel to_ban_channel = to_ban.getVoiceState().getChannel(); - if (to_ban_channel.getIdLong() == channel.getIdLong()) { - event.getGuild().moveVoiceMember(to_ban, null).and( - event.reply("Banned " + to_ban.getAsMention()).setEphemeral(true) - ).queue(); - } - } else { - event.reply("Banned " + to_ban.getAsMention()).setEphemeral(true).queue(); - } - - VoiceChannel voice = (VoiceChannel) channel; - voice.getManager().putPermissionOverride(to_ban, Collections.emptyList(), List.of(Permission.VIEW_CHANNEL, Permission.VOICE_CONNECT)).queue(); - } - - @ICommand(name = "permanent", description = "Make channel permanent", permissions = {Permission.MANAGE_CHANNEL}) - @IArgument(name = "status", - description = "True to make permanent, False to make temporary", - required = true, type = OptionType.BOOLEAN) - public static void permanent(SlashCommandInteractionEvent event) { - Member member = event.getMember(); - - AudioChannel channel = Dynamic.validateRequest(event, member); - if (channel == null) return; - - VoiceChannel voice = (VoiceChannel) channel; - - try { - Dynamic.droneManager.makePermanent(voice, event.getOption("status").getAsBoolean()); - } catch (KeyNotFoundException e) { - event.reply("You need to be in a temporary voice channel to use this command!").setEphemeral(true).queue(); - return; - } - event.reply("Channel is now " + event.getOption("status").getAsBoolean()).setEphemeral(true).queue(); - } - - @ISubGroup(name = "Dynamic", description = "Dynamic") - @Component - public static class Dynamic extends ListenerAdapter { - - public static final long inviteDeadline = 1000L * 10L * 60L; // 600000 ms = 10 minutes - // region constants - public static final String configModal = "voice-dynamic-config-modal"; - public static final String generateConfigModal = "voice-dynamic-generate-config-modal"; - public static final String droneConfig = "voice-dynamic-drone-config"; - public static final String droneHideShow = "voice-dynamic-drone-hide-show"; - public static final String dronePublicPrivate = "voice-dynamic-drone-public-private"; - public static final String dronePermTemp = "voice-dynamic-drone-permanent-temporary"; - public static final String droneClaim = "voice-dynamic-drone-claim"; - private static VoiceManager voiceManager; - private static DroneManager droneManager; - - @Autowired - public void setVoiceManager(VoiceManager voiceManager) { - Dynamic.voiceManager = voiceManager; - } - - @Autowired - public void setDroneManager(DroneManager droneManager) { - Dynamic.droneManager = droneManager; - } - - // endregion - - //region Discord Commands - - /** - * This command is used to put a 'Voice Dynamic Master' channel in a category - * - * @param event : SlashCommandInteractionEvent - */ - @ICommand(name = "set", description = "Set dynamic voice channels to the selected category", - permissions = {Permission.ADMINISTRATOR}) - @IArgument(name = "category", description = "Category to add dynamic voice chat!", required = true, - type = OptionType.CHANNEL) - @SuppressWarnings({"ConstantConditions", "unused"}) - public static void set(SlashCommandInteractionEvent event) { - String method = new Throwable().getStackTrace()[0].getMethodName(); - LOGGER.debug(method + " : start"); - - // region Verify and Decode - GuildChannelUnion channel = event.getOption("category").getAsChannel(); - - if (channel.getType() != ChannelType.CATEGORY) { - LOGGER.debug(method + " : error : non category : " + channel); - event.reply("You need to pass a category!").queue(); - return; - } - - // endregion - - Category category = channel.asCategory(); - - // Manager (business rule) - try { - VoiceHive hive = voiceManager.setDynamicCategory(category); - - // Reply -> Never NULL (Guild Command) - Guild guild = event.getGuild(); - - VoiceChannel hiveChannel = guild.getVoiceChannelById(hive.getVoiceId()); - - MessageEmbed embed = Utils.simpleEmbed("Voice Hive Initialized", - "Just click in " + hiveChannel.getAsMention() + " to create a dynamic channel!", Color.GREEN); - - event.replyEmbeds(embed) - .addActionRow(Button.primary(generateConfigModal + ":" + hiveChannel.getParentCategoryIdLong(), "Open Settings")) - .setEphemeral(true) - .queue(); - } catch (ExistingDynamicCategoryException e) { - LOGGER.debug(method + " : error : " + e.getMessage()); - - VoiceHive hive; - try { - hive = voiceManager.find(category); - } catch (KeyNotFoundException ex) { - // Wait, this is a bug! - LOGGER.debug(method + " : error : " + ex.getMessage()); - return; - } - // Reply -> Never NULL (Guild Command) - Guild guild = event.getGuild(); - VoiceChannel hiveChannel = guild.getVoiceChannelById(hive.getVoiceId()); - MessageEmbed embed = Utils.simpleEmbed("The current category is already a hive of voice channels!", - "Just click in " + hiveChannel.getAsMention() + " to create a dynamic channel!", Color.RED); - event.replyEmbeds(embed).queue(); - } - - LOGGER.debug(method + " : end"); - } - - @ICommand(name = "unset", description = "Unset dynamic voice channels to the selected category", - permissions = {Permission.ADMINISTRATOR}) - @IArgument(name = "category", description = "Category to add dynamic voice chat!", required = true, - type = OptionType.CHANNEL) - @SuppressWarnings({"ConstantConditions", "unused"}) - public static void unset(SlashCommandInteractionEvent event) { - String method = new Throwable().getStackTrace()[0].getMethodName(); - LOGGER.debug(method + " : start"); - - // region Verify and Decode - GuildChannelUnion channel = event.getOption("category").getAsChannel(); - - if (channel.getType() != ChannelType.CATEGORY) { - LOGGER.debug(method + " : error : non category : " + channel); - event.reply("You need to pass a category!").queue(); - return; - } - - // endregion - - Category category = channel.asCategory(); - - // Manager (business rule) - try { - voiceManager.unsetDynamicCategory(category); - - // Reply -> Never NULL (Guild Command) - Guild guild = event.getGuild(); - - MessageEmbed embed = Utils.simpleEmbed("Voice Hive Uninitialized", - "The dynamic voice channels are now unset!", Color.GREEN); - - event.replyEmbeds(embed).queue(); - } catch (KeyNotFoundException e) { - LOGGER.debug(method + " : error : " + e.getMessage()); - - // Reply -> Never NULL (Guild Command) - Guild guild = event.getGuild(); - MessageEmbed embed = Utils.simpleEmbed("The current category is not a hive of voice channels!", - "You need to set a dynamic voice channel first!", Color.RED); - event.replyEmbeds(embed).queue(); - } - - LOGGER.debug(method + " : end"); - } - - @ICommand(name = "list", description = "List all dynamic voice channels categories") - @SuppressWarnings({"ConstantConditions", "unused"}) - public static void list(SlashCommandInteractionEvent event) { - String method = new Throwable().getStackTrace()[0].getMethodName(); - LOGGER.debug(method + " : start"); - - long guildId = event.getGuild().getIdLong(); - Guild guild = event.getGuild(); - - List hives = voiceManager.findAllByGuildId(guildId); - - StringBuilder sb = new StringBuilder(); - for (VoiceHive hive : hives) { - VoiceChannel hiveChannel = guild.getVoiceChannelById(hive.getVoiceId()); - Category parent = hiveChannel.getParentCategory(); - - if (hiveChannel == null || parent == null) { - LOGGER.debug(method + " : error : hive channel not found : " + hive.getVoiceId()); - continue; - } - - sb.append(hiveChannel.getParentCategory().getAsMention()) - .append(" : ") - .append(hiveChannel.getAsMention()) - .append("\n"); - } - String message = sb.toString(); - - MessageEmbed embed = Utils.simpleEmbed("Voice Hives", message, Color.GREEN); - event.replyEmbeds(embed).queue(); - - LOGGER.debug(method + " : end"); - } - - @ICommand(name = "config", description = "Configure dynamic voice channels", - permissions = {Permission.ADMINISTRATOR}) - @IArgument(name = "category", description = "Category to configure your dynamic voice chat!", required = true, - type = OptionType.CHANNEL) - @SuppressWarnings({"unused"}) - public static void config(SlashCommandInteractionEvent event) { - String method = new Throwable().getStackTrace()[0].getMethodName(); - LOGGER.debug(method + " : start"); - - // region Verify and Decode - GuildChannelUnion channel = event.getOption("category").getAsChannel(); - - if (channel.getType() != ChannelType.CATEGORY) { - LOGGER.debug(method + " : error : non category : " + channel); - event.reply("You need to pass a category!").queue(); - return; - } - - // endregion - - Category category = channel.asCategory(); - - // Manager (business rule) - Modal configModal = voiceManager.getConfigModal(category, Dynamic.configModal); - - if (configModal == null) { - LOGGER.debug(method + " : error : config modal not found : " + category); - event.reply("This category is not a dynamic voice channel!").queue(); - return; - } - - event.replyModal(configModal).queue(); - LOGGER.debug(method + " : end"); - } - - //endregion - - // region Utils - - @Nullable - private static AudioChannel validateRequest(SlashCommandInteractionEvent event, Member member) { - AudioChannel channel = member.getVoiceState().getChannel(); - - if (channel == null || channel.getType() != ChannelType.VOICE) { - event.reply("You need to be in a temporary voice channel to use this command!").setEphemeral(true).queue(); - return null; - } - - VoiceChannel voiceChannel = (VoiceChannel) channel; - - try { - if (!droneManager.canInteract(voiceChannel, member)) { - event.reply("You are not allowed to use this command in this channel!").setEphemeral(true).queue(); - return null; - } - } catch (KeyNotFoundException e) { - event.reply("You need to be in a temporary voice channel to use this command!!").setEphemeral(true).queue(); - return null; - } - return channel; - } - - // endregion - - // region Discord Modals, Buttons and Menus - - @IButton(id = generateConfigModal) - public static void generateConfig(ButtonInteractionEvent event) { - LOGGER.debug("generateConfig : start"); - String[] args = event.getComponentId().split(":"); - - if (args.length != 2) { - LOGGER.debug("generateConfig : error : invalid component id : " + event.getComponentId()); - return; - } - - long categoryId = Long.parseLong(args[1]); - Category category = event.getGuild().getCategoryById(categoryId); - - if (category == null) { - LOGGER.debug("generateConfig : error : category not found : " + categoryId); - return; - } - - Modal configModal = voiceManager.getConfigModal(category, Dynamic.configModal); - - event.replyModal(configModal).queue(); - } - - @IModal(id = configModal) - @SuppressWarnings({"unused"}) - public static void configModal(ModalInteractionEvent event) { - String method = new Throwable().getStackTrace()[0].getMethodName(); - LOGGER.debug(method + " : start"); - - String strCategoryId = event.getModalId().split(":")[1]; - long categoryId = Long.parseLong(strCategoryId); - VoiceHive voiceHive; - try { - Category category = event.getGuild().getCategoryById(categoryId); - - if (category == null) { - LOGGER.debug(method + " : error : category not found : " + categoryId); - event.reply("Category not found!").setEphemeral(true).queue(); - return; - } - voiceHive = voiceManager.setConfigModal(event, category); - } catch (KeyNotFoundException e) { - event.reply("This category is not a dynamic voice channel!").setEphemeral(true).queue(); - return; - } catch (Exception e) { - LOGGER.debug(method + " : error : " + e.getMessage()); - event.reply("An error occurred while configuring the dynamic voice channel!").setEphemeral(true).queue(); - return; - } - - try { - event.replyEmbeds(voiceHive.show(event.getGuild())).queue(); - } catch (Exception e) { - LOGGER.debug(method + " : error : " + e.getMessage()); - event.reply("update!!").setEphemeral(true).queue(); - } - - LOGGER.debug(method + " : end"); - } - - @IButton(id = droneConfig) - @SuppressWarnings({"unused"}) - public static void droneConfigButton(ButtonInteractionEvent event) { - MessageChannelUnion channel = event.getChannel(); - - Modal modal; - try { - modal = droneManager.checkConfigDrone(event.getGuild(), channel, event.getMember(), droneConfig); - } catch (KeyNotFoundException e) { - event.reply("This channel is not a temporary channel!").queue(); - return; - } catch (MissingPermissionsException e) { - event.reply("You don't have the required permissions to manage this channel!").queue(); - return; - } - event.replyModal(modal).queue(); - } - - @IModal(id = droneConfig) - @SuppressWarnings({"unused"}) - public static void droneConfigModal(ModalInteractionEvent event) { - try { - droneManager.updateDrone(event); - event.reply("Settings Updated!").setEphemeral(true).queue(); - } catch (InvalidInputException e) { - event.reply("Invalid input! You need to pass " + e.getMessage()).setEphemeral(true).queue(); - } catch (NumberFormatException e) { - event.reply("Invalid input! You need to pass a number!").setEphemeral(true).queue(); - } catch (Exception e) { - event.reply("An error occurred while changing the channel!").setEphemeral(true).queue(); - } - } - - @IButton(id = droneHideShow) - @SuppressWarnings({"unused"}) - public static void droneHideShow(ButtonInteractionEvent event) { - MessageChannelUnion channel = event.getChannel(); - Member member = event.getMember(); - - try { - droneManager.toggleDroneVisibility(event.getGuild(), channel, member); - } catch (MissingPermissionsException e) { - event.reply("You don't have the required permissions to manage this channel!").setEphemeral(true).queue(); - return; - } catch (KeyNotFoundException e) { - event.reply("This channel is not a temporary channel!").setEphemeral(true).queue(); - return; - } - event.reply("Drone visibility toggled!").setEphemeral(true).queue(); - } - - @IButton(id = dronePublicPrivate) - @SuppressWarnings({"unused"}) - public static void dronePublicPrivate(ButtonInteractionEvent event) { - MessageChannelUnion channel = event.getChannel(); - Member member = event.getMember(); - - try { - droneManager.toggleDronePublicPrivate(event.getGuild(), channel, member); - } catch (MissingPermissionsException e) { - event.reply("You don't have the required permissions to manage this channel!").setEphemeral(true).queue(); - return; - } catch (KeyNotFoundException e) { - event.reply("This channel is not a temporary channel!").setEphemeral(true).queue(); - return; - } - event.reply("Drone privacy toggled!").setEphemeral(true).queue(); - } - - @IButton(id = dronePermTemp) - @SuppressWarnings({"unused"}) - public static void dronePermTemp(ButtonInteractionEvent event) { - MessageChannelUnion channel = event.getChannel(); - Member member = event.getMember(); - - try { - droneManager.toggleDronePermTemp(event.getGuild(), channel, member); - } catch (MissingPermissionsException e) { - event.reply("You don't have the required permissions to make this channel permanent this channel!").setEphemeral(true).queue(); - return; - } catch (KeyNotFoundException e) { - event.reply("This channel is not a temporary channel!").setEphemeral(true).queue(); - return; - } - event.reply("Drone persistence toggled!").setEphemeral(true).queue(); - } - - @IButton(id = droneClaim) - public static void droneClaim(ButtonInteractionEvent event) { - MessageChannelUnion channel = event.getChannel(); - Member member = event.getMember(); - - try { - droneManager.claimDrone(event.getGuild(), channel, member); - } catch (KeyNotFoundException e) { - event.reply("This channel is not a temporary channel!").setEphemeral(true).queue(); - return; - } catch (OwnerInTheChannelException e) { - event.reply("The owner is in the channel!").setEphemeral(true).queue(); - return; - } catch (NotInTheDroneException e) { - event.reply("You are not in the channel!!!").setEphemeral(true).queue(); - return; - } catch (Exception e) { - LOGGER.error("droneClaim : " + e.getMessage()); - event.reply("An error occurred while claiming the channel!").setEphemeral(true).queue(); - return; - } - event.getMessage().delete().and(event.reply("Now the channel is yours!").setEphemeral(true)).submit(); - } - - //endregion - } - - // endregion - -} diff --git a/src/main/resources/social.properties b/src/main/resources/social.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/social_en_US.properties b/src/main/resources/social_en_US.properties new file mode 100644 index 0000000..f5e1ce6 --- /dev/null +++ b/src/main/resources/social_en_US.properties @@ -0,0 +1,5 @@ +social.twitter.enable.response = The twitter link remapping was enabled +social.twitter.disable.response = The twitter link remapping was disabled + +social.error.missing_permissions = You don't have the necessary permissions to execute this command +social.error.generic = An error occurred while executing this command diff --git a/src/main/resources/social_pt_BR.properties b/src/main/resources/social_pt_BR.properties new file mode 100644 index 0000000..832333b --- /dev/null +++ b/src/main/resources/social_pt_BR.properties @@ -0,0 +1,18 @@ +social.name = social +social.description = Rede Social + +social.twitter.name = twitter +social.twitter.description = Rede Social Twitter (também conhecido como X) + +social.twitter.enable.name = enable +social.twitter.enable.description = Habilitar o remapping de links do twitter para melhoria no embed + +social.twitter.disable.name = disable +social.twitter.disable.description = Desabilitar o remapping de links do twitter para melhoria no embed + +social.twitter.enable.response = O remapping de links do twitter foi habilitado +social.twitter.disable.response = O remapping de links do twitter foi desabilitado + +social.error.missing_permissions = Você não tem as permissões necessárias para executar este comando +social.error.generic = Ocorreu um erro ao executar este comando + diff --git a/src/main/resources/voice.properties b/src/main/resources/voice.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/voice_en_US.properties b/src/main/resources/voice_en_US.properties new file mode 100644 index 0000000..b29a551 --- /dev/null +++ b/src/main/resources/voice_en_US.properties @@ -0,0 +1,83 @@ +# Agent + +agent.name = agent +agent.description = Temporary voice channel to meet user demands. + +agent.invite.name = invite +agent.invite.description = Invitation for the user to join the voice channel. + +agent.kick.name = kick +agent.kick.description = Removes the user from the voice channel. + +agent.invite.response = The user {0} has been invited to the voice channel. +agent.kick.response = The user {0} has been removed from the voice channel. +agent.error.not_in_channel = The user {0} is not in the voice channel. +agent.error.not_in_your_channel = The user {0} is not in your voice channel. + +# Master + +voice.name = voice +voice.description = Manages voice channels. + +voice.master.name = master +voice.master.description = Manage voice channels to oversee other channels. + +voice.master.set.name = set +voice.master.set.description = Adds a master voice channel to manage other channels. + +voice.master.set.category.name = category +voice.master.set.category.description = Category to add the master voice channel. + +voice.master.set.success.title = Master voice channel successfully added. +voice.master.set.success.description = The master voice channel {0} has been successfully added to category {1}. + +voice.master.unset.name = unset +voice.master.unset.description = Removes a master voice channel from a category. + +voice.master.unset.category.name = category +voice.master.unset.category.description = Category to remove the master voice channel. + +voice.master.unset.success = Master voice channel successfully removed from category {0}. + +voice.master.config.name = config +voice.master.config.description = Master voice channel settings. + +voice.master.config.category.name = category +voice.master.config.category.description = Category to configure the master voice channel. + +voice.master.list.name = list +voice.master.list.description = Lists the master voice channels. + +voice.master.list.title = Master Voice Channels + +voice.master.drone.config.success = Master voice channel settings successfully updated. + +voice.agent.hide-show.success = The voice channel visibility was successfully changed. + +voice.agent.public-private.success = The voice channel privacy was successfully changed. + +voice.agent.perm-temp.success = The voice channel persistence state was successfully changed. + +voice.master.claim.success = The voice channel has been successfully claimed. + +voice.error.missing_permissions = You do not have permission to execute this command. + +voice.error.command_not_found = Command not found. + +voice.error.existing_dynamic_category = There is already a master channel for the informed category. + +voice.error.invalid_channel_type = Invalid channel type. + +voice.error.field_length = The field is too long. + +voice.error.invalid_input = Invalid input. + +voice.error.key_not_found = Key not found. + +voice.error.not_in_the_drone = You are not in the voice channel to claim it. + +voice.error.owner_in_the_channel = The owner of the voice channel is in the channel. + +voice.error.url_not_found = URL not found. + +voice.error.generic = An error occurred while executing this command. diff --git a/src/main/resources/voice_pt_BR.properties b/src/main/resources/voice_pt_BR.properties new file mode 100644 index 0000000..bdeaafc --- /dev/null +++ b/src/main/resources/voice_pt_BR.properties @@ -0,0 +1,84 @@ +# Agent + +agent.name = agent +agent.description = Canal de voz temporário para atender as demandas dos usuários. + +agent.invite.name = invite +agent.invite.description = Convite para o usuário entrar no canal de voz. + +agent.kick.name = kick +agent.kick.description = Remove o usuário do canal de voz. + +agent.invite.response = O usuário {0} foi convidado para o canal de voz. +agent.kick.response = O usuário {0} foi removido do canal de voz. +agent.error.not_in_channel = O usuário {0} não está no canal de voz. +agent.error.not_in_your_channel = O usuário {0} não está no seu canal de voz. + +# Master + +voice.name = voice +voice.description = Gerencia os canais de voz. + +voice.master.name = master +voice.master.description = Gerenciar canais de voz para gerenciar outros canais. + +voice.master.set.name = set +voice.master.set.description = Adiciona um canal de voz mestre para gerenciar outros canais. + +voice.master.set.category.name = category +voice.master.set.category.description = Categoria para adicionar o canal de voz mestre. + +voice.master.set.success.title = Canal de voz mestre adicionado com sucesso. +voice.master.set.success.description = O canal de voz mestre {0} foi adicionado com sucesso a categoria {1}. + +voice.master.unset.name = unset +voice.master.unset.description = Remove um canal de voz mestre de uma categoria. + +voice.master.unset.category.name = category +voice.master.unset.category.description = Categoria para remover o canal de voz mestre. + +voice.master.unset.success = Canal de voz mestre removido com sucesso da categoria {0}. + +voice.master.config.name = config +voice.master.config.description = Configurações do canal de voz mestre. + +voice.master.config.category.name = category +voice.master.config.category.description = Categoria para configurar o canal de voz mestre. + +voice.master.list.name = list +voice.master.list.description = Lista os canais de voz mestre. + +voice.master.list.title = Canais de voz mestre + +voice.master.drone.config.success = Configurações do canal de voz mestre atualizadas com sucesso. + +voice.agent.hide-show.success = O canal de voz alterou a visibilidade com sucesso. + +voice.agent.public-private.success = O canal de voz alterou a privacidade com sucesso. + +voice.agent.perm-temp.success = O canal de voz alterou o estado de persistência com sucesso. + +voice.master.claim.success = O canal de voz foi reivindicado com sucesso. + +voice.error.missing_permissions = Você não tem permissão para executar este comando. + +voice.error.command_not_found = Comando não encontrado. + +voice.error.existing_dynamic_category = Já existe um canal mestre para a categoria informada. + +voice.error.invalid_channel_type = Tipo de canal inválido. + +voice.error.field_length = O campo é muito longo. + +voice.error.invalid_input = Entrada inválida. + +voice.error.key_not_found = Chave não encontrada. + +voice.error.not_in_the_drone = Você não está no canal de voz mestre para reivindica-lo. + +voice.error.owner_in_the_channel = O proprietário do canal de voz está no canal. + +voice.error.url_not_found = URL não encontrada. + +voice.error.generic = Ocorreu um erro ao executar este comando. + diff --git a/start-container.sh b/start-container.sh index 7fccd2e..9debda8 100644 --- a/start-container.sh +++ b/start-container.sh @@ -37,7 +37,7 @@ podman run -d \ -e DATABASE_PASSWORD=${DATABASE_PASSWORD:-sa} \ -e JAVA_ARGS=${JAVA_ARGS:--Xmx200M} \ --cpus 0.5 \ - --memory 300M \ + --memory 400M \ --name $CONTAINER_NAME \ --restart always \ --network slirp4netns:allow_host_loopback=true \