├── settings.gradle ├── src └── main │ ├── resources │ ├── messages │ │ ├── leave_messages.txt │ │ ├── status_messages.txt │ │ └── join_messages.txt │ ├── app.properties │ ├── sql_tables │ │ ├── voters.sql │ │ ├── guild_tag_attachments.sql │ │ ├── guild_invites.sql │ │ ├── bot_ignored_members.sql │ │ ├── bot_disabled_channels.sql │ │ ├── snipe_disabled_channels.sql │ │ ├── member_roles.sql │ │ ├── stream_user_events.sql │ │ ├── guild_invite_roles.sql │ │ ├── sessions.sql │ │ ├── self_assignable_role_messages.sql │ │ ├── self_assignable_role_groups.sql │ │ ├── stream_users.sql │ │ ├── self_assignable_roles.sql │ │ ├── reactive_messages.sql │ │ ├── requests.sql │ │ ├── guild_tags.sql │ │ ├── notifications.sql │ │ ├── user_statistics.sql │ │ └── guilds.sql │ └── logback.xml │ ├── java │ └── de │ │ └── kittybot │ │ └── kittybot │ │ ├── utils │ │ ├── annotations │ │ │ └── Ignore.java │ │ ├── PlaceholderUtils.java │ │ ├── Colors.java │ │ ├── ThreadFactoryHelper.java │ │ ├── Utils.java │ │ ├── FileUtils.java │ │ ├── exporters │ │ │ └── DiscordPingExporter.java │ │ ├── EmoteHelper.java │ │ └── MessageUtils.java │ │ ├── objects │ │ ├── enums │ │ │ ├── AnnouncementType.java │ │ │ ├── Environment.java │ │ │ ├── API.java │ │ │ └── Neko.java │ │ ├── music │ │ │ ├── RepeatMode.java │ │ │ └── SearchProvider.java │ │ ├── exceptions │ │ │ ├── OptionParseException.java │ │ │ ├── MissingOptionException.java │ │ │ ├── ModuleNotFoundException.java │ │ │ ├── MissingConfigValuesException.java │ │ │ └── TooManyRequestResponse.java │ │ ├── data │ │ │ ├── Placeholder.java │ │ │ ├── LavalinkNode.java │ │ │ ├── InviteData.java │ │ │ ├── GuildData.java │ │ │ ├── ReactiveMessage.java │ │ │ └── Paginator.java │ │ ├── module │ │ │ └── Module.java │ │ ├── streams │ │ │ ├── twitch │ │ │ │ └── TwitchUser.java │ │ │ ├── BearerToken.java │ │ │ ├── Game.java │ │ │ └── StreamType.java │ │ ├── settings │ │ │ ├── SelfAssignableRole.java │ │ │ ├── SelfAssignableRoleGroup.java │ │ │ ├── Tag.java │ │ │ ├── StreamAnnouncement.java │ │ │ └── Notification.java │ │ └── session │ │ │ └── DashboardSessionController.java │ │ ├── slashcommands │ │ ├── application │ │ │ ├── CommandOptionsHolder.java │ │ │ ├── RunCommand.java │ │ │ ├── RunGuildCommand.java │ │ │ ├── RunnableCommand.java │ │ │ ├── RunnableGuildCommand.java │ │ │ ├── PermissionHolder.java │ │ │ ├── options │ │ │ │ ├── SubCommand.java │ │ │ │ ├── GuildSubCommand.java │ │ │ │ ├── CommandOptionBoolean.java │ │ │ │ ├── CommandOptionInteger.java │ │ │ │ ├── CommandOptionString.java │ │ │ │ ├── CommandOptionLong.java │ │ │ │ ├── CommandOptionFloat.java │ │ │ │ ├── CommandOptionRole.java │ │ │ │ ├── CommandOptionUser.java │ │ │ │ ├── CommandOptionChannel.java │ │ │ │ ├── CommandOptionTime.java │ │ │ │ ├── CommandOptionUrl.java │ │ │ │ ├── CommandOptionRawEmote.java │ │ │ │ ├── CommandOptionEmote.java │ │ │ │ ├── SubBaseCommand.java │ │ │ │ └── SubCommandGroup.java │ │ │ ├── GenericHelpCommand.java │ │ │ ├── CommandOptionType.java │ │ │ ├── CommandOptionChoice.java │ │ │ └── Category.java │ │ └── interaction │ │ │ ├── InteractionOptionsHolder.java │ │ │ ├── response │ │ │ ├── InteractionResponseType.java │ │ │ └── InteractionResponseData.java │ │ │ ├── InteractionType.java │ │ │ ├── GuildInteraction.java │ │ │ └── InteractionData.java │ │ ├── commands │ │ ├── neko │ │ │ ├── HugCommand.java │ │ │ ├── PatCommand.java │ │ │ ├── BiteCommand.java │ │ │ ├── FeedCommand.java │ │ │ ├── LickCommand.java │ │ │ ├── PokeCommand.java │ │ │ ├── SlapCommand.java │ │ │ ├── KissCommand.java │ │ │ ├── CuddleCommand.java │ │ │ ├── TickleCommand.java │ │ │ └── ReactionCommand.java │ │ ├── admin │ │ │ ├── settings │ │ │ │ ├── SnipesCommand.java │ │ │ │ ├── DJRoleCommand.java │ │ │ │ ├── NsfwCommand.java │ │ │ │ ├── snipes │ │ │ │ │ ├── EnableCommand.java │ │ │ │ │ └── ChannelCommand.java │ │ │ │ ├── RoleSaverCommand.java │ │ │ │ ├── AnnouncementChannelCommand.java │ │ │ │ ├── JoinMessageCommand.java │ │ │ │ ├── LeaveMessageCommand.java │ │ │ │ └── LogMessagesCommand.java │ │ │ ├── ignore │ │ │ │ ├── UserDisableCommand.java │ │ │ │ ├── ChannelDisableCommand.java │ │ │ │ ├── user │ │ │ │ │ ├── ListCommand.java │ │ │ │ │ ├── RemoveCommand.java │ │ │ │ │ └── AddCommand.java │ │ │ │ └── channel │ │ │ │ │ ├── AddCommand.java │ │ │ │ │ ├── RemoveCommand.java │ │ │ │ │ └── ListCommand.java │ │ │ ├── DisableCommand.java │ │ │ ├── BanCommand.java │ │ │ ├── SettingsCommand.java │ │ │ └── ban │ │ │ │ ├── ListCommand.java │ │ │ │ └── RemoveCommand.java │ │ ├── dev │ │ │ ├── dev │ │ │ │ └── TestCommand.java │ │ │ └── DevCommand.java │ │ ├── streams │ │ │ ├── StreamsCommand.java │ │ │ └── streams │ │ │ │ ├── MessageCommand.java │ │ │ │ ├── ChannelCommand.java │ │ │ │ ├── ListCommand.java │ │ │ │ ├── AddCommand.java │ │ │ │ └── RemoveCommand.java │ │ ├── roles │ │ │ ├── roles │ │ │ │ ├── GroupsCommand.java │ │ │ │ ├── groups │ │ │ │ │ ├── ListCommand.java │ │ │ │ │ ├── RemoveCommand.java │ │ │ │ │ └── AddCommand.java │ │ │ │ └── RemoveCommand.java │ │ │ ├── RolesCommand.java │ │ │ └── UnassignCommand.java │ │ ├── notification │ │ │ ├── NotificationCommand.java │ │ │ └── notification │ │ │ │ ├── DeleteCommand.java │ │ │ │ └── CreateCommand.java │ │ ├── info │ │ │ ├── DashboardCommand.java │ │ │ ├── PrivacyCommand.java │ │ │ ├── PingCommand.java │ │ │ ├── UptimeCommand.java │ │ │ ├── VoteCommand.java │ │ │ ├── HelpCommand.java │ │ │ ├── AvatarCommand.java │ │ │ └── InfoCommand.java │ │ ├── music │ │ │ ├── SkipCommand.java │ │ │ ├── StopCommand.java │ │ │ ├── PreviousCommand.java │ │ │ ├── ShuffleCommand.java │ │ │ ├── SearchCommand.java │ │ │ ├── HistoryCommand.java │ │ │ ├── VolumeCommand.java │ │ │ ├── PauseCommand.java │ │ │ ├── RepeatCommand.java │ │ │ ├── SeekCommand.java │ │ │ ├── RewindCommand.java │ │ │ └── ForwardCommand.java │ │ ├── tags │ │ │ ├── TagsCommand.java │ │ │ ├── tags │ │ │ │ ├── DeleteCommand.java │ │ │ │ ├── SearchCommand.java │ │ │ │ ├── ListCommand.java │ │ │ │ ├── InfoCommand.java │ │ │ │ ├── UnpublishCommand.java │ │ │ │ └── CreateCommand.java │ │ │ └── TagCommand.java │ │ └── snipe │ │ │ └── SnipeCommand.java │ │ ├── web │ │ ├── bot │ │ │ └── invite │ │ │ │ └── GetBotInviteRoute.java │ │ ├── discord │ │ │ ├── invite │ │ │ │ └── GetDiscordInviteRoute.java │ │ │ └── login │ │ │ │ └── GetDiscordLoginRoute.java │ │ ├── login │ │ │ ├── DeleteLoginRoute.java │ │ │ └── PostLoginRoute.java │ │ ├── guilds │ │ │ ├── guild │ │ │ │ ├── tags │ │ │ │ │ ├── tag │ │ │ │ │ │ ├── DeleteTagRoute.java │ │ │ │ │ │ └── PostTagRoute.java │ │ │ │ │ └── GetTagsRoute.java │ │ │ │ ├── channels │ │ │ │ │ └── GetChannelsRoute.java │ │ │ │ ├── emotes │ │ │ │ │ └── GetEmotesRoute.java │ │ │ │ ├── roles │ │ │ │ │ └── GetRolesRoute.java │ │ │ │ ├── users │ │ │ │ │ └── GetUsersRoute.java │ │ │ │ └── invites │ │ │ │ │ └── GetInvitesRoute.java │ │ │ └── GetAllGuildsRoute.java │ │ ├── shards │ │ │ └── GetShardsRoute.java │ │ ├── info │ │ │ └── GetInfoRoute.java │ │ ├── commands │ │ │ └── GetCommandsRoute.java │ │ └── user │ │ │ └── GetUserInfoRoute.java │ │ ├── modules │ │ ├── ReactiveMessageModule.java │ │ ├── LavalinkModule.java │ │ └── StatusModule.java │ │ └── main │ │ └── Main.java │ └── jooq │ └── de │ └── kittybot │ └── kittybot │ └── jooq │ └── DefaultCatalog.java ├── .github ├── banner.png └── KittyBotBanner.png ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties.example ├── Dockerfile ├── config.json.example └── README.md /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'KittyBot' 2 | -------------------------------------------------------------------------------- /src/main/resources/messages/leave_messages.txt: -------------------------------------------------------------------------------- 1 | ${user}(${user_tag}) sprinted away! -------------------------------------------------------------------------------- /.github/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KittyBot-Org/KittyBot/HEAD/.github/banner.png -------------------------------------------------------------------------------- /.github/KittyBotBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KittyBot-Org/KittyBot/HEAD/.github/KittyBotBanner.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .history/ 2 | .gradle/ 3 | .idea/ 4 | build/ 5 | out/ 6 | config.json 7 | .idea 8 | gradle.properties -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KittyBot-Org/KittyBot/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle.properties.example: -------------------------------------------------------------------------------- 1 | KITTYBOT_DB_HOST= 2 | KITTYBOT_DB_PORT= 3 | KITTYBOT_DB_DATABASE= 4 | KITTYBOT_DB_USER= 5 | KITTYBOT_DB_PASSWORD= 6 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/utils/annotations/Ignore.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.utils.annotations; 2 | 3 | public @interface Ignore{ 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/app.properties: -------------------------------------------------------------------------------- 1 | version=@project.version@ 2 | groupId=@project.groupId@ 3 | artifactId=@project.artifactId@ 4 | buildNumber=@env.BUILD_NUMBER@ 5 | buildTime=@env.BUILD_TIME@ -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/enums/AnnouncementType.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.enums; 2 | 3 | public enum AnnouncementType{ 4 | 5 | START(), 6 | END() 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/messages/status_messages.txt: -------------------------------------------------------------------------------- 1 | watching you 👀 2 | watching ${total_guilds} guilds 👀 3 | watching ${total_users} users 👀 4 | playing with new slash commands 5 | playing JDA 6 | watching JDA 7 | watching Discord 8 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/voters.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS voters( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | user_id BIGINT NOT NULL, 4 | vote_expiry TIMESTAMP NOT NULL, 5 | UNIQUE(user_id) 6 | ); 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/guild_tag_attachments.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS guild_tag_attachments( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | tag_id BIGINT NOT NULL REFERENCES guild_tags(id) ON DELETE CASCADE, 4 | url VARCHAR NOT NULL 5 | ); 6 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/music/RepeatMode.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.music; 2 | 3 | public enum RepeatMode{ 4 | 5 | OFF, 6 | QUEUE, 7 | SONG; 8 | 9 | public String getName(){ 10 | return name().toLowerCase(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/guild_invites.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS guild_invites( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | code VARCHAR(8) NOT NULL UNIQUE, 5 | UNIQUE(guild_id, code) 6 | ); 7 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/CommandOptionsHolder.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application; 2 | 3 | import java.util.List; 4 | 5 | public interface CommandOptionsHolder{ 6 | 7 | List> getOptions(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/bot_ignored_members.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS bot_ignored_members( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | user_id BIGINT NOT NULL, 5 | UNIQUE(guild_id, user_id) 6 | ); 7 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/interaction/InteractionOptionsHolder.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.interaction; 2 | 3 | import java.util.List; 4 | 5 | public interface InteractionOptionsHolder{ 6 | 7 | List getOptions(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/bot_disabled_channels.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS bot_disabled_channels( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | channel_id BIGINT NOT NULL, 5 | UNIQUE(guild_id, channel_id) 6 | ); 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM adoptopenjdk/openjdk11-openj9:alpine 2 | 3 | WORKDIR /home/kittybot 4 | 5 | COPY build/libs/KittyBot-all.jar KittyBot.jar 6 | 7 | RUN apk update && apk upgrade && apk add curl 8 | 9 | ENV JAVA_OPTS="-Xmx1G -XX:+UseG1GC" 10 | 11 | ENTRYPOINT java -jar $JAVA_OPTS KittyBot.jar 12 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/snipe_disabled_channels.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS snipe_disabled_channels( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | channel_id BIGINT NOT NULL, 5 | UNIQUE(guild_id, channel_id) 6 | ); 7 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/member_roles.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS member_roles( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | user_id BIGINT NOT NULL, 5 | role_id BIGINT NOT NULL, 6 | UNIQUE(guild_id, user_id, role_id) 7 | ); -------------------------------------------------------------------------------- /src/main/resources/sql_tables/stream_user_events.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS stream_user_events( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | stream_user_id BIGINT NOT NULL REFERENCES stream_users(id) ON DELETE CASCADE, 4 | event INT NOT NULL, 5 | UNIQUE(stream_user_id, event) 6 | ); 7 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/exceptions/OptionParseException.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.exceptions; 2 | 3 | public class OptionParseException extends RuntimeException{ 4 | 5 | public OptionParseException(String message){ 6 | super(message, null, false, false); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/guild_invite_roles.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS guild_invite_roles( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_invite_id BIGINT NOT NULL REFERENCES guild_invites(id) ON DELETE CASCADE, 4 | role_id BIGINT NOT NULL, 5 | UNIQUE(guild_invite_id, role_id) 6 | ); 7 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/sessions.sql: -------------------------------------------------------------------------------- 1 | create TABLE IF NOT EXISTS sessions( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | user_id BIGINT NOT NULL, 4 | access_token VARCHAR(32) NOT NULL, 5 | refresh_token VARCHAR(32) NOT NULL, 6 | expiration TIMESTAMP NOT NULL, 7 | UNIQUE(user_id) 8 | ); 9 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/self_assignable_role_messages.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS self_assignable_role_messages( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | message_id BIGINT NOT NULL, 5 | UNIQUE(guild_id, message_id) 6 | ); 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/self_assignable_role_groups.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS self_assignable_role_groups( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | name VARCHAR(255) NOT NULL, 5 | max_roles INT NOT NULL DEFAULT(-1), 6 | UNIQUE(guild_id, name) 7 | ); 8 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/HugCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.objects.enums.Neko; 4 | 5 | @SuppressWarnings("unused") 6 | public class HugCommand extends ReactionCommand{ 7 | 8 | public HugCommand(){ 9 | super(Neko.HUG, "Hugs a user", "hugs"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/PatCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.objects.enums.Neko; 4 | 5 | @SuppressWarnings("unused") 6 | public class PatCommand extends ReactionCommand{ 7 | 8 | public PatCommand(){ 9 | super(Neko.PAT, "Pats a user", "pats"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/BiteCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.objects.enums.Neko; 4 | 5 | @SuppressWarnings("unused") 6 | public class BiteCommand extends ReactionCommand{ 7 | 8 | public BiteCommand(){ 9 | super(Neko.BITE, "Bites a user", "bites"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/FeedCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.objects.enums.Neko; 4 | 5 | @SuppressWarnings("unused") 6 | public class FeedCommand extends ReactionCommand{ 7 | 8 | public FeedCommand(){ 9 | super(Neko.FEED, "Feeds a user", "feeds"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/LickCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.objects.enums.Neko; 4 | 5 | @SuppressWarnings("unused") 6 | public class LickCommand extends ReactionCommand{ 7 | 8 | public LickCommand(){ 9 | super(Neko.LICK, "Licks a user", "licks"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/PokeCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.objects.enums.Neko; 4 | 5 | @SuppressWarnings("unused") 6 | public class PokeCommand extends ReactionCommand{ 7 | 8 | public PokeCommand(){ 9 | super(Neko.POKE, "Pokes a user", "pokes"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/SlapCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.objects.enums.Neko; 4 | 5 | @SuppressWarnings("unused") 6 | public class SlapCommand extends ReactionCommand{ 7 | 8 | public SlapCommand(){ 9 | super(Neko.SLAP, "Slaps a user", "slaps"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/RunCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application; 2 | 3 | public abstract class RunCommand extends Command implements RunnableCommand{ 4 | 5 | public RunCommand(String name, String description, Category category){ 6 | super(name, description, category); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/KissCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.objects.enums.Neko; 4 | 5 | @SuppressWarnings("unused") 6 | public class KissCommand extends ReactionCommand{ 7 | 8 | public KissCommand(){ 9 | super(Neko.KISS, "Kisses a user", "kisses"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/CuddleCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.objects.enums.Neko; 4 | 5 | @SuppressWarnings("unused") 6 | public class CuddleCommand extends ReactionCommand{ 7 | 8 | public CuddleCommand(){ 9 | super(Neko.CUDDLE, "Cuddles a user", "cuddles"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/TickleCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.objects.enums.Neko; 4 | 5 | @SuppressWarnings("unused") 6 | public class TickleCommand extends ReactionCommand{ 7 | 8 | public TickleCommand(){ 9 | super(Neko.TICKLE, "Tickles a user", "tickles"); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/exceptions/MissingOptionException.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.exceptions; 2 | 3 | public class MissingOptionException extends RuntimeException{ 4 | 5 | public MissingOptionException(String name, Class clazz){ 6 | super("Option `" + name + "` of type `" + clazz.getSimpleName() + "` is missing"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/RunGuildCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application; 2 | 3 | public abstract class RunGuildCommand extends Command implements RunnableGuildCommand{ 4 | 5 | public RunGuildCommand(String name, String description, Category category){ 6 | super(name, description, category); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/RunnableCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application; 2 | 3 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 4 | import de.kittybot.kittybot.slashcommands.interaction.Options; 5 | 6 | public interface RunnableCommand{ 7 | 8 | void run(Options options, Interaction ia); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/RunnableGuildCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application; 2 | 3 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 4 | import de.kittybot.kittybot.slashcommands.interaction.Options; 5 | 6 | public interface RunnableGuildCommand{ 7 | 8 | void run(Options options, GuildInteraction ia); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/stream_users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS stream_users( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | user_id BIGINT NOT NULL, 5 | user_name VARCHAR(32) NOT NULL, 6 | stream_type INT NOT NULL, 7 | is_live BOOLEAN NOT NULL DEFAULT(false), 8 | UNIQUE(guild_id, user_id) 9 | ); 10 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/self_assignable_roles.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS self_assignable_roles( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | group_id BIGINT NOT NULL REFERENCES self_assignable_role_groups(id) ON DELETE CASCADE, 4 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 5 | role_id BIGINT NOT NULL, 6 | emote_id BIGINT NOT NULL, 7 | UNIQUE(group_id, role_id) 8 | ); 9 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/settings/SnipesCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.settings; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.options.SubCommandGroup; 4 | 5 | public class SnipesCommand extends SubCommandGroup{ 6 | 7 | public SnipesCommand(){ 8 | super("snipes", "Used to disable snipes"); 9 | addOptions( 10 | 11 | ); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/exceptions/ModuleNotFoundException.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.exceptions; 2 | 3 | import de.kittybot.kittybot.objects.module.Module; 4 | 5 | public class ModuleNotFoundException extends RuntimeException{ 6 | 7 | public ModuleNotFoundException(Class clazz){ 8 | super("Module '" + clazz.getName() + "' not found"); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/exceptions/MissingConfigValuesException.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.exceptions; 2 | 3 | import java.util.Set; 4 | 5 | public class MissingConfigValuesException extends Exception{ 6 | 7 | public MissingConfigValuesException(Set missingKeys){ 8 | super("Following config keys are missing: \"" + String.join(", ", missingKeys) + "\""); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/reactive_messages.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS reactive_messages( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | user_id BIGINT NOT NULL, 5 | channel_id BIGINT NOT NULL, 6 | message_id BIGINT NOT NULL, 7 | command_path VARCHAR(255) NOT NULL, 8 | allowed BIGINT NOT NULL DEFAULT(-1) 9 | ); 10 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/PermissionHolder.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application; 2 | 3 | import net.dv8tion.jda.api.Permission; 4 | 5 | import java.util.Set; 6 | 7 | public interface PermissionHolder{ 8 | 9 | void devOnly(); 10 | 11 | boolean isDevOnly(); 12 | 13 | void addPermissions(Permission... permissions); 14 | 15 | Set getPermissions(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/SubCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.RunnableCommand; 4 | 5 | public abstract class SubCommand extends SubBaseCommand implements RunnableCommand{ 6 | 7 | public SubCommand(String name, String description){ 8 | super(name, description); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/requests.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS requests( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | user_id BIGINT NOT NULL, 5 | title VARCHAR(64) NOT NULL, 6 | body TEXT NOT NULL, 7 | answered BOOLEAN NOT NULL, 8 | accepted BOOLEAN NOT NULL, 9 | creation_at TIMESTAMP NOT NULL DEFAULT(current_timestamp) 10 | ); 11 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/GuildSubCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.RunnableGuildCommand; 4 | 5 | public abstract class GuildSubCommand extends SubBaseCommand implements RunnableGuildCommand{ 6 | 7 | public GuildSubCommand(String name, String description){ 8 | super(name, description); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/data/Placeholder.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.data; 2 | 3 | public class Placeholder{ 4 | 5 | private final String name, value; 6 | 7 | public Placeholder(String name, String value){ 8 | this.name = name; 9 | this.value = value; 10 | } 11 | 12 | public String getName(){ 13 | return "${" + this.name + "}"; 14 | } 15 | 16 | public String getValue(){ 17 | return this.value; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/utils/PlaceholderUtils.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.utils; 2 | 3 | import de.kittybot.kittybot.objects.data.Placeholder; 4 | 5 | public class PlaceholderUtils{ 6 | 7 | public static String replacePlaceholders(String message, Placeholder... placeholders){ 8 | for(var placeholder : placeholders){ 9 | message = message.replace(placeholder.getName(), placeholder.getValue()); 10 | } 11 | return message; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/dev/dev/TestCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.dev.dev; 2 | 3 | import de.kittybot.kittybot.commands.dev.dev.test.ResponseCommand; 4 | import de.kittybot.kittybot.slashcommands.application.options.SubCommandGroup; 5 | 6 | public class TestCommand extends SubCommandGroup{ 7 | 8 | public TestCommand(){ 9 | super("test", "Some test commands"); 10 | addOptions( 11 | new ResponseCommand() 12 | ); 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/bot/invite/GetBotInviteRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.bot.invite; 2 | 3 | import de.kittybot.kittybot.utils.Config; 4 | import io.javalin.http.Context; 5 | import io.javalin.http.Handler; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public class GetBotInviteRoute implements Handler{ 9 | 10 | @Override 11 | public void handle(@NotNull Context ctx){ 12 | ctx.redirect(Config.BOT_INVITE_URL); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/guild_tags.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS guild_tags( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | name VARCHAR(64) NOT NULL, 4 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 5 | user_id BIGINT NOT NULL, 6 | content TEXT NOT NULL, 7 | created_at TIMESTAMP NOT NULL DEFAULT(current_timestamp), 8 | updated_at TIMESTAMP, 9 | command_id BIGINT NOT NULL DEFAULT(-1), 10 | UNIQUE(name, guild_id) 11 | ); 12 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/utils/Colors.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.utils; 2 | 3 | import java.awt.Color; 4 | 5 | public class Colors{ 6 | 7 | public static final Color KITTYBOT_BLUE = new Color(76, 80, 193); 8 | 9 | public static final int KITTYBOT_BLUE_INT = 0x5c5fea; 10 | 11 | public static final Color TWITCH_PURPLE = new Color(89, 54, 149); 12 | 13 | public static final Color NOTIFICATION = new Color(250, 166, 26); 14 | 15 | private Colors(){} 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/exceptions/TooManyRequestResponse.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.exceptions; 2 | 3 | import io.javalin.http.HttpResponseException; 4 | import org.eclipse.jetty.http.HttpStatus; 5 | 6 | import java.util.HashMap; 7 | 8 | public class TooManyRequestResponse extends HttpResponseException{ 9 | 10 | public TooManyRequestResponse(String message){ 11 | super(HttpStatus.TOO_MANY_REQUESTS_429, message, new HashMap<>()); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/interaction/response/InteractionResponseType.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.interaction.response; 2 | 3 | public enum InteractionResponseType{ 4 | 5 | PONG(1), 6 | CHANNEL_MESSAGE_WITH_SOURCE(4), 7 | DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE(5); 8 | 9 | private final int type; 10 | 11 | InteractionResponseType(int type){ 12 | this.type = type; 13 | } 14 | 15 | public int getType(){ 16 | return this.type; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/discord/invite/GetDiscordInviteRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.discord.invite; 2 | 3 | import de.kittybot.kittybot.utils.Config; 4 | import io.javalin.http.Context; 5 | import io.javalin.http.Handler; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public class GetDiscordInviteRoute implements Handler{ 9 | 10 | @Override 11 | public void handle(@NotNull Context ctx){ 12 | ctx.redirect(Config.SUPPORT_GUILD_INVITE_URL); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/notifications.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS notifications( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | user_id BIGINT NOT NULL, 5 | channel_id BIGINT NOT NULL, 6 | message_id BIGINT NOT NULL, 7 | content TEXT NOT NULL, 8 | created_at TIMESTAMP NOT NULL DEFAULT(current_timestamp), 9 | notification_time TIMESTAMP NOT NULL 10 | ); 11 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/enums/Environment.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.enums; 2 | 3 | public enum Environment{ 4 | 5 | PRODUCTION, 6 | DEVELOPMENT; 7 | 8 | public static boolean is(Environment environment){ 9 | return getCurrent() == environment; 10 | } 11 | 12 | public static Environment getCurrent(){ 13 | try{ 14 | var env = System.getenv("ENV"); 15 | if(env != null){ 16 | return valueOf(env); 17 | } 18 | } 19 | catch(IllegalArgumentException ignored){ 20 | } 21 | return DEVELOPMENT; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/module/Module.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.module; 2 | 3 | import net.dv8tion.jda.api.hooks.ListenerAdapter; 4 | 5 | import java.util.Set; 6 | 7 | public abstract class Module extends ListenerAdapter{ 8 | 9 | protected Modules modules; 10 | 11 | public Module init(Modules modules){ 12 | this.modules = modules; 13 | return this; 14 | } 15 | 16 | public Set> getDependencies(){ 17 | return null; 18 | } 19 | 20 | protected void onEnable(){} 21 | 22 | protected void onDisable(){} 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/streams/twitch/TwitchUser.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.streams.twitch; 2 | 3 | import net.dv8tion.jda.api.utils.data.DataObject; 4 | 5 | public class TwitchUser{ 6 | 7 | private final long id; 8 | private final String displayName; 9 | 10 | public TwitchUser(DataObject json){ 11 | this.id = json.getLong("id"); 12 | this.displayName = json.getString("display_name"); 13 | } 14 | 15 | public long getId(){ 16 | return this.id; 17 | } 18 | 19 | public String getDisplayName(){ 20 | return this.displayName; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/user_statistics.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS user_statistics( 2 | id BIGSERIAL PRIMARY KEY NOT NULL, 3 | guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE, 4 | user_id BIGINT NOT NULL, 5 | xp INT NOT NULL DEFAULT(0), 6 | level INT NOT NULL DEFAULT(0), 7 | bot_calls INT NOT NULL DEFAULT(0), 8 | voice_time INT NOT NULL DEFAULT(0), 9 | message_count INT NOT NULL DEFAULT(0), 10 | emote_count INT NOT NULL DEFAULT(0), 11 | last_active TIMESTAMP NOT NULL DEFAULT(current_timestamp) 12 | ); 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/streams/BearerToken.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.streams; 2 | 3 | import java.time.Instant; 4 | 5 | public class BearerToken{ 6 | 7 | private final String accessToken; 8 | private final long expires; 9 | 10 | public BearerToken(String accessToken, long expiresIn){ 11 | this.accessToken = accessToken; 12 | this.expires = Instant.now().getEpochSecond() + expiresIn; 13 | } 14 | 15 | public String getAccessToken(){ 16 | return "Bearer " + this.accessToken; 17 | } 18 | 19 | public boolean isExpired(){ 20 | return Instant.now().getEpochSecond() >= expires; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/interaction/InteractionType.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.interaction; 2 | 3 | public enum InteractionType{ 4 | 5 | PING(1), 6 | APPLICATION_COMMAND(2); 7 | 8 | private final int type; 9 | 10 | InteractionType(int type){ 11 | this.type = type; 12 | } 13 | 14 | public static InteractionType get(int type){ 15 | if(type == 1){ 16 | return PING; 17 | } 18 | else if(type == 2){ 19 | return APPLICATION_COMMAND; 20 | } 21 | throw new IllegalArgumentException("Unknown InteractionType: " + type + " provided"); 22 | } 23 | 24 | public int getType(){ 25 | return this.type; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/streams/StreamsCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.streams; 2 | 3 | import de.kittybot.kittybot.commands.streams.streams.*; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.Command; 6 | 7 | @SuppressWarnings("unused") 8 | public class StreamsCommand extends Command{ 9 | 10 | public StreamsCommand(){ 11 | super("streams", "Used to configure stream announcements", Category.ANNOUNCEMENT); 12 | addOptions( 13 | new AddCommand(), 14 | new RemoveCommand(), 15 | new ListCommand(), 16 | new MessageCommand(), 17 | new ChannelCommand() 18 | ); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/GenericHelpCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.options.SubCommand; 4 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 5 | import de.kittybot.kittybot.slashcommands.interaction.Options; 6 | 7 | public class GenericHelpCommand extends SubCommand{ 8 | 9 | private final String help; 10 | 11 | public GenericHelpCommand(String help){ 12 | super("help", "Send you a detailed help messages"); 13 | this.help = help; 14 | } 15 | 16 | @Override 17 | public void run(Options options, Interaction ia){ 18 | ia.reply(this.help); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/ignore/UserDisableCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.ignore; 2 | 3 | import de.kittybot.kittybot.commands.admin.ignore.user.AddCommand; 4 | import de.kittybot.kittybot.commands.admin.ignore.user.ListCommand; 5 | import de.kittybot.kittybot.commands.admin.ignore.user.RemoveCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.SubCommandGroup; 7 | 8 | public class UserDisableCommand extends SubCommandGroup{ 9 | 10 | public UserDisableCommand(){ 11 | super("users", "Used to list/ignore/unignore a user"); 12 | addOptions( 13 | new AddCommand(), 14 | new RemoveCommand(), 15 | new ListCommand() 16 | ); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/CommandOptionType.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application; 2 | 3 | import java.util.Arrays; 4 | 5 | public enum CommandOptionType{ 6 | 7 | SUB_COMMAND(1), 8 | SUB_COMMAND_GROUP(2), 9 | STRING(3), 10 | INTEGER(4), 11 | BOOLEAN(5), 12 | USER(6), 13 | CHANNEL(7), 14 | ROLE(8), 15 | UNKNOWN(0); 16 | 17 | private final int type; 18 | 19 | CommandOptionType(int type){ 20 | this.type = type; 21 | } 22 | 23 | public static CommandOptionType get(int type){ 24 | return Arrays.stream(values()).filter(t -> t.getType() == type).findFirst().orElse(null); 25 | } 26 | 27 | public int getType(){ 28 | return this.type; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/ignore/ChannelDisableCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.ignore; 2 | 3 | import de.kittybot.kittybot.commands.admin.ignore.channel.AddCommand; 4 | import de.kittybot.kittybot.commands.admin.ignore.channel.ListCommand; 5 | import de.kittybot.kittybot.commands.admin.ignore.channel.RemoveCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.SubCommandGroup; 7 | 8 | public class ChannelDisableCommand extends SubCommandGroup{ 9 | 10 | public ChannelDisableCommand(){ 11 | super("channels", "Used to list/ignore/unignore a channel"); 12 | addOptions( 13 | new AddCommand(), 14 | new RemoveCommand(), 15 | new ListCommand() 16 | ); 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/utils/ThreadFactoryHelper.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.concurrent.ThreadFactory; 8 | 9 | public class ThreadFactoryHelper implements ThreadFactory{ 10 | 11 | private static final Logger LOG = LoggerFactory.getLogger(ThreadFactoryHelper.class); 12 | 13 | @Override 14 | public Thread newThread(@NotNull Runnable r){ 15 | var thread = new Thread(r, "KittyBot Scheduler"); 16 | thread.setDaemon(true); 17 | thread.setUncaughtExceptionHandler((t, e) -> LOG.error("Caught an unexpected Exception in scheduler", e)); 18 | return thread; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/roles/roles/GroupsCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.roles.roles; 2 | 3 | import de.kittybot.kittybot.commands.roles.roles.groups.AddCommand; 4 | import de.kittybot.kittybot.commands.roles.roles.groups.ListCommand; 5 | import de.kittybot.kittybot.commands.roles.roles.groups.RemoveCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.SubCommandGroup; 7 | 8 | @SuppressWarnings("unused") 9 | public class GroupsCommand extends SubCommandGroup{ 10 | 11 | public GroupsCommand(){ 12 | super("groups", "Used to configure self assignable role groups"); 13 | addOptions( 14 | new AddCommand(), 15 | new RemoveCommand(), 16 | new ListCommand() 17 | ); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/enums/API.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.enums; 2 | 3 | import de.kittybot.kittybot.utils.Config; 4 | 5 | public enum API{ 6 | 7 | // other 8 | PURR_BOT("purr bot", "https://purrbot.site/api/img/%s/%s/%s"), 9 | HASTEBIN("hastebin", Config.HASTEBIN_URL), 10 | GOOGLE_TRANSLATE_API("google translate api", "https://translate.google.com/translate_a/single?client=gtx&sl=%s&tl=%s&dt=t&q=%s&ie=UTF-8&oe=UTF-8"); 11 | 12 | private final String name; 13 | private final String url; 14 | 15 | API(final String name, final String url){ 16 | this.name = name; 17 | this.url = url; 18 | } 19 | 20 | public String getName(){ 21 | return this.name; 22 | } 23 | 24 | public String getUrl(){ 25 | return this.url; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/login/DeleteLoginRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.login; 2 | 3 | import de.kittybot.kittybot.modules.DashboardSessionModule; 4 | import de.kittybot.kittybot.modules.WebModule; 5 | import de.kittybot.kittybot.objects.module.Modules; 6 | import io.javalin.http.Context; 7 | import io.javalin.http.Handler; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public class DeleteLoginRoute implements Handler{ 11 | 12 | private final Modules modules; 13 | 14 | public DeleteLoginRoute(Modules modules){ 15 | this.modules = modules; 16 | } 17 | 18 | @Override 19 | public void handle(@NotNull Context ctx){ 20 | this.modules.get(DashboardSessionModule.class).delete(this.modules.get(WebModule.class).getUserId(ctx)); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/DisableCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin; 2 | 3 | import de.kittybot.kittybot.commands.admin.ignore.ChannelDisableCommand; 4 | import de.kittybot.kittybot.commands.admin.ignore.UserDisableCommand; 5 | import de.kittybot.kittybot.slashcommands.application.Category; 6 | import de.kittybot.kittybot.slashcommands.application.Command; 7 | import net.dv8tion.jda.api.Permission; 8 | 9 | @SuppressWarnings("unused") 10 | public class DisableCommand extends Command{ 11 | 12 | public DisableCommand(){ 13 | super("disable", "Used to disable users or channels", Category.ADMIN); 14 | addOptions( 15 | new UserDisableCommand(), 16 | new ChannelDisableCommand() 17 | ); 18 | addPermissions(Permission.ADMINISTRATOR); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/BanCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin; 2 | 3 | import de.kittybot.kittybot.commands.admin.ban.AddCommand; 4 | import de.kittybot.kittybot.commands.admin.ban.ListCommand; 5 | import de.kittybot.kittybot.commands.admin.ban.RemoveCommand; 6 | import de.kittybot.kittybot.slashcommands.application.Category; 7 | import de.kittybot.kittybot.slashcommands.application.Command; 8 | import net.dv8tion.jda.api.Permission; 9 | 10 | @SuppressWarnings("unused") 11 | public class BanCommand extends Command{ 12 | 13 | public BanCommand(){ 14 | super("ban", "Bans a member", Category.ADMIN); 15 | addOptions( 16 | new AddCommand(), 17 | new RemoveCommand(), 18 | new ListCommand() 19 | ); 20 | addPermissions(Permission.BAN_MEMBERS); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/dev/DevCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.dev; 2 | 3 | import de.kittybot.kittybot.commands.dev.dev.DeployCommand; 4 | import de.kittybot.kittybot.commands.dev.dev.PresenceCommand; 5 | import de.kittybot.kittybot.commands.dev.dev.RemoveCommand; 6 | import de.kittybot.kittybot.commands.dev.dev.TestCommand; 7 | import de.kittybot.kittybot.slashcommands.application.Category; 8 | import de.kittybot.kittybot.slashcommands.application.Command; 9 | 10 | @SuppressWarnings("unused") 11 | public class DevCommand extends Command{ 12 | 13 | public DevCommand(){ 14 | super("dev", "Collection of some dev commands", Category.DEV); 15 | addOptions( 16 | new DeployCommand(), 17 | new RemoveCommand(), 18 | new TestCommand(), 19 | new PresenceCommand() 20 | ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/music/SearchProvider.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.music; 2 | 3 | import java.util.Arrays; 4 | 5 | public enum SearchProvider{ 6 | 7 | YOUTUBE("youtube", "yt"), 8 | SPOTIFY("spotify", "sp"), 9 | SOUNDCLOUD("soundcloud", "sc"); 10 | 11 | private final String name, shortName; 12 | 13 | SearchProvider(String name, String shortName){ 14 | this.name = name; 15 | this.shortName = shortName; 16 | } 17 | 18 | public static SearchProvider getByShortname(String shortName){ 19 | return Arrays.stream(values()).filter(searchProvider -> searchProvider.shortName.equalsIgnoreCase(shortName)).findFirst().orElse(null); 20 | } 21 | 22 | public String getName(){ 23 | return this.name; 24 | } 25 | 26 | public String getShortName(){ 27 | return this.shortName; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionBoolean.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | 7 | public class CommandOptionBoolean extends CommandOption{ 8 | 9 | public CommandOptionBoolean(String name, String description){ 10 | super(CommandOptionType.BOOLEAN, name, description); 11 | } 12 | 13 | public Boolean parseValue(Object value){ 14 | try{ 15 | return (boolean) value; 16 | } 17 | catch(ClassCastException e){ 18 | throw new OptionParseException("Failed to parse " + value + " as true/false"); 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionInteger.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | 7 | public class CommandOptionInteger extends CommandOption{ 8 | 9 | public CommandOptionInteger(String name, String description){ 10 | super(CommandOptionType.INTEGER, name, description); 11 | } 12 | 13 | @Override 14 | public Integer parseValue(Object value){ 15 | try{ 16 | return (int) value; 17 | } 18 | catch(ClassCastException e){ 19 | throw new OptionParseException("Failed to parse " + value + " as integer"); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionString.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | 7 | public class CommandOptionString extends CommandOption{ 8 | 9 | public CommandOptionString(String name, String description){ 10 | super(CommandOptionType.STRING, name, description); 11 | } 12 | 13 | @Override 14 | public String parseValue(Object value){ 15 | try{ 16 | return (String) value; 17 | } 18 | catch(ClassCastException e){ 19 | throw new OptionParseException("Failed to parse " + value + " as string"); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/notification/NotificationCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.notification; 2 | 3 | import de.kittybot.kittybot.commands.notification.notification.CreateCommand; 4 | import de.kittybot.kittybot.commands.notification.notification.DeleteCommand; 5 | import de.kittybot.kittybot.commands.notification.notification.ListCommand; 6 | import de.kittybot.kittybot.slashcommands.application.Category; 7 | import de.kittybot.kittybot.slashcommands.application.Command; 8 | 9 | @SuppressWarnings("unused") 10 | public class NotificationCommand extends Command{ 11 | 12 | public NotificationCommand(){ 13 | super("notification", "Creates/deletes/lists notifications", Category.NOTIFICATION); 14 | addOptions( 15 | new CreateCommand(), 16 | new DeleteCommand(), 17 | new ListCommand() 18 | ); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/data/LavalinkNode.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.data; 2 | 3 | import net.dv8tion.jda.api.utils.data.DataObject; 4 | 5 | public class LavalinkNode{ 6 | 7 | private final String host, protocol; 8 | private final int port; 9 | private final String password; 10 | 11 | public LavalinkNode(DataObject node){ 12 | this.host = node.getString("host", null); 13 | this.protocol = node.getString("protocol", "ws"); 14 | this.port = node.getInt("port", -1); 15 | this.password = node.getString("password", null); 16 | } 17 | 18 | public String getHost(){ 19 | return this.host; 20 | } 21 | 22 | public String getProtocol(){ 23 | return this.protocol; 24 | } 25 | 26 | public int getPort(){ 27 | return this.port; 28 | } 29 | 30 | public String getPassword(){ 31 | return this.password; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionLong.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | 7 | public class CommandOptionLong extends CommandOption{ 8 | 9 | public CommandOptionLong(String name, String description){ 10 | super(CommandOptionType.STRING, name, description); 11 | } 12 | 13 | @Override 14 | public Long parseValue(Object value){ 15 | try{ 16 | return Long.parseLong((String) value); 17 | } 18 | catch(ClassCastException | NumberFormatException e){ 19 | throw new OptionParseException("Failed to parse " + value + " as long"); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionFloat.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | 7 | public class CommandOptionFloat extends CommandOption{ 8 | 9 | public CommandOptionFloat(String name, String description){ 10 | super(CommandOptionType.STRING, name, description); 11 | } 12 | 13 | @Override 14 | public Float parseValue(Object value){ 15 | try{ 16 | return Float.parseFloat((String) value); 17 | } 18 | catch(ClassCastException | NumberFormatException e){ 19 | throw new OptionParseException("Failed to parse " + value + " as float"); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/info/DashboardCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.info; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.Category; 4 | import de.kittybot.kittybot.slashcommands.application.RunCommand; 5 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 6 | import de.kittybot.kittybot.slashcommands.interaction.Options; 7 | import de.kittybot.kittybot.utils.Config; 8 | import de.kittybot.kittybot.utils.MessageUtils; 9 | 10 | @SuppressWarnings("unused") 11 | public class DashboardCommand extends RunCommand{ 12 | 13 | public DashboardCommand(){ 14 | super("dashboard", "Shows you our dashboard", Category.INFORMATION); 15 | } 16 | 17 | @Override 18 | public void run(Options options, Interaction ia){ 19 | ia.reply("You can find our dashboard " + MessageUtils.maskLink("here", Config.ORIGIN_URL)); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/info/PrivacyCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.info; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.Category; 4 | import de.kittybot.kittybot.slashcommands.application.RunCommand; 5 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 6 | import de.kittybot.kittybot.slashcommands.interaction.Options; 7 | import de.kittybot.kittybot.utils.Config; 8 | import de.kittybot.kittybot.utils.MessageUtils; 9 | 10 | @SuppressWarnings("unused") 11 | public class PrivacyCommand extends RunCommand{ 12 | 13 | public PrivacyCommand(){ 14 | super("privacy", "Gives you a link to our privacy policy", Category.INFORMATION); 15 | } 16 | 17 | @Override 18 | public void run(Options options, Interaction ia){ 19 | ia.reply("You can find our privacy policy " + MessageUtils.maskLink("here", Config.ORIGIN_URL + "/privacy")); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionRole.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | 7 | public class CommandOptionRole extends CommandOption{ 8 | 9 | public CommandOptionRole(String name, String description){ 10 | super(CommandOptionType.ROLE, name, description); 11 | } 12 | 13 | @Override 14 | public Long parseValue(Object value){ 15 | try{ 16 | return value instanceof Long ? (Long) value : Long.parseLong((String) value); 17 | } 18 | catch(ClassCastException | NumberFormatException e){ 19 | throw new OptionParseException("Failed to parse " + value + " as role"); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionUser.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | 7 | public class CommandOptionUser extends CommandOption{ 8 | 9 | public CommandOptionUser(String name, String description){ 10 | super(CommandOptionType.USER, name, description); 11 | } 12 | 13 | @Override 14 | public Long parseValue(Object value){ 15 | try{ 16 | return value instanceof Long ? (Long) value : Long.parseLong((String) value); 17 | } 18 | catch(ClassCastException | NumberFormatException e){ 19 | throw new OptionParseException("Failed to parse " + value + " as user"); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/streams/Game.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.streams; 2 | 3 | import java.net.URLEncoder; 4 | import java.nio.charset.StandardCharsets; 5 | 6 | public class Game{ 7 | 8 | private final int id; 9 | private final String name; 10 | 11 | public Game(int id, String name){ 12 | this.id = id; 13 | this.name = name; 14 | } 15 | 16 | public static Game getUnknown(){ 17 | return new Game(0, "unknown"); 18 | } 19 | 20 | public int getId(){ 21 | return this.id; 22 | } 23 | 24 | public String getName(){ 25 | return this.name; 26 | } 27 | 28 | public String getThumbnailUrl(int width, int height){ 29 | // WHATA FUCK GIMME %20 INSTEAD OF + 30 | return "https://static-cdn.jtvnw.net/ttv-boxart/" + URLEncoder.encode(this.name, StandardCharsets.UTF_8).replace("+", "%20") + "-" + width + "x" + height + ".jpg?v=" + System.currentTimeMillis(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/SettingsCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin; 2 | 3 | import de.kittybot.kittybot.commands.admin.settings.*; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.Command; 6 | import net.dv8tion.jda.api.Permission; 7 | 8 | @SuppressWarnings("unused") 9 | public class SettingsCommand extends Command{ 10 | 11 | public SettingsCommand(){ 12 | super("settings", "Let's you see/change settings", Category.ADMIN); 13 | addOptions( 14 | new ListCommand(), 15 | new DJRoleCommand(), 16 | new AnnouncementChannelCommand(), 17 | new JoinMessageCommand(), 18 | new LeaveMessageCommand(), 19 | new NsfwCommand(), 20 | new LogMessagesCommand(), 21 | new SnipesCommand(), 22 | new RoleSaverCommand() 23 | ); 24 | addPermissions(Permission.ADMINISTRATOR); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionChannel.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | 7 | public class CommandOptionChannel extends CommandOption{ 8 | 9 | public CommandOptionChannel(String name, String description){ 10 | super(CommandOptionType.CHANNEL, name, description); 11 | } 12 | 13 | @Override 14 | public Long parseValue(Object value){ 15 | try{ 16 | return value instanceof Long ? (Long) value : Long.parseLong((String) value); 17 | } 18 | catch(ClassCastException | NumberFormatException e){ 19 | throw new OptionParseException("Failed to parse " + value + " as channel"); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/guilds/guild/tags/tag/DeleteTagRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.guilds.guild.tags.tag; 2 | 3 | import de.kittybot.kittybot.modules.TagsModule; 4 | import de.kittybot.kittybot.modules.WebModule; 5 | import de.kittybot.kittybot.objects.module.Modules; 6 | import io.javalin.http.Context; 7 | import io.javalin.http.Handler; 8 | import io.javalin.http.InternalServerErrorResponse; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class DeleteTagRoute implements Handler{ 12 | 13 | private final Modules modules; 14 | 15 | public DeleteTagRoute(Modules modules){ 16 | this.modules = modules; 17 | } 18 | 19 | @Override 20 | public void handle(@NotNull Context ctx){ 21 | if(!this.modules.get(TagsModule.class).delete(this.modules.get(WebModule.class).getTagId(ctx))){ 22 | throw new InternalServerErrorResponse("Error while deleting tag"); 23 | } 24 | WebModule.accepted(ctx); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionTime.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | import de.kittybot.kittybot.utils.TimeUtils; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | public class CommandOptionTime extends CommandOption{ 11 | 12 | public CommandOptionTime(String name, String description){ 13 | super(CommandOptionType.STRING, name, description); 14 | } 15 | 16 | @Override 17 | public LocalDateTime parseValue(Object value){ 18 | try{ 19 | return TimeUtils.parse((String) value); 20 | } 21 | catch(ClassCastException ignored){ 22 | } 23 | throw new OptionParseException("Failed to parse " + value + " as time"); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionUrl.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | 7 | import java.net.MalformedURLException; 8 | import java.net.URL; 9 | 10 | public class CommandOptionUrl extends CommandOption{ 11 | 12 | public CommandOptionUrl(String name, String description){ 13 | super(CommandOptionType.STRING, name, description); 14 | } 15 | 16 | @Override 17 | public String parseValue(Object value){ 18 | try{ 19 | var url = (String) value; 20 | new URL(url); 21 | return url; 22 | } 23 | catch(ClassCastException | MalformedURLException e){ 24 | throw new OptionParseException("Failed to parse " + value + " as url"); 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/data/InviteData.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.data; 2 | 3 | import net.dv8tion.jda.api.entities.Invite; 4 | 5 | public class InviteData{ 6 | 7 | private final long guildId, userId; 8 | private final String code; 9 | private int uses; 10 | 11 | public InviteData(Invite invite){ 12 | this.guildId = invite.getGuild().getIdLong(); 13 | var inviter = invite.getInviter(); 14 | if(inviter != null){ 15 | this.userId = inviter.getIdLong(); 16 | } 17 | else{ 18 | this.userId = -1L; 19 | } 20 | this.code = invite.getCode(); 21 | this.uses = invite.getUses(); 22 | } 23 | 24 | public long getGuildId(){ 25 | return this.guildId; 26 | } 27 | 28 | public long getUserId(){ 29 | return this.userId; 30 | } 31 | 32 | public String getCode(){ 33 | return this.code; 34 | } 35 | 36 | public int getUses(){ 37 | return this.uses; 38 | } 39 | 40 | public void used(){ 41 | this.uses++; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/settings/DJRoleCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.settings; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionRole; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class DJRoleCommand extends GuildSubCommand{ 10 | 11 | public DJRoleCommand(){ 12 | super("djrole", "Sets the dj role"); 13 | addOptions( 14 | new CommandOptionRole("role", "The new dj role").required() 15 | ); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var role = options.getRole("role"); 21 | ia.get(SettingsModule.class).setDjRoleId(ia.getGuildId(), role.getIdLong()); 22 | ia.reply("DJ Role set to: " + role.getAsMention()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/data/GuildData.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.data; 2 | 3 | import com.jagrosh.jdautilities.oauth2.entities.OAuth2Guild; 4 | import net.dv8tion.jda.api.entities.Guild; 5 | 6 | public class GuildData{ 7 | 8 | private final long id; 9 | private final String name, iconUrl; 10 | 11 | public GuildData(Guild guild){ 12 | this(guild.getIdLong(), guild.getName(), guild.getIconUrl()); 13 | } 14 | 15 | public GuildData(long id, String name, String iconUrl){ 16 | this.id = id; 17 | this.name = name; 18 | this.iconUrl = iconUrl; 19 | } 20 | 21 | public GuildData(OAuth2Guild guild){ 22 | this(guild.getIdLong(), guild.getName(), guild.getIconUrl()); 23 | } 24 | 25 | public long getId(){ 26 | return this.id; 27 | } 28 | 29 | public String getIdString(){ 30 | return String.valueOf(this.id); 31 | } 32 | 33 | public String getName(){ 34 | return this.name; 35 | } 36 | 37 | public String getIconUrl(){ 38 | return this.iconUrl; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/CommandOptionChoice.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application; 2 | 3 | import net.dv8tion.jda.api.utils.data.DataArray; 4 | import net.dv8tion.jda.api.utils.data.DataObject; 5 | 6 | import java.util.Collection; 7 | import java.util.stream.Collectors; 8 | 9 | public class CommandOptionChoice{ 10 | 11 | private final String name; 12 | private final T value; 13 | 14 | public CommandOptionChoice(String name, T value){ 15 | this.name = name; 16 | this.value = value; 17 | } 18 | 19 | public CommandOptionChoice(T tEnum){ 20 | this.name = tEnum.toString(); 21 | this.value = tEnum; 22 | } 23 | 24 | public static DataArray toJSON(Collection> choices){ 25 | return DataArray.fromCollection( 26 | choices.stream().map(CommandOptionChoice::toJSON).collect(Collectors.toList()) 27 | ); 28 | } 29 | 30 | public DataObject toJSON(){ 31 | return DataObject.empty().put("name", this.name).put("value", this.value); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionRawEmote.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | import net.dv8tion.jda.api.entities.Message; 7 | 8 | public class CommandOptionRawEmote extends CommandOption{ 9 | 10 | public CommandOptionRawEmote(String name, String description){ 11 | super(CommandOptionType.STRING, name, description); 12 | } 13 | 14 | @Override 15 | public String parseValue(Object value){ 16 | try{ 17 | var rawEmote = (String) value; 18 | var matcher = Message.MentionType.EMOTE.getPattern().matcher(rawEmote); 19 | if(matcher.matches()){ 20 | return rawEmote; 21 | } 22 | } 23 | catch(ClassCastException ignored){ 24 | } 25 | throw new OptionParseException("Failed to parse " + value + " as emote"); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/settings/NsfwCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.settings; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionBoolean; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class NsfwCommand extends GuildSubCommand{ 10 | 11 | public NsfwCommand(){ 12 | super("nsfw", "Enables/Disables nsfw commands"); 13 | addOptions( 14 | new CommandOptionBoolean("enabled", "Whether nsfw commands are enabled").required() 15 | ); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var enabled = options.getBoolean("enabled"); 21 | ia.get(SettingsModule.class).setNsfwEnabled(ia.getGuildId(), enabled); 22 | ia.reply((enabled ? "Enabled" : "Disabled") + "nsfw commands"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/info/PingCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.info; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.Category; 4 | import de.kittybot.kittybot.slashcommands.application.RunCommand; 5 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 6 | import de.kittybot.kittybot.slashcommands.interaction.Options; 7 | import de.kittybot.kittybot.utils.Config; 8 | 9 | @SuppressWarnings("unused") 10 | public class PingCommand extends RunCommand{ 11 | 12 | public PingCommand(){ 13 | super("ping", "Shows the bots ping", Category.INFORMATION); 14 | } 15 | 16 | @Override 17 | public void run(Options options, Interaction ia){ 18 | var jda = ia.getJDA(); 19 | jda.getRestPing().queue(ping -> 20 | ia.reply(builder -> builder 21 | .setAuthor("KittyBot Ping", Config.ORIGIN_URL, jda.getSelfUser().getEffectiveAvatarUrl()) 22 | 23 | .addField("Gateway Ping:", jda.getGatewayPing() + "ms", false) 24 | .addField("Rest Ping:", ping + "ms", false) 25 | ) 26 | ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/CommandOptionEmote.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.objects.exceptions.OptionParseException; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 5 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 6 | import net.dv8tion.jda.api.entities.Message; 7 | 8 | public class CommandOptionEmote extends CommandOption{ 9 | 10 | public CommandOptionEmote(String name, String description){ 11 | super(CommandOptionType.STRING, name, description); 12 | } 13 | 14 | @Override 15 | public String parseValue(Object value){ 16 | try{ 17 | var emote = (String) value; 18 | var matcher = Message.MentionType.EMOTE.getPattern().matcher(emote); 19 | if(matcher.matches()){ 20 | return emote; 21 | } 22 | } 23 | catch(ClassCastException | NumberFormatException ignored){ 24 | } 25 | throw new OptionParseException("Failed to parse " + value + " as emote"); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/ignore/user/ListCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.ignore.user; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 5 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 6 | import de.kittybot.kittybot.slashcommands.interaction.Options; 7 | import de.kittybot.kittybot.utils.MessageUtils; 8 | 9 | import java.util.stream.Collectors; 10 | 11 | public class ListCommand extends GuildSubCommand{ 12 | 13 | public ListCommand(){ 14 | super("list", "Used to list disabled a users"); 15 | } 16 | 17 | @Override 18 | public void run(Options options, GuildInteraction ia){ 19 | var users = ia.get(SettingsModule.class).getBotIgnoredUsers(ia.getGuildId()); 20 | if(users.isEmpty()){ 21 | ia.reply("No disabled users configured yet"); 22 | } 23 | ia.reply("**Disabled following users:**\n" + users.stream().map(MessageUtils::getUserMention).collect(Collectors.joining(", "))); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/settings/SelfAssignableRole.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.settings; 2 | 3 | import de.kittybot.kittybot.jooq.tables.records.SelfAssignableRolesRecord; 4 | 5 | public class SelfAssignableRole{ 6 | 7 | private final long groupId, guildId, roleId, emoteId; 8 | 9 | public SelfAssignableRole(long roleId, long emoteId, long guildId, long groupId){ 10 | this.roleId = roleId; 11 | this.emoteId = emoteId; 12 | this.guildId = guildId; 13 | this.groupId = groupId; 14 | } 15 | 16 | public SelfAssignableRole(SelfAssignableRolesRecord record){ 17 | this.roleId = record.getRoleId(); 18 | this.emoteId = record.getEmoteId(); 19 | this.guildId = record.getGuildId(); 20 | this.groupId = record.getGroupId(); 21 | } 22 | 23 | public long getRoleId(){ 24 | return this.roleId; 25 | } 26 | 27 | public long getEmoteId(){ 28 | return this.emoteId; 29 | } 30 | 31 | public long getGuildId(){ 32 | return this.guildId; 33 | } 34 | 35 | public long getGroupId(){ 36 | return this.groupId; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/streams/StreamType.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.streams; 2 | 3 | import java.util.Arrays; 4 | 5 | public enum StreamType{ 6 | 7 | TWITCH(1, "Twitch", "twitch.tv"), 8 | YOUTUBE(2, "YouTube", "youtube.com"); 9 | 10 | private final int id; 11 | private final String name, baseUrl; 12 | 13 | StreamType(int id, String name, String baseUrl){ 14 | this.id = id; 15 | this.name = name; 16 | this.baseUrl = baseUrl; 17 | } 18 | 19 | public static StreamType byId(int id){ 20 | return Arrays.stream(values()).filter(streamType -> streamType.getId() == id).findFirst().orElse(null); 21 | } 22 | 23 | public int getId(){ 24 | return this.id; 25 | } 26 | 27 | public static StreamType byName(String name){ 28 | return Arrays.stream(values()).filter(streamType -> streamType.getName().equalsIgnoreCase(name)).findFirst().orElse(null); 29 | } 30 | 31 | public String getName(){ 32 | return this.name; 33 | } 34 | 35 | public String getBaseUrl(){ 36 | return "https://" + this.baseUrl + "/"; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/ignore/channel/AddCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.ignore.channel; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionChannel; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class AddCommand extends GuildSubCommand{ 10 | 11 | public AddCommand(){ 12 | super("add", "Used to disable a channel"); 13 | addOptions( 14 | new CommandOptionChannel("channel", "Channel to disable").required() 15 | ); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var channel = options.getTextChannel("channel"); 21 | ia.get(SettingsModule.class).setBotDisabledInChannel(ia.getGuildId(), channel.getIdLong(), true); 22 | ia.reply("Disabled commands in: " + channel.getAsMention()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/info/UptimeCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.info; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.Category; 4 | import de.kittybot.kittybot.slashcommands.application.RunCommand; 5 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 6 | import de.kittybot.kittybot.slashcommands.interaction.Options; 7 | import de.kittybot.kittybot.utils.Config; 8 | import de.kittybot.kittybot.utils.TimeUtils; 9 | 10 | import java.lang.management.ManagementFactory; 11 | 12 | @SuppressWarnings("unused") 13 | public class UptimeCommand extends RunCommand{ 14 | 15 | public UptimeCommand(){ 16 | super("uptime", "Shows the bots uptime", Category.INFORMATION); 17 | } 18 | 19 | @Override 20 | public void run(Options options, Interaction ia){ 21 | ia.reply(builder -> builder 22 | .setAuthor("KittyBot Uptime", Config.ORIGIN_URL, ia.getSelfUser().getEffectiveAvatarUrl()) 23 | .addField("Uptime:", TimeUtils.formatDurationDHMS(ManagementFactory.getRuntimeMXBean().getUptime()), false) 24 | ); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/ignore/channel/RemoveCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.ignore.channel; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionChannel; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class RemoveCommand extends GuildSubCommand{ 10 | 11 | public RemoveCommand(){ 12 | super("remove", "Used to enable a channel"); 13 | addOptions( 14 | new CommandOptionChannel("channel", "Channel to enable").required() 15 | ); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var channel = options.getTextChannel("channel"); 21 | ia.get(SettingsModule.class).setBotDisabledInChannel(ia.getGuildId(), channel.getIdLong(), false); 22 | ia.reply("Enabled commands in: " + channel.getAsMention()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/streams/streams/MessageCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.streams.streams; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class MessageCommand extends GuildSubCommand{ 10 | 11 | public MessageCommand(){ 12 | super("message", "Sets the stream announcement message template"); 13 | addOptions( 14 | new CommandOptionString("message", "The message template").required() 15 | ); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var message = options.getString("message"); 21 | ia.get(SettingsModule.class).setStreamAnnouncementMessage(ia.getGuildId(), message); 22 | ia.reply("Set stream announcements template to:\n" + message); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/settings/snipes/EnableCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.settings.snipes; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionBoolean; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class EnableCommand extends GuildSubCommand{ 10 | 11 | public EnableCommand(){ 12 | super("enable", "Used to globally disable snipes"); 13 | addOptions( 14 | new CommandOptionBoolean("enabled", "Whether to enable/disable snipes globally") 15 | ); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var enabled = options.getBoolean("enabled"); 21 | ia.get(SettingsModule.class).setSnipesEnabled(ia.getGuildId(), enabled); 22 | ia.reply("Snipes globally `" + (enabled ? "enabled" : "disabled") + "`"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/ignore/channel/ListCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.ignore.channel; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 5 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 6 | import de.kittybot.kittybot.slashcommands.interaction.Options; 7 | import de.kittybot.kittybot.utils.MessageUtils; 8 | 9 | import java.util.stream.Collectors; 10 | 11 | public class ListCommand extends GuildSubCommand{ 12 | 13 | public ListCommand(){ 14 | super("list", "Used to list ignored a users"); 15 | } 16 | 17 | @Override 18 | public void run(Options options, GuildInteraction ia){ 19 | var channels = ia.get(SettingsModule.class).getBotDisabledChannels(ia.getGuildId()); 20 | if(channels.isEmpty()){ 21 | ia.reply("No disabled channels configured yet"); 22 | } 23 | ia.reply("**Disabled following channels:**\n" + channels.stream().map(MessageUtils::getChannelMention).collect(Collectors.joining(", "))); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/ignore/user/RemoveCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.ignore.user; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionUser; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | import java.util.Collections; 10 | 11 | public class RemoveCommand extends GuildSubCommand{ 12 | 13 | public RemoveCommand(){ 14 | super("remove", "Used to enable a user"); 15 | addOptions( 16 | new CommandOptionUser("user", "User to enable").required() 17 | ); 18 | } 19 | 20 | @Override 21 | public void run(Options options, GuildInteraction ia){ 22 | var user = options.getUser("user"); 23 | ia.get(SettingsModule.class).removeBotIgnoredUsers(ia.getGuildId(), Collections.singleton(user.getIdLong())); 24 | ia.reply("Enabled commands for: " + user.getAsMention()); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/settings/RoleSaverCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.settings; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionBoolean; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class RoleSaverCommand extends GuildSubCommand{ 10 | 11 | public RoleSaverCommand(){ 12 | super("rolesaver", "Enables/disables saving of user roles on leave"); 13 | addOptions( 14 | new CommandOptionBoolean("enabled", "Whether role saving is enabled or disabled").required() 15 | ); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var enabled = options.getBoolean("enabled"); 21 | ia.get(SettingsModule.class).setRoleSaverEnabled(ia.getGuildId(), enabled); 22 | ia.reply((enabled ? "Enabled" : "Disabled") + " role saving"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/ignore/user/AddCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.ignore.user; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionUser; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | import java.util.Collections; 10 | 11 | public class AddCommand extends GuildSubCommand{ 12 | 13 | public AddCommand(){ 14 | super("add", "Used to disable commands for a users"); 15 | addOptions( 16 | new CommandOptionUser("user", "User to disable commands").required() 17 | ); 18 | } 19 | 20 | @Override 21 | public void run(Options options, GuildInteraction ia){ 22 | var user = options.getUser("user"); 23 | ia.get(SettingsModule.class).addBotIgnoredUsers(ia.getGuildId(), Collections.singleton(user.getIdLong())); 24 | ia.reply("Disabled commands for: " + user.getAsMention()); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | INFO 9 | 10 | 11 | %cyan([) %boldWhite(%d{dd.MM.yyyy HH:mm:ss}) %cyan(%-5level]) %boldBlue([%t]) %boldWhite([%logger{0}]) %boldRed(-->) %white(%msg) %n 12 | 13 | 14 | 15 | 16 | 17 | WARN 18 | 19 | 20 | %d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/main/jooq/de/kittybot/kittybot/jooq/DefaultCatalog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is generated by jOOQ. 3 | */ 4 | package de.kittybot.kittybot.jooq; 5 | 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | import org.jooq.Schema; 11 | import org.jooq.impl.CatalogImpl; 12 | 13 | 14 | /** 15 | * This class is generated by jOOQ. 16 | */ 17 | @SuppressWarnings({ "all", "unchecked", "rawtypes" }) 18 | public class DefaultCatalog extends CatalogImpl { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | /** 23 | * The reference instance of DEFAULT_CATALOG 24 | */ 25 | public static final DefaultCatalog DEFAULT_CATALOG = new DefaultCatalog(); 26 | 27 | /** 28 | * The schema public. 29 | */ 30 | public final Public PUBLIC = Public.PUBLIC; 31 | 32 | /** 33 | * No further instances allowed 34 | */ 35 | private DefaultCatalog() { 36 | super(""); 37 | } 38 | 39 | @Override 40 | public final List getSchemas() { 41 | return Arrays.asList( 42 | Public.PUBLIC); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/info/VoteCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.info; 2 | 3 | import de.kittybot.kittybot.objects.enums.BotList; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import de.kittybot.kittybot.utils.MessageUtils; 9 | 10 | import java.util.Arrays; 11 | import java.util.stream.Collectors; 12 | 13 | @SuppressWarnings("unused") 14 | public class VoteCommand extends RunCommand{ 15 | 16 | public VoteCommand(){ 17 | super("vote", "Displays all info about voting for kitty", Category.INFORMATION); 18 | } 19 | 20 | @Override 21 | public void run(Options options, Interaction ia){ 22 | ia.reply("You can vote on following sites for KittyBot:\n" + Arrays.stream(BotList.values()). 23 | filter(BotList::canVote) 24 | .map(botList -> MessageUtils.maskLink(botList.getName(), botList.getBotUrl())) 25 | .collect(Collectors.joining(", ")) 26 | ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/settings/AnnouncementChannelCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.settings; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionChannel; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class AnnouncementChannelCommand extends GuildSubCommand{ 10 | 11 | public AnnouncementChannelCommand(){ 12 | super("announcementchannel", "Sets the announcement channel"); 13 | addOptions( 14 | new CommandOptionChannel("channel", "The new announcement channel").required() 15 | ); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var channel = options.getTextChannel("channel"); 21 | ia.get(SettingsModule.class).setAnnouncementChannelId(ia.getGuildId(), channel.getIdLong()); 22 | ia.reply("Announcement channel set to: " + channel.getAsMention()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/SkipCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import de.kittybot.kittybot.utils.MusicUtils; 9 | 10 | @SuppressWarnings("unused") 11 | public class SkipCommand extends RunGuildCommand{ 12 | 13 | public SkipCommand(){ 14 | super("skip", "Skips the current song", Category.MUSIC); 15 | } 16 | 17 | @Override 18 | public void run(Options options, GuildInteraction ia){ 19 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 20 | if(!MusicUtils.checkCommandRequirements(ia, scheduler)){ 21 | return; 22 | } 23 | if(!MusicUtils.checkMusicPermissions(ia, scheduler)){ 24 | return; 25 | } 26 | ia.reply("Skipped to the next song"); 27 | scheduler.next(true); 28 | scheduler.setPaused(false); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/StopCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import de.kittybot.kittybot.utils.MusicUtils; 9 | 10 | @SuppressWarnings("unused") 11 | public class StopCommand extends RunGuildCommand{ 12 | 13 | public StopCommand(){ 14 | super("stop", "Stops playing music", Category.MUSIC); 15 | } 16 | 17 | @Override 18 | public void run(Options options, GuildInteraction ia){ 19 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 20 | if(!MusicUtils.checkCommandRequirements(ia, scheduler)){ 21 | return; 22 | } 23 | if(!MusicUtils.checkMusicPermissions(ia, scheduler)){ 24 | return; 25 | } 26 | ia.acknowledge().queue(success -> ia.get(MusicModule.class).destroy(ia.getGuildId(), ia.getUserId())); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/guilds/guild/channels/GetChannelsRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.guilds.guild.channels; 2 | 3 | import de.kittybot.kittybot.modules.WebModule; 4 | import de.kittybot.kittybot.objects.module.Modules; 5 | import io.javalin.http.Context; 6 | import io.javalin.http.Handler; 7 | import net.dv8tion.jda.api.utils.data.DataArray; 8 | import net.dv8tion.jda.api.utils.data.DataObject; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.stream.Collectors; 12 | 13 | public class GetChannelsRoute implements Handler{ 14 | 15 | private final Modules modules; 16 | 17 | public GetChannelsRoute(Modules modules){ 18 | this.modules = modules; 19 | } 20 | 21 | @Override 22 | public void handle(@NotNull Context ctx){ 23 | var guild = this.modules.get(WebModule.class).getGuild(ctx); 24 | var channels = DataArray.fromCollection( 25 | guild.getTextChannelCache().stream().map(channel -> DataObject.empty().put("id", channel.getId()).put("name", channel.getName())).collect(Collectors.toSet()) 26 | ); 27 | WebModule.ok(ctx, DataObject.empty().put("channels", channels)); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "default_prefix": "", 3 | 4 | "bot_token": "", 5 | "bot_secret": "", 6 | 7 | "dev_ids": [ 8 | ], 9 | 10 | "backend_port": 6969, 11 | "prometheus_port": 8080, 12 | 13 | "redirect_url": "", 14 | "origin_url": "", 15 | "hastebin_url": "", 16 | 17 | "log_webhook_url": "", 18 | 19 | "support_guild_invite_url": "", 20 | "bot_invite_url": "", 21 | 22 | "twitch_client_id": "", 23 | "twitch_client_secret": "", 24 | 25 | "signing_key": "", 26 | 27 | "discord_bots_token": "", 28 | "top_gg_token": "", 29 | "discord_extreme_list_token": "", 30 | "discord_boats_token": "", 31 | "botlist_space": "", 32 | "bots_for_discord_token": "", 33 | "discordbotlist_token": "", 34 | "discord_services_token": "", 35 | 36 | "db_host": "", 37 | "db_port": "", 38 | "db_database": "", 39 | "db_user": "", 40 | "db_password": "", 41 | 42 | "lavalink_nodes": [ 43 | { 44 | "host": "", 45 | "port": "", 46 | "password": "" 47 | } 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/streams/streams/ChannelCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.streams.streams; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionChannel; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class ChannelCommand extends GuildSubCommand{ 10 | 11 | public ChannelCommand(){ 12 | super("channel", "Sets the stream announcement channel"); 13 | addOptions( 14 | new CommandOptionChannel("channel", "The channel which stream announcements should get send to").required() 15 | ); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var channel = options.getTextChannel("channel"); 21 | ia.get(SettingsModule.class).setStreamAnnouncementChannelId(ia.getGuildId(), channel.getIdLong()); 22 | ia.reply("Stream announcements now get send to " + channel.getAsMention()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/guilds/guild/emotes/GetEmotesRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.guilds.guild.emotes; 2 | 3 | import de.kittybot.kittybot.modules.WebModule; 4 | import de.kittybot.kittybot.objects.module.Modules; 5 | import io.javalin.http.Context; 6 | import io.javalin.http.Handler; 7 | import net.dv8tion.jda.api.utils.data.DataArray; 8 | import net.dv8tion.jda.api.utils.data.DataObject; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.stream.Collectors; 12 | 13 | public class GetEmotesRoute implements Handler{ 14 | 15 | private final Modules modules; 16 | 17 | public GetEmotesRoute(Modules modules){ 18 | this.modules = modules; 19 | } 20 | 21 | @Override 22 | public void handle(@NotNull Context ctx){ 23 | var guild = this.modules.get(WebModule.class).getGuild(ctx); 24 | var emotes = DataArray.fromCollection( 25 | guild.getEmoteCache().stream().map(emote -> DataObject.empty().put("id", emote.getId()).put("name", emote.getName()).put("url", emote.getImageUrl())).collect(Collectors.toSet()) 26 | ); 27 | WebModule.ok(ctx, DataObject.empty().put("emotes", emotes)); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/data/ReactiveMessage.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.data; 2 | 3 | public class ReactiveMessage{ 4 | 5 | private final long guildId, channelId, messageId, responseId, userId, allowed; 6 | private final String path; 7 | 8 | public ReactiveMessage(long guildId, long channelId, long messageId, long responseId, long userId, String path, long allowed){ 9 | this.guildId = guildId; 10 | this.channelId = channelId; 11 | this.messageId = messageId; 12 | this.responseId = responseId; 13 | this.userId = userId; 14 | this.path = path; 15 | this.allowed = allowed; 16 | } 17 | 18 | public long getGuildId(){ 19 | return this.guildId; 20 | } 21 | 22 | public long getChannelId(){ 23 | return this.channelId; 24 | } 25 | 26 | public long getMessageId(){ 27 | return this.messageId; 28 | } 29 | 30 | public long getResponseId(){ 31 | return this.responseId; 32 | } 33 | 34 | public long getUserId(){ 35 | return this.userId; 36 | } 37 | 38 | public String getPath(){ 39 | return this.path; 40 | } 41 | 42 | public long getAllowed(){ 43 | return this.allowed; 44 | } 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/shards/GetShardsRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.shards; 2 | 3 | import de.kittybot.kittybot.modules.WebModule; 4 | import de.kittybot.kittybot.objects.module.Modules; 5 | import io.javalin.http.Context; 6 | import io.javalin.http.Handler; 7 | import net.dv8tion.jda.api.utils.data.DataArray; 8 | import net.dv8tion.jda.api.utils.data.DataObject; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.stream.Collectors; 12 | 13 | public class GetShardsRoute implements Handler{ 14 | 15 | private final Modules modules; 16 | 17 | public GetShardsRoute(Modules modules){ 18 | this.modules = modules; 19 | } 20 | 21 | @Override 22 | public void handle(@NotNull Context ctx){ 23 | WebModule.ok(ctx, DataObject.empty().put("shards", DataArray.fromCollection(modules.getShardManager().getShardCache().stream().map(shard -> DataObject.empty() 24 | .put("id", shard.getShardInfo().getShardId()) 25 | .put("guilds", shard.getGuildCache().size()) 26 | .put("status", shard.getStatus().name()) 27 | .put("ping", shard.getGatewayPing()) 28 | ).collect(Collectors.toList()))) 29 | ); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/ban/ListCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.ban; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 4 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 5 | import de.kittybot.kittybot.slashcommands.interaction.Options; 6 | import net.dv8tion.jda.api.utils.MarkdownSanitizer; 7 | 8 | import java.util.stream.Collectors; 9 | 10 | public class ListCommand extends GuildSubCommand{ 11 | 12 | public ListCommand(){ 13 | super("list", "Lists all bans"); 14 | } 15 | 16 | @Override 17 | public void run(Options options, GuildInteraction ia){ 18 | ia.getGuild().retrieveBanList().queue(bans -> { 19 | if(bans.isEmpty()){ 20 | ia.reply("There are no banned users yet"); 21 | return; 22 | } 23 | ia.reply("**Banned Users:**\n" + bans.stream().map(ban -> MarkdownSanitizer.escape(ban.getUser().getAsTag()) + "(`" + ban.getUser().getId() + "`)" + " - " + ban.getReason()).collect(Collectors.joining("\n"))); 24 | }, error -> ia.error("I was not able to retrieve the bans. Please give me the `ban members` permission") 25 | ); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/notification/notification/DeleteCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.notification.notification; 2 | 3 | import de.kittybot.kittybot.modules.NotificationModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionInteger; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class DeleteCommand extends GuildSubCommand{ 10 | 11 | public DeleteCommand(){ 12 | super("delete", "Deletes a notification"); 13 | addOptions( 14 | new CommandOptionInteger("notification-id", "The notification id").required() 15 | ); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var notificationId = options.getLong("notification-id"); 21 | if(ia.get(NotificationModule.class).delete(notificationId, ia.getUserId())){ 22 | ia.reply("Deleted your notification with id `" + notificationId + "`"); 23 | return; 24 | } 25 | ia.error("Notification either does not exist or does not belong to you"); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/roles/roles/groups/ListCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.roles.roles.groups; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 5 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 6 | import de.kittybot.kittybot.slashcommands.interaction.Options; 7 | 8 | import java.util.stream.Collectors; 9 | 10 | public class ListCommand extends GuildSubCommand{ 11 | 12 | public ListCommand(){ 13 | super("list", "Lists all self assignable role groups"); 14 | } 15 | 16 | @Override 17 | public void run(Options options, GuildInteraction ia){ 18 | var settings = ia.get(SettingsModule.class).getSettings(ia.getGuildId()); 19 | var groups = settings.getSelfAssignableRoleGroups(); 20 | if(groups.isEmpty()){ 21 | ia.error("There are not groups defined.\nYou can add them with `/groups add `"); 22 | return; 23 | } 24 | ia.reply("**Self assignable role groups:**\n\n" + groups.stream().map(group -> "**Name:** `" + group.getName() + "` **Max Roles:** `" + group.getFormattedMaxRoles() + "`").collect(Collectors.joining("\n"))); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.utils; 2 | 3 | import net.dv8tion.jda.api.entities.Guild; 4 | import net.dv8tion.jda.api.sharding.ShardManager; 5 | import net.dv8tion.jda.api.utils.MiscUtil; 6 | 7 | import java.util.List; 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.stream.Collectors; 10 | 11 | public class Utils{ 12 | 13 | private Utils(){} 14 | 15 | public static int getUserCount(ShardManager shardManager){ 16 | //noinspection ConstantConditions 17 | return shardManager.getGuildCache().applyStream(guildStream -> guildStream.mapToInt(Guild::getMemberCount).sum()); 18 | } 19 | 20 | public static boolean isSnowflake(String id){ 21 | try{ 22 | MiscUtil.parseSnowflake(id); 23 | return true; 24 | } 25 | catch(NumberFormatException ignored){ 26 | return false; 27 | } 28 | } 29 | 30 | public static CompletableFuture> all(List> futures){ 31 | CompletableFuture[] cfs = futures.toArray(new CompletableFuture[]{}); 32 | 33 | return CompletableFuture.allOf(cfs) 34 | .thenApply(ignored -> futures.stream() 35 | .map(CompletableFuture::join) 36 | .collect(Collectors.toList()) 37 | ); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/guilds/guild/roles/GetRolesRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.guilds.guild.roles; 2 | 3 | import de.kittybot.kittybot.modules.WebModule; 4 | import de.kittybot.kittybot.objects.module.Modules; 5 | import io.javalin.http.Context; 6 | import io.javalin.http.Handler; 7 | import net.dv8tion.jda.api.utils.data.DataArray; 8 | import net.dv8tion.jda.api.utils.data.DataObject; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.stream.Collectors; 12 | 13 | public class GetRolesRoute implements Handler{ 14 | 15 | private final Modules modules; 16 | 17 | public GetRolesRoute(Modules modules){ 18 | this.modules = modules; 19 | } 20 | 21 | @Override 22 | public void handle(@NotNull Context ctx){ 23 | var guild = this.modules.get(WebModule.class).getGuild(ctx); 24 | var roles = DataArray.fromCollection( 25 | guild.getRoleCache().stream().filter(role -> !role.isPublicRole()).map(role -> DataObject.empty().put("id", role.getId()).put("name", role.getName()).put("color", role.getColor() == null ? "" : "#" + Integer.toHexString(role.getColor().getRGB()).substring(2))).collect(Collectors.toSet()) 26 | ); 27 | WebModule.ok(ctx, DataObject.empty().put("roles", roles)); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/interaction/GuildInteraction.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.interaction; 2 | 3 | import de.kittybot.kittybot.objects.module.Modules; 4 | import net.dv8tion.jda.api.JDA; 5 | import net.dv8tion.jda.api.entities.Guild; 6 | import net.dv8tion.jda.api.entities.Member; 7 | import net.dv8tion.jda.api.entities.TextChannel; 8 | import net.dv8tion.jda.api.utils.data.DataObject; 9 | 10 | public class GuildInteraction extends Interaction{ 11 | 12 | private final Guild guild; 13 | private final Member member; 14 | 15 | public GuildInteraction(DataObject json, InteractionData data, Guild guild, Member member, TextChannel channel, Modules modules, JDA jda){ 16 | super(json, data, member.getUser(), channel, true, modules, jda); 17 | this.guild = guild; 18 | this.member = member; 19 | } 20 | 21 | public Guild getGuild(){ 22 | return this.guild; 23 | } 24 | 25 | public long getGuildId(){ 26 | return this.guild.getIdLong(); 27 | } 28 | 29 | public Member getMember(){ 30 | return this.member; 31 | } 32 | 33 | public Member getSelfMember(){ 34 | return this.guild.getSelfMember(); 35 | } 36 | 37 | @Override 38 | public TextChannel getChannel(){ 39 | return (TextChannel) this.channel; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.utils; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.nio.charset.StandardCharsets; 10 | import java.util.ArrayList; 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | public class FileUtils{ 15 | 16 | private static final Logger LOG = LoggerFactory.getLogger(FileUtils.class); 17 | 18 | private FileUtils(){} 19 | 20 | public static List loadMessageFile(String fileName){ 21 | var inputStream = FileUtils.class.getClassLoader().getResourceAsStream("messages/" + fileName + "_messages.txt"); 22 | if(inputStream == null){ 23 | LOG.error("Message file not found"); 24 | return Collections.emptyList(); 25 | } 26 | var reader = new BufferedReader(new InputStreamReader((inputStream), StandardCharsets.UTF_8)); 27 | List set = new ArrayList<>(); 28 | try{ 29 | String line; 30 | while((line = reader.readLine()) != null){ 31 | set.add(line); 32 | } 33 | reader.close(); 34 | } 35 | catch(IOException e){ 36 | LOG.error("Error reading message file", e); 37 | } 38 | return set; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/PreviousCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import de.kittybot.kittybot.utils.MusicUtils; 9 | 10 | @SuppressWarnings("unused") 11 | public class PreviousCommand extends RunGuildCommand{ 12 | 13 | public PreviousCommand(){ 14 | super("previous", "Plays the previous song", Category.MUSIC); 15 | } 16 | 17 | @Override 18 | public void run(Options options, GuildInteraction ia){ 19 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 20 | if(!MusicUtils.checkCommandRequirements(ia, scheduler)){ 21 | return; 22 | } 23 | if(!MusicUtils.checkMusicPermissions(ia, scheduler)){ 24 | return; 25 | } 26 | if(scheduler.getHistory().isEmpty()){ 27 | ia.error("Can't go back because the history is empty"); 28 | return; 29 | } 30 | ia.reply("Went back to the previous song"); 31 | scheduler.previous(); 32 | scheduler.setPaused(false); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/session/DashboardSessionController.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.session; 2 | 3 | import com.jagrosh.jdautilities.oauth2.session.SessionController; 4 | import com.jagrosh.jdautilities.oauth2.session.SessionData; 5 | import de.kittybot.kittybot.modules.DashboardSessionModule; 6 | 7 | import java.io.IOException; 8 | 9 | public class DashboardSessionController implements SessionController{ 10 | 11 | private final DashboardSessionModule dashboardSessionModule; 12 | 13 | public DashboardSessionController(DashboardSessionModule dashboardSessionModule){ 14 | this.dashboardSessionModule = dashboardSessionModule; 15 | } 16 | 17 | @Override 18 | public DashboardSession getSession(String userId){ 19 | return this.dashboardSessionModule.get(Long.parseLong(userId)); 20 | } 21 | 22 | @Override 23 | public DashboardSession createSession(SessionData sessionData){ 24 | var session = new DashboardSession(sessionData); 25 | try{ 26 | var user = this.dashboardSessionModule.getOAuth2Client().getUser(session).complete(); 27 | session.setUserId(user.getIdLong()); 28 | this.dashboardSessionModule.add(session); 29 | return session; 30 | } 31 | catch(IOException ignored){ 32 | } 33 | return null; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/ShuffleCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.modules.SettingsModule; 5 | import de.kittybot.kittybot.slashcommands.application.Category; 6 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.utils.MusicUtils; 10 | 11 | @SuppressWarnings("unused") 12 | public class ShuffleCommand extends RunGuildCommand{ 13 | 14 | public ShuffleCommand(){ 15 | super("shuffle", "Shuffles all queued tracks", Category.MUSIC); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 21 | if(!MusicUtils.checkCommandRequirements(ia, scheduler)){ 22 | return; 23 | } 24 | if(!ia.get(SettingsModule.class).hasDJRole(ia.getMember())){ 25 | ia.error("Only DJs are allowed shuffle"); 26 | return; 27 | } 28 | if(scheduler.shuffle()){ 29 | ia.reply("Queue shuffled"); 30 | return; 31 | } 32 | ia.error("Queue is empty. Nothing to shuffle"); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/discord/login/GetDiscordLoginRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.discord.login; 2 | 3 | import de.kittybot.kittybot.modules.DashboardSessionModule; 4 | import de.kittybot.kittybot.modules.WebModule; 5 | import de.kittybot.kittybot.objects.module.Modules; 6 | import de.kittybot.kittybot.utils.Config; 7 | import io.javalin.http.Context; 8 | import io.javalin.http.ForbiddenResponse; 9 | import io.javalin.http.Handler; 10 | import io.javalin.http.UnauthorizedResponse; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | public class GetDiscordLoginRoute implements Handler{ 14 | 15 | private final Modules modules; 16 | 17 | public GetDiscordLoginRoute(Modules modules){ 18 | this.modules = modules; 19 | } 20 | 21 | @Override 22 | public void handle(@NotNull Context ctx){ 23 | var dashboardSessionModule = this.modules.get(DashboardSessionModule.class); 24 | try{ 25 | if(!dashboardSessionModule.has(this.modules.get(WebModule.class).getUserId(ctx))){ 26 | ctx.redirect(Config.REDIRECT_URL); 27 | return; 28 | } 29 | } 30 | catch(UnauthorizedResponse | ForbiddenResponse ignored){ 31 | } 32 | ctx.redirect(dashboardSessionModule.getOAuth2Client().generateAuthorizationURL(Config.REDIRECT_URL, DashboardSessionModule.getScopes())); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/tags/TagsCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.tags; 2 | 3 | import de.kittybot.kittybot.commands.tags.tags.*; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.Command; 6 | import de.kittybot.kittybot.slashcommands.application.GenericHelpCommand; 7 | 8 | @SuppressWarnings("unused") 9 | public class TagsCommand extends Command{ 10 | 11 | public TagsCommand(){ 12 | super("tags", "Used to create/edit/delete/search tags", Category.TAGS); 13 | addOptions( 14 | new CreateCommand(), 15 | new EditCommand(), 16 | new DeleteCommand(), 17 | new SearchCommand(), 18 | new ListCommand(), 19 | new InfoCommand(), 20 | new PublishCommand(), 21 | new UnpublishCommand(), 22 | new GenericHelpCommand("Tags lets anyone create shortcuts to certain information.\n" + 23 | "You can create them via `/tags create ` or `/tags create ` to mirror the content of an already sent message.\n" + 24 | "Members with the `MANAGE_SERVER` permission can also add up to 50 tags as server commands with `/tags publish `\n" + 25 | "You can remove them again via `/tags remove `" 26 | ) 27 | ); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/interaction/response/InteractionResponseData.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.interaction.response; 2 | 3 | import net.dv8tion.jda.api.entities.Message; 4 | import net.dv8tion.jda.api.entities.MessageEmbed; 5 | 6 | import java.util.EnumSet; 7 | import java.util.List; 8 | 9 | public class InteractionResponseData{ 10 | 11 | private final boolean tts; 12 | private final String content; 13 | private final List embeds; 14 | private final int flags; 15 | private final EnumSet allowedMentions; 16 | 17 | protected InteractionResponseData(boolean tts, String content, List embeds, int flags, EnumSet allowedMentions){ 18 | this.tts = tts; 19 | this.content = content; 20 | this.embeds = embeds; 21 | this.flags = flags; 22 | this.allowedMentions = allowedMentions; 23 | } 24 | 25 | public boolean isTts(){ 26 | return this.tts; 27 | } 28 | 29 | public String getContent(){ 30 | return this.content; 31 | } 32 | 33 | public List getEmbeds(){ 34 | return this.embeds; 35 | } 36 | 37 | public int getFlags(){ 38 | return this.flags; 39 | } 40 | 41 | public EnumSet getAllowedMentions(){ 42 | return this.allowedMentions; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/streams/streams/ListCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.streams.streams; 2 | 3 | import de.kittybot.kittybot.modules.StreamModule; 4 | import de.kittybot.kittybot.objects.streams.StreamType; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import de.kittybot.kittybot.utils.MessageUtils; 9 | 10 | import java.util.stream.Collectors; 11 | 12 | public class ListCommand extends GuildSubCommand{ 13 | 14 | public ListCommand(){ 15 | super("list", "Lists stream announcements"); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var streamAnnouncements = ia.get(StreamModule.class).get(ia.getGuildId()); 21 | if(streamAnnouncements.isEmpty()){ 22 | ia.error("No stream announcements found. Create them with `/settings streamannouncements add `"); 23 | return; 24 | } 25 | ia.reply("**Stream Announcements:**\n" + streamAnnouncements.stream().map(sa -> MessageUtils.maskLink(sa.getUserName(), "https://twitch.tv/" + sa.getUserName()) + " on " + StreamType.byId(sa.getStreamType()).getName()).collect(Collectors.joining("\n"))); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/guilds/guild/users/GetUsersRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.guilds.guild.users; 2 | 3 | import de.kittybot.kittybot.modules.WebModule; 4 | import de.kittybot.kittybot.objects.module.Modules; 5 | import io.javalin.http.Context; 6 | import io.javalin.http.Handler; 7 | import net.dv8tion.jda.api.utils.data.DataArray; 8 | import net.dv8tion.jda.api.utils.data.DataObject; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.stream.Collectors; 12 | 13 | public class GetUsersRoute implements Handler{ 14 | 15 | private final Modules modules; 16 | 17 | public GetUsersRoute(Modules modules){ 18 | this.modules = modules; 19 | } 20 | 21 | @Override 22 | public void handle(@NotNull Context ctx){ 23 | var guild = this.modules.get(WebModule.class).getGuild(ctx); 24 | var users = DataArray.fromCollection( 25 | guild.loadMembers().get().stream().map(user -> 26 | DataObject.empty() 27 | .put("id", user.getId()) 28 | .put("name", user.getUser().getAsTag()) 29 | .put("url", user.getUser().getEffectiveAvatarUrl()) 30 | .put("color", user.getColor() == null ? "" : "#" + Integer.toHexString(user.getColor().getRGB()).substring(2)) 31 | ).collect(Collectors.toSet()) 32 | ); 33 | WebModule.ok(ctx, DataObject.empty().put("users", users)); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/SearchCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.Category; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOptionChoice; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.utils.annotations.Ignore; 10 | 11 | @SuppressWarnings("unused") 12 | @Ignore 13 | public class SearchCommand extends RunGuildCommand{ 14 | 15 | public SearchCommand(){ 16 | super("search", "Searched for a given search-term on yt/sc", Category.MUSIC); 17 | addOptions( 18 | new CommandOptionString("search-term", "A search-term to search for").required(), 19 | new CommandOptionString("search-provider", "Which search provider use") 20 | .addChoices( 21 | new CommandOptionChoice<>("youtube", "yt"), 22 | new CommandOptionChoice<>("soundcloud", "sc") 23 | ) 24 | ); 25 | } 26 | 27 | @Override 28 | public void run(Options options, GuildInteraction ia){ 29 | // TODO implement 30 | ia.error("not implemented yet"); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/settings/SelfAssignableRoleGroup.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.settings; 2 | 3 | import de.kittybot.kittybot.jooq.tables.records.SelfAssignableRoleGroupsRecord; 4 | 5 | public class SelfAssignableRoleGroup{ 6 | 7 | private final long guildId; 8 | private final String groupName; 9 | private final int maxRoles; 10 | private long id; 11 | 12 | public SelfAssignableRoleGroup(long id, long guildId, String groupName, int maxRoles){ 13 | this.id = id; 14 | this.guildId = guildId; 15 | this.groupName = groupName; 16 | this.maxRoles = maxRoles; 17 | } 18 | 19 | public SelfAssignableRoleGroup(SelfAssignableRoleGroupsRecord record){ 20 | this.id = record.getId(); 21 | this.guildId = record.getGuildId(); 22 | this.groupName = record.getName(); 23 | this.maxRoles = record.getMaxRoles(); 24 | } 25 | 26 | public long getId(){ 27 | return this.id; 28 | } 29 | 30 | public void setId(long id){ 31 | this.id = id; 32 | } 33 | 34 | public long getGuildId(){ 35 | return this.guildId; 36 | } 37 | 38 | public String getName(){ 39 | return this.groupName; 40 | } 41 | 42 | public int getMaxRoles(){ 43 | return this.maxRoles; 44 | } 45 | 46 | public String getFormattedMaxRoles(){ 47 | return this.maxRoles == -1 ? "unlimited" : String.valueOf(this.maxRoles); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/resources/sql_tables/guilds.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS guilds( 2 | id BIGINT PRIMARY KEY NOT NULL, 3 | announcement_channel_id BIGINT NOT NULL DEFAULT(-1), 4 | join_message TEXT NOT NULL DEFAULT('Welcome ${user}!'), 5 | join_messages_enabled BOOLEAN NOT NULL DEFAULT(false), 6 | leave_message TEXT NOT NULL DEFAULT('Bye ${user}!'), 7 | leave_messages_enabled BOOLEAN NOT NULL DEFAULT(false), 8 | log_channel_id BIGINT NOT NULL DEFAULT(-1), 9 | log_messages_enabled BOOLEAN NOT NULL DEFAULT(false), 10 | request_channel_id BIGINT NOT NULL DEFAULT(-1), 11 | requests_enabled BOOLEAN NOT NULL DEFAULT(false), 12 | stream_announcement_channel_id BIGINT NOT NULL DEFAULT(-1), 13 | stream_announcement_message TEXT NOT NULL DEFAULT('${user} is now live!'), 14 | nsfw_enabled BOOLEAN NOT NULL DEFAULT(true), 15 | inactive_role_id BIGINT NOT NULL DEFAULT(-1), 16 | inactive_duration INTERVAL NOT NULL, 17 | inactive_role_enabled BOOLEAN NOT NULL DEFAULT(false), 18 | dj_role_id BIGINT NOT NULL DEFAULT(-1), 19 | snipes_enabled BOOLEAN NOT NULL DEFAULT(true), 20 | role_saver_enabled BOOLEAN NOT NULL DEFAULT(true) 21 | ); 22 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/HistoryCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import de.kittybot.kittybot.utils.MessageUtils; 9 | import de.kittybot.kittybot.utils.MusicUtils; 10 | 11 | @SuppressWarnings("unused") 12 | public class HistoryCommand extends RunGuildCommand{ 13 | 14 | public HistoryCommand(){ 15 | super("history", "Displays the last played tracks", Category.MUSIC); 16 | } 17 | 18 | @Override 19 | public void run(Options options, GuildInteraction ia){ 20 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 21 | if(!MusicUtils.checkCommandRequirements(ia, scheduler)){ 22 | return; 23 | } 24 | var tracks = scheduler.getHistory(); 25 | if(tracks.isEmpty()){ 26 | ia.reply("The history is empty. Play some tracks to fill it"); 27 | return; 28 | } 29 | MusicUtils.sendTracks(tracks, ia.getModules(), ia.getChannel(), ia.getUserId(), "Currently " + tracks.size() + " " + MessageUtils.pluralize("track", tracks) + " are in the history"); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/streams/streams/AddCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.streams.streams; 2 | 3 | import de.kittybot.kittybot.modules.StreamModule; 4 | import de.kittybot.kittybot.objects.streams.StreamType; 5 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 6 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | 10 | public class AddCommand extends GuildSubCommand{ 11 | 12 | public AddCommand(){ 13 | super("add", "Adds a new stream announcement for twitch"); 14 | addOptions( 15 | new CommandOptionString("username", "The username of the streamer").required() 16 | ); 17 | } 18 | 19 | @Override 20 | public void run(Options options, GuildInteraction ia){ 21 | var type = StreamType.TWITCH;//StreamType.byId(options.getInt("service")); 22 | var username = options.getString("username"); 23 | var user = ia.get(StreamModule.class).add(username, ia.getGuildId(), type); 24 | if(user == null){ 25 | ia.error("No user found with username " + username + "for " + type.getName()); 26 | return; 27 | } 28 | ia.reply("Stream announcement for " + type.getName() + " with username: " + user.getDisplayName() + " added"); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/tags/tags/DeleteCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.tags.tags; 2 | 3 | import de.kittybot.kittybot.modules.TagsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import net.dv8tion.jda.api.Permission; 9 | 10 | public class DeleteCommand extends GuildSubCommand{ 11 | 12 | public DeleteCommand(){ 13 | super("delete", "Used to delete a tag"); 14 | addOptions( 15 | new CommandOptionString("name", "Tag name").required() 16 | ); 17 | } 18 | 19 | @Override 20 | public void run(Options options, GuildInteraction ia){ 21 | var tagName = options.getString("name"); 22 | var deleted = false; 23 | if(ia.getMember().hasPermission(Permission.ADMINISTRATOR)){ 24 | deleted = ia.get(TagsModule.class).delete(tagName, ia.getGuildId()); 25 | } 26 | else{ 27 | deleted = ia.get(TagsModule.class).delete(tagName, ia.getGuildId(), ia.getUserId()); 28 | } 29 | 30 | if(deleted){ 31 | ia.reply("Deleted tag with name `" + tagName + "`"); 32 | return; 33 | } 34 | ia.error("Tag `" + tagName + "` does not exist or is not owned by you"); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/info/GetInfoRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.info; 2 | 3 | import de.kittybot.kittybot.modules.CommandsModule; 4 | import de.kittybot.kittybot.modules.MusicModule; 5 | import de.kittybot.kittybot.modules.WebModule; 6 | import de.kittybot.kittybot.objects.module.Modules; 7 | import io.javalin.http.Context; 8 | import io.javalin.http.Handler; 9 | import net.dv8tion.jda.api.JDAInfo; 10 | import net.dv8tion.jda.api.entities.Guild; 11 | import net.dv8tion.jda.api.utils.data.DataObject; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | public class GetInfoRoute implements Handler{ 15 | 16 | private final Modules modules; 17 | 18 | public GetInfoRoute(Modules modules){ 19 | this.modules = modules; 20 | } 21 | 22 | @Override 23 | public void handle(@NotNull Context ctx){ 24 | var shardManager = modules.getShardManager(); 25 | WebModule.ok(ctx, DataObject.empty() 26 | .put("shards", shardManager.getShardCache().size()) 27 | .put("guilds", shardManager.getGuildCache().size()) 28 | .put("users", shardManager.getGuildCache().applyStream(guildStream -> guildStream.mapToInt(Guild::getMemberCount).sum())) 29 | .put("jda_version", JDAInfo.VERSION) 30 | .put("players", modules.get(MusicModule.class).getActivePlayers()) 31 | .put("commands", modules.get(CommandsModule.class).getCommands().size()) 32 | ); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/VolumeCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionInteger; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.utils.MusicUtils; 10 | 11 | @SuppressWarnings("unused") 12 | public class VolumeCommand extends RunGuildCommand{ 13 | 14 | public VolumeCommand(){ 15 | super("volume", "Used to set the player volume", Category.MUSIC); 16 | addOptions( 17 | new CommandOptionInteger("volume", "The music volume") 18 | ); 19 | } 20 | 21 | @Override 22 | public void run(Options options, GuildInteraction ia){ 23 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 24 | if(!MusicUtils.checkCommandRequirements(ia, scheduler)){ 25 | return; 26 | } 27 | int volume = options.getInt("volume"); 28 | if(volume < 0 || volume > 150){ 29 | ia.error("Volume needs to between 0 and 150"); 30 | return; 31 | } 32 | scheduler.setVolume(volume); 33 | ia.reply("Volume set to: `" + volume + "`"); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/settings/snipes/ChannelCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.settings.snipes; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionBoolean; 5 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionChannel; 6 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | 10 | public class ChannelCommand extends GuildSubCommand{ 11 | 12 | public ChannelCommand(){ 13 | super("channel", "Used to enable/disable snipes in a specific channel"); 14 | addOptions( 15 | new CommandOptionChannel("channel", "The channel to enable/disable snipes").required(), 16 | new CommandOptionBoolean("enabled", "Whether to enable/disable snipes").required() 17 | ); 18 | } 19 | 20 | @Override 21 | public void run(Options options, GuildInteraction ia){ 22 | var channel = options.getTextChannel("channel"); 23 | var enabled = options.getBoolean("enabled"); 24 | ia.get(SettingsModule.class).setSnipesDisabledInChannel(ia.getGuildId(), channel.getIdLong(), !enabled); 25 | ia.reply("Snipes `" + (enabled ? "enabled" : "disabled") + "` in " + channel.getAsMention()); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/commands/GetCommandsRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.commands; 2 | 3 | import de.kittybot.kittybot.modules.CommandsModule; 4 | import de.kittybot.kittybot.modules.WebModule; 5 | import de.kittybot.kittybot.objects.module.Modules; 6 | import de.kittybot.kittybot.slashcommands.application.Category; 7 | import de.kittybot.kittybot.slashcommands.application.Command; 8 | import io.javalin.http.Context; 9 | import io.javalin.http.Handler; 10 | import net.dv8tion.jda.api.utils.data.DataArray; 11 | import net.dv8tion.jda.api.utils.data.DataObject; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.Arrays; 15 | import java.util.stream.Collectors; 16 | 17 | public class GetCommandsRoute implements Handler{ 18 | 19 | private final Modules modules; 20 | 21 | public GetCommandsRoute(Modules modules){ 22 | this.modules = modules; 23 | } 24 | 25 | @Override 26 | public void handle(@NotNull Context ctx){ 27 | 28 | var categories = DataArray.fromCollection(Arrays.stream(Category.values()).map(Category::toJSON).collect(Collectors.toList())); 29 | var commands = DataArray.fromCollection(this.modules.get(CommandsModule.class).getCommands().values().stream().map(Command::toDetailedJSON).collect(Collectors.toList())); 30 | 31 | WebModule.ok(ctx, DataObject.empty().put("categories", categories).put("commands", commands)); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/roles/RolesCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.roles; 2 | 3 | import de.kittybot.kittybot.commands.roles.roles.AddCommand; 4 | import de.kittybot.kittybot.commands.roles.roles.GroupsCommand; 5 | import de.kittybot.kittybot.commands.roles.roles.ListCommand; 6 | import de.kittybot.kittybot.commands.roles.roles.RemoveCommand; 7 | import de.kittybot.kittybot.slashcommands.application.Category; 8 | import de.kittybot.kittybot.slashcommands.application.Command; 9 | import de.kittybot.kittybot.slashcommands.application.GenericHelpCommand; 10 | 11 | @SuppressWarnings("unused") 12 | public class RolesCommand extends Command{ 13 | 14 | public RolesCommand(){ 15 | super("roles", "Used to configure self assignable roles", Category.ROLES); 16 | addOptions( 17 | new AddCommand(), 18 | new RemoveCommand(), 19 | new ListCommand(), 20 | new GroupsCommand(), 21 | new GenericHelpCommand("To configure self assignable roles you need first need to create a group with `/roles groups add `.\n" + 22 | "Then you can add a role to this group by doing `/roles add <@role> `.\n" + 23 | "You can add as much as you like but only 20 of them are assignable by reactions via the specific emote.\n" + 24 | "Use `/roles list` to view all roles with groups in a nice message" 25 | ) 26 | ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/roles/roles/RemoveCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.roles.roles; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionRole; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import net.dv8tion.jda.api.Permission; 9 | 10 | import java.util.Collections; 11 | 12 | public class RemoveCommand extends GuildSubCommand{ 13 | 14 | public RemoveCommand(){ 15 | super("remove", "Removes a self assignable role"); 16 | addOptions( 17 | new CommandOptionRole("role", "The self assignable role to remove").required() 18 | ); 19 | addPermissions(Permission.ADMINISTRATOR); 20 | } 21 | 22 | @Override 23 | public void run(Options options, GuildInteraction ia){ 24 | var role = options.getRole("role"); 25 | var settings = ia.get(SettingsModule.class); 26 | if(settings.getSelfAssignableRoles(ia.getGuildId()).stream().noneMatch(r -> r.getRoleId() == role.getIdLong())){ 27 | ia.error("This role is not self assignable"); 28 | return; 29 | } 30 | settings.removeSelfAssignableRoles(ia.getGuildId(), Collections.singleton(role.getIdLong())); 31 | ia.reply("Removed self assignable role"); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/streams/streams/RemoveCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.streams.streams; 2 | 3 | import de.kittybot.kittybot.modules.StreamModule; 4 | import de.kittybot.kittybot.objects.streams.StreamType; 5 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 6 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | 10 | public class RemoveCommand extends GuildSubCommand{ 11 | 12 | public RemoveCommand(){ 13 | super("remove", "Removes a stream announcement"); 14 | addOptions( 15 | new CommandOptionString("username", "The username of the streamer").required() 16 | ); 17 | } 18 | 19 | @Override 20 | public void run(Options options, GuildInteraction ia){ 21 | var type = StreamType.TWITCH;//StreamType.byId(options.getInt("service")); 22 | var username = options.getString("username"); 23 | var success = ia.get(StreamModule.class).remove(username, ia.getGuildId(), type); 24 | if(!success){ 25 | ia.error("Could not find stream announcement for " + type.getName() + " with username: " + username + ". Check your spelling"); 26 | return; 27 | } 28 | ia.reply("Stream announcement for " + type.getName() + " with username: " + username + " removed"); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/tags/tags/SearchCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.tags.tags; 2 | 3 | import de.kittybot.kittybot.modules.TagsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import de.kittybot.kittybot.utils.MessageUtils; 9 | 10 | import java.util.stream.Collectors; 11 | 12 | public class SearchCommand extends GuildSubCommand{ 13 | 14 | public SearchCommand(){ 15 | super("search", "Used to search a tag"); 16 | addOptions( 17 | new CommandOptionString("name", "Tag name").required() 18 | ); 19 | } 20 | 21 | @Override 22 | public void run(Options options, GuildInteraction ia){ 23 | var tagName = options.getString("name"); 24 | var tags = ia.get(TagsModule.class).search(tagName, ia.getGuildId(), ia.getUserId()); 25 | 26 | if(tags.isEmpty()){ 27 | ia.reply("No tags found for `" + tagName + "`"); 28 | return; 29 | } 30 | // TODO add paginator 31 | ia.reply("**Following tags were found for `" + tagName + "`:**\n" + 32 | tags.stream().map(tag -> "• `" + tag.getName() + "` (" + MessageUtils.getUserMention(tag.getUserId()) + ")").collect(Collectors.joining("\n")) 33 | ); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Website Banner](.github/banner.png)](https://kittybot.de) 2 | 3 | [![KittyBot Support Guild](https://discordapp.com/api/guilds/608506410803658753/embed.png?style=shield)](https://discord.gg/sD3ABd5) 4 | [![Last Build Status](https://img.shields.io/teamcity/https/ci.kittybot.de/s/KittyBot_Bot_Master_Jar_Build.svg)](https://ci.kittybot.de/project/KittyBot_Bot?guest=1) 5 | [![Total Downloads](https://img.shields.io/github/downloads/KittyBot-Org/kittybot/total.svg)](https://github.com/KittyBot-Org/kittybot/releases) 6 | [![Docker Pulls](https://img.shields.io/docker/pulls/kittybot/kittybot.svg)](https://hub.docker.com/repository/docker/kittybot/kittybot) 7 | [![Docker Image Size](https://img.shields.io/docker/image-size/kittybot/kittybot/latest)](https://hub.docker.com/repository/docker/kittybot/kittybot) 8 | [![Docker Latest Version](https://img.shields.io/docker/v/kittybot/kittybot)](https://hub.docker.com/repository/docker/kittybot/kittybot) 9 | [![KittyBot License](https://img.shields.io/github/license/KittyBot-Org/KittyBot)](LICENSE) 10 | 11 | [CI Server](https://ci.kittybot.de/project/KittyBot_Bot?guest=1) 12 | 13 | [Docker Hub](https://hub.docker.com/repository/docker/kittybot/kittybot) 14 | 15 | [Website Project](https://github.com/KittyBot-Org/KittyBot-Website) 16 | 17 | [Website](https://kittybot.de) 18 | #### The only discord bot you need 19 | --- 20 | 21 | # hewe to manyage uw discowd 22 | 23 | //TODO: README.md 24 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/modules/ReactiveMessageModule.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.modules; 2 | 3 | import com.github.benmanes.caffeine.cache.Cache; 4 | import com.github.benmanes.caffeine.cache.Caffeine; 5 | import com.github.benmanes.caffeine.cache.stats.CacheStats; 6 | import de.kittybot.kittybot.objects.data.ReactiveMessage; 7 | import de.kittybot.kittybot.objects.module.Module; 8 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | 12 | public class ReactiveMessageModule extends Module{ 13 | 14 | private Cache reactiveMessages; 15 | 16 | @Override 17 | public void onEnable(){ 18 | this.reactiveMessages = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).recordStats().build(); 19 | } 20 | 21 | public void remove(long responseId){ 22 | reactiveMessages.invalidate(responseId); 23 | } 24 | 25 | public void add(GuildInteraction ia, long responseId, long allowed){ 26 | reactiveMessages.put( 27 | responseId, 28 | new ReactiveMessage(ia.getGuildId(), ia.getChannelId(), -1, responseId, ia.getUser().getIdLong(), ia.getData().getName(), 29 | allowed 30 | ) 31 | ); 32 | } 33 | 34 | public ReactiveMessage get(long responseId){ 35 | return reactiveMessages.getIfPresent(responseId); 36 | } 37 | 38 | public CacheStats getStats(){ 39 | return this.reactiveMessages.stats(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/ban/RemoveCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.ban; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionUser; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | 9 | public class RemoveCommand extends GuildSubCommand{ 10 | 11 | public RemoveCommand(){ 12 | super("remove", "Removes a ban"); 13 | addOptions( 14 | new CommandOptionUser("user", "The user to unban").required(), 15 | new CommandOptionString("reason", "The unban reason") 16 | ); 17 | } 18 | 19 | @Override 20 | public void run(Options options, GuildInteraction ia){ 21 | var user = options.getUser("user"); 22 | if(user == null){ 23 | ia.error("Please provide a valid user id"); 24 | return; 25 | } 26 | var reason = options.has("reason") ? options.getString("reason") : "Unbanned by " + ia.getMember().getAsMention(); 27 | ia.getGuild().unban(user).reason(reason).queue(success -> 28 | ia.reply("Unbanned " + user.getAsMention() + " with reason: " + reason), 29 | error -> ia.error("Failed to unban " + user.getAsMention() + " for reason: `" + error.getMessage() + "`") 30 | ); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/guilds/guild/tags/GetTagsRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.guilds.guild.tags; 2 | 3 | import de.kittybot.kittybot.modules.TagsModule; 4 | import de.kittybot.kittybot.modules.WebModule; 5 | import de.kittybot.kittybot.objects.module.Modules; 6 | import io.javalin.http.Context; 7 | import io.javalin.http.Handler; 8 | import net.dv8tion.jda.api.utils.data.DataArray; 9 | import net.dv8tion.jda.api.utils.data.DataObject; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.time.ZoneOffset; 13 | import java.util.stream.Collectors; 14 | 15 | public class GetTagsRoute implements Handler{ 16 | 17 | private final Modules modules; 18 | 19 | public GetTagsRoute(Modules modules){ 20 | this.modules = modules; 21 | } 22 | 23 | @Override 24 | public void handle(@NotNull Context ctx){ 25 | var guild = this.modules.get(WebModule.class).getGuild(ctx); 26 | var tags = this.modules.get(TagsModule.class).get(guild.getIdLong()); 27 | WebModule.ok(ctx, DataObject.empty().put("tags", DataArray.fromCollection( 28 | tags.stream().map(tag -> DataObject.empty() 29 | .put("id", tag.getId()) 30 | .put("name", tag.getName()) 31 | .put("content", tag.getContent()) 32 | .put("user_id", tag.getUserId()) 33 | .put("guild_id", tag.getGuildId()) 34 | .put("created_at", tag.getCreatedAt().toEpochSecond(ZoneOffset.UTC)) 35 | ).collect(Collectors.toSet()) 36 | ))); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/guilds/guild/tags/tag/PostTagRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.guilds.guild.tags.tag; 2 | 3 | import de.kittybot.kittybot.modules.TagsModule; 4 | import de.kittybot.kittybot.modules.WebModule; 5 | import de.kittybot.kittybot.objects.module.Modules; 6 | import io.javalin.http.BadRequestResponse; 7 | import io.javalin.http.Context; 8 | import io.javalin.http.Handler; 9 | import io.javalin.http.InternalServerErrorResponse; 10 | import net.dv8tion.jda.api.utils.data.DataObject; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | public class PostTagRoute implements Handler{ 14 | 15 | private final Modules modules; 16 | 17 | public PostTagRoute(Modules modules){ 18 | this.modules = modules; 19 | } 20 | 21 | @Override 22 | public void handle(@NotNull Context ctx){ 23 | var tagId = this.modules.get(WebModule.class).getTagId(ctx); 24 | var json = DataObject.fromJson(ctx.body()); 25 | var name = json.getString("name", ""); 26 | var content = json.getString("content", ""); 27 | var userId = json.getLong("user_id", -1); 28 | if(name.isBlank() || content.isBlank() || userId == -1){ 29 | throw new BadRequestResponse("Please provide a valid name, content or userId"); 30 | } 31 | if(!this.modules.get(TagsModule.class).edit(tagId, name, content, userId)){ 32 | throw new InternalServerErrorResponse("Error while updating tag"); 33 | } 34 | WebModule.accepted(ctx); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/guilds/guild/invites/GetInvitesRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.guilds.guild.invites; 2 | 3 | import de.kittybot.kittybot.modules.InviteModule; 4 | import de.kittybot.kittybot.modules.WebModule; 5 | import de.kittybot.kittybot.objects.module.Modules; 6 | import io.javalin.http.Context; 7 | import io.javalin.http.Handler; 8 | import net.dv8tion.jda.api.utils.data.DataArray; 9 | import net.dv8tion.jda.api.utils.data.DataObject; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.HashMap; 13 | import java.util.stream.Collectors; 14 | 15 | public class GetInvitesRoute implements Handler{ 16 | 17 | private final Modules modules; 18 | 19 | public GetInvitesRoute(Modules modules){ 20 | this.modules = modules; 21 | } 22 | 23 | @Override 24 | public void handle(@NotNull Context ctx){ 25 | var guild = this.modules.get(WebModule.class).getGuild(ctx); 26 | 27 | var guildInvites = this.modules.get(InviteModule.class).getGuildInvites(guild.getIdLong()); 28 | if(guildInvites == null){ 29 | guildInvites = new HashMap<>(); 30 | } 31 | var invites = DataArray.fromCollection( 32 | guildInvites.values().stream().map( 33 | invite -> DataObject.empty().put("code", invite.getCode()).put("user_id", invite.getUserId()).put("uses", invite.getUses()) 34 | ).collect(Collectors.toSet()) 35 | ); 36 | WebModule.ok(ctx, DataObject.empty().put("invites", invites)); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/tags/TagCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.tags; 2 | 3 | import de.kittybot.kittybot.modules.TagsModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.slashcommands.interaction.response.InteractionResponse; 10 | import net.dv8tion.jda.api.entities.Message; 11 | 12 | @SuppressWarnings("unused") 13 | public class TagCommand extends RunGuildCommand{ 14 | 15 | public TagCommand(){ 16 | super("tag", "Displays a tag", Category.TAGS); 17 | addOptions( 18 | new CommandOptionString("name", "The tag name").required() 19 | ); 20 | } 21 | 22 | @Override 23 | public void run(Options options, GuildInteraction ia){ 24 | var tagName = options.getString("name"); 25 | var tag = ia.get(TagsModule.class).get(tagName, ia.getGuildId()); 26 | 27 | if(tag == null){ 28 | ia.error("Tag with name `" + tagName + "` not found"); 29 | return; 30 | } 31 | ia.reply(new InteractionResponse.Builder().setContent(tag.getContent()) 32 | .setAllowedMentions(Message.MentionType.EMOTE, Message.MentionType.CHANNEL) 33 | .build() 34 | ); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/PauseCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionBoolean; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.utils.MusicUtils; 10 | 11 | @SuppressWarnings("unused") 12 | public class PauseCommand extends RunGuildCommand{ 13 | 14 | public PauseCommand(){ 15 | super("pause", "Pauses/Unpauses the current track", Category.MUSIC); 16 | addOptions( 17 | new CommandOptionBoolean("pause", "If it should pause or resume. Omit for toggle") 18 | ); 19 | } 20 | 21 | @Override 22 | public void run(Options options, GuildInteraction ia){ 23 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 24 | if(!MusicUtils.checkCommandRequirements(ia, scheduler)){ 25 | return; 26 | } 27 | if(!MusicUtils.checkMusicPermissions(ia, scheduler)){ 28 | return; 29 | } 30 | boolean pause; 31 | if(options.has("pause")){ 32 | pause = options.getBoolean("pause"); 33 | } 34 | else{ 35 | pause = !scheduler.isPaused(); 36 | } 37 | scheduler.setPaused(pause); 38 | ia.reply("Toggled pause"); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/main/Main.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.main; 2 | 3 | import de.kittybot.kittybot.objects.enums.Environment; 4 | import de.kittybot.kittybot.objects.exceptions.MissingConfigValuesException; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import javax.security.auth.login.LoginException; 9 | import java.io.IOException; 10 | 11 | public class Main{ 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(Main.class); 14 | 15 | public static void main(String... args) throws InterruptedException{ 16 | try{ 17 | LOG.info("Starting KittyBot in " + Environment.getCurrent() + " mode..."); 18 | LOG.info("\n" + 19 | "\n" + 20 | " _ ___ _ _ ______ _ \n" + 21 | " | | / (_) | | | | ___ \\ | | \n" + 22 | " | |/ / _| |_| |_ _ _| |_/ / ___ | |_ \n" + 23 | " | \\| | __| __| | | | ___ \\/ _ \\| __|\n" + 24 | " | |\\ \\ | |_| |_| |_| | |_/ / (_) | |_ \n" + 25 | " \\_| \\_/_|\\__|\\__|\\__, \\____/ \\___/ \\__|\n" + 26 | " __/ | \n" + 27 | " |___/ \n" + 28 | "\n" + 29 | " https://github.com/KittyBot-Org/KittyBot\n" 30 | ); 31 | new KittyBot(); 32 | } 33 | catch(LoginException | IOException | MissingConfigValuesException e){ 34 | LOG.error("Error while starting KittyBot", e); 35 | System.exit(-1); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/RepeatCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.objects.music.RepeatMode; 5 | import de.kittybot.kittybot.slashcommands.application.Category; 6 | import de.kittybot.kittybot.slashcommands.application.CommandOptionChoice; 7 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 8 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 9 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 10 | import de.kittybot.kittybot.slashcommands.interaction.Options; 11 | 12 | @SuppressWarnings("unused") 13 | public class RepeatCommand extends RunGuildCommand{ 14 | 15 | public RepeatCommand(){ 16 | super("repeat", "Sets the repeat mode", Category.MUSIC); 17 | addOptions( 18 | new CommandOptionString("type", "The repeat mode").required() 19 | .addChoices( 20 | new CommandOptionChoice<>("off", "OFF"), 21 | new CommandOptionChoice<>("song", "SONG"), 22 | new CommandOptionChoice<>("queue", "QUEUE") 23 | ) 24 | ); 25 | } 26 | 27 | @Override 28 | public void run(Options options, GuildInteraction ia){ 29 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 30 | var repeatMode = RepeatMode.valueOf(options.getString("type")); 31 | 32 | scheduler.setRepeatMode(repeatMode); 33 | ia.reply("Set repeat mode to `" + repeatMode.getName() + "`"); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/tags/tags/ListCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.tags.tags; 2 | 3 | import de.kittybot.kittybot.modules.TagsModule; 4 | import de.kittybot.kittybot.objects.settings.Tag; 5 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionUser; 6 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.utils.MessageUtils; 10 | 11 | import java.util.List; 12 | import java.util.stream.Collectors; 13 | 14 | public class ListCommand extends GuildSubCommand{ 15 | 16 | public ListCommand(){ 17 | super("list", "Used to list tags"); 18 | addOptions( 19 | new CommandOptionUser("user", "Filter by user") 20 | ); 21 | } 22 | 23 | @Override 24 | public void run(Options options, GuildInteraction ia){ 25 | List tags; 26 | if(options.has("user")){ 27 | tags = ia.get(TagsModule.class).get(ia.getGuildId(), options.getLong("user")); 28 | } 29 | else{ 30 | tags = ia.get(TagsModule.class).get(ia.getGuildId()); 31 | } 32 | 33 | if(tags.isEmpty()){ 34 | ia.reply("No tags created yet"); 35 | return; 36 | } 37 | // TODO add paginator 38 | ia.reply("**Following tags exist:**\n" + tags.stream().map(tag -> "• `" + tag.getName() + "` (" + MessageUtils.getUserMention(tag.getUserId()) + ")").collect(Collectors.joining("\n"))); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/Category.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application; 2 | 3 | import de.kittybot.kittybot.objects.enums.Emoji; 4 | import de.kittybot.kittybot.utils.Config; 5 | import net.dv8tion.jda.api.utils.data.DataObject; 6 | 7 | public enum Category{ 8 | 9 | INFORMATION(Emoji.INFORMATION, "Information"), 10 | UTILITIES(Emoji.UTILITIES, "Utilities"), 11 | SNIPE(Emoji.SNIPE, "Snipe"), 12 | ROLES(Emoji.ROLES, "Roles"), 13 | MUSIC(Emoji.MUSIC, "Music"), 14 | NEKO(Emoji.NEKO, "Neko"), 15 | ADMIN(Emoji.ADMIN, "Admin"), 16 | NOTIFICATION(Emoji.NOTIFICATION, "Notification"), 17 | ANNOUNCEMENT(Emoji.ANNOUNCEMENT, "Stream Announcement"), 18 | TAGS(Emoji.TAGS, "Tags"), 19 | DEV(Emoji.DEV, "Developer"); 20 | 21 | private final Emoji emote; 22 | private final String name; 23 | 24 | Category(Emoji emote, String name){ 25 | this.emote = emote; 26 | this.name = name; 27 | } 28 | 29 | public String getEmote(){ 30 | return this.emote.get(); 31 | } 32 | 33 | public String getName(){ 34 | return this.name; 35 | } 36 | 37 | public DataObject toJSON(){ 38 | return DataObject.empty() 39 | .put("name", this.name) 40 | .put("url", getUrl()) 41 | .put("emote", getEmoteUrl()); 42 | } 43 | 44 | public String getUrl(){ 45 | return "https://" + Config.ORIGIN_URL + "/commands#" + this.name.toLowerCase(); 46 | } 47 | 48 | public String getEmoteUrl(){ 49 | return "https://cdn.discordapp.com/emojis/" + this.emote.getId() + ".png"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/roles/roles/groups/RemoveCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.roles.roles.groups; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import net.dv8tion.jda.api.Permission; 9 | 10 | import java.util.Collections; 11 | 12 | public class RemoveCommand extends GuildSubCommand{ 13 | 14 | public RemoveCommand(){ 15 | super("remove", "Removes a self assignable role group & its roles"); 16 | addOptions( 17 | new CommandOptionString("name", "The self assignable role to remove").required() 18 | ); 19 | addPermissions(Permission.ADMINISTRATOR); 20 | } 21 | 22 | @Override 23 | public void run(Options options, GuildInteraction ia){ 24 | var name = options.getString("name"); 25 | var settings = ia.get(SettingsModule.class); 26 | var group = settings.getSelfAssignableRoleGroups(ia.getGuildId()).stream().filter(g -> g.getName().equalsIgnoreCase(name)).findFirst(); 27 | if(group.isEmpty()){ 28 | ia.error("Group with name `" + name + "` not found"); 29 | return; 30 | } 31 | settings.removeSelfAssignableRoleGroups(ia.getGuildId(), Collections.singleton(group.get().getId())); 32 | ia.reply("Removed group with name `" + name + "`"); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/tags/tags/InfoCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.tags.tags; 2 | 3 | import de.kittybot.kittybot.modules.TagsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import de.kittybot.kittybot.utils.MessageUtils; 9 | import de.kittybot.kittybot.utils.TimeUtils; 10 | 11 | public class InfoCommand extends GuildSubCommand{ 12 | 13 | public InfoCommand(){ 14 | super("info", "Used to get info about a tag"); 15 | addOptions( 16 | new CommandOptionString("name", "Tag name").required() 17 | ); 18 | } 19 | 20 | @Override 21 | public void run(Options options, GuildInteraction ia){ 22 | var tagName = options.getString("name"); 23 | var tag = ia.get(TagsModule.class).get(tagName, ia.getGuildId()); 24 | 25 | if(tag == null){ 26 | ia.error("Tag with name `" + tagName + "` not found"); 27 | return; 28 | } 29 | ia.reply(builder -> builder 30 | .setTitle("Tag `" + tagName + "`") 31 | .addField("Owner", MessageUtils.getUserMention(tag.getUserId()), false) 32 | .addField("ID", Long.toString(tag.getId()), false) 33 | .addField("Created at", TimeUtils.format(tag.getCreatedAt()), false) 34 | .addField("Updated at", (tag.getUpdatedAt() == null ? "not edited" : TimeUtils.format(tag.getUpdatedAt())), false) 35 | ); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/info/HelpCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.info; 2 | 3 | import de.kittybot.kittybot.objects.enums.Emoji; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import de.kittybot.kittybot.utils.Config; 9 | import de.kittybot.kittybot.utils.MessageUtils; 10 | 11 | @SuppressWarnings("unused") 12 | public class HelpCommand extends RunCommand{ 13 | 14 | public HelpCommand(){ 15 | super("help", "Shows help", Category.INFORMATION); 16 | } 17 | 18 | @Override 19 | public void run(Options options, Interaction ia){ 20 | ia.reply(builder -> builder 21 | .setAuthor("Help", Config.ORIGIN_URL, ia.getSelfUser().getEffectiveAvatarUrl()) 22 | .setThumbnail(ia.getSelfUser().getEffectiveAvatarUrl()) 23 | .setDescription( 24 | "Hello " + ia.getUser().getAsMention() + "\n" + 25 | "KittyBot uses the new " + Emoji.SLASH.get() + " Slash Commands by Discord!\n" + 26 | "To see all available commands just type `/` or use `/commands`\n\n" + 27 | MessageUtils.maskLink("Website", Config.ORIGIN_URL) + " | " + 28 | MessageUtils.maskLink("Invite Me", Config.BOT_INVITE_URL) + " | " + 29 | MessageUtils.maskLink("Support Server", Config.SUPPORT_GUILD_INVITE_URL) + " | " + 30 | MessageUtils.maskLink("GitHub", "https://github.com/KittyBot-Org/KittyBot") 31 | ) 32 | ); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/interaction/InteractionData.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.interaction; 2 | 3 | import net.dv8tion.jda.api.utils.data.DataObject; 4 | import net.dv8tion.jda.internal.entities.EntityBuilder; 5 | import net.dv8tion.jda.internal.entities.GuildImpl; 6 | 7 | import java.util.List; 8 | 9 | public class InteractionData implements InteractionOptionsHolder{ 10 | 11 | private final long id; 12 | private final String name; 13 | private final List options; 14 | private final ResolvedMentions resolvedMentions; 15 | 16 | public InteractionData(long id, String name, List options, ResolvedMentions resolvedMentions){ 17 | this.id = id; 18 | this.name = name; 19 | this.options = options; 20 | this.resolvedMentions = resolvedMentions; 21 | } 22 | 23 | public static InteractionData fromJSON(DataObject json, EntityBuilder entityBuilder, GuildImpl guild){ 24 | return new InteractionData( 25 | json.getLong("id"), 26 | json.getString("name"), 27 | InteractionDataOption.fromJSON(json.optArray("options").orElse(null)), 28 | new ResolvedMentions(json.optObject("resolved").orElse(DataObject.empty()), entityBuilder, guild) 29 | ); 30 | } 31 | 32 | public long getId(){ 33 | return this.id; 34 | } 35 | 36 | public String getName(){ 37 | return this.name; 38 | } 39 | 40 | public List getOptions(){ 41 | return this.options; 42 | } 43 | 44 | public ResolvedMentions getResolvedMentions(){ 45 | return this.resolvedMentions; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/roles/roles/groups/AddCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.roles.roles.groups; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.objects.settings.SelfAssignableRoleGroup; 5 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionInteger; 6 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 7 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 8 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 9 | import de.kittybot.kittybot.slashcommands.interaction.Options; 10 | import net.dv8tion.jda.api.Permission; 11 | 12 | import java.util.Collections; 13 | 14 | public class AddCommand extends GuildSubCommand{ 15 | 16 | public AddCommand(){ 17 | super("add", "Adds a new self assignable role group"); 18 | addOptions( 19 | new CommandOptionString("name", "The self assignable role to add").required(), 20 | new CommandOptionInteger("max-roles", "The amount of max roles you can get from this group") 21 | ); 22 | addPermissions(Permission.ADMINISTRATOR); 23 | } 24 | 25 | @Override 26 | public void run(Options options, GuildInteraction ia){ 27 | var name = options.getString("name"); 28 | var maxRoles = options.has("max-roles") ? options.getInt("max-roles") : -1; 29 | ia.get(SettingsModule.class).addSelfAssignableRoleGroups(ia.getGuildId(), Collections.singleton(new SelfAssignableRoleGroup(-1, ia.getGuildId(), name, maxRoles))); 30 | ia.reply("New group added"); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/utils/exporters/DiscordPingExporter.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.utils.exporters; 2 | 3 | import de.kittybot.kittybot.modules.PrometheusModule; 4 | import de.kittybot.kittybot.objects.module.Modules; 5 | import io.prometheus.client.Gauge; 6 | 7 | import java.util.concurrent.TimeUnit; 8 | 9 | public class DiscordPingExporter{ 10 | 11 | // ty Natan 👀 https://github.com/Mantaro/MantaroBot/blob/master/src/main/java/net/kodehawa/mantarobot/utils/exporters/DiscordLatencyExports.java 12 | 13 | private static final Gauge GATEWAY_PING = Gauge.build() 14 | .name("kittybot_gateway_ping") 15 | .help("Gateway ping per shard in ms") 16 | .labelNames("shard") 17 | .create(); 18 | 19 | private static final Gauge REST_PING = Gauge.build() 20 | .name("kittybot_rest_ping") 21 | .help("Rest latency in ms") 22 | .create(); 23 | 24 | public void register(Modules modules){ 25 | GATEWAY_PING.register(); 26 | REST_PING.register(); 27 | modules.scheduleAtFixedRate(() -> { 28 | var shardManager = modules.getShardManager(); 29 | if(shardManager == null){ 30 | return; 31 | } 32 | var shards = shardManager.getShardCache(); 33 | shards.forEach(shard -> { 34 | var ping = shard.getGatewayPing(); 35 | 36 | if(ping >= 0){ 37 | GATEWAY_PING.labels(String.valueOf(shard.getShardInfo().getShardId())).set(ping); 38 | } 39 | }); 40 | if(shards.size() > 0){ 41 | shards.iterator().next().getRestPing().queue(REST_PING::set); 42 | } 43 | }, 0, PrometheusModule.UPDATE_PERIOD.toMillis(), TimeUnit.MILLISECONDS); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/SeekCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionInteger; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.utils.MusicUtils; 10 | import de.kittybot.kittybot.utils.TimeUtils; 11 | 12 | @SuppressWarnings("unused") 13 | public class SeekCommand extends RunGuildCommand{ 14 | 15 | public SeekCommand(){ 16 | super("seek", "Seeks the current song to given amount of seconds", Category.MUSIC); 17 | addOptions( 18 | new CommandOptionInteger("seconds", "Seconds to seek to") 19 | ); 20 | } 21 | 22 | @Override 23 | public void run(Options options, GuildInteraction ia){ 24 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 25 | if(!MusicUtils.checkCommandRequirements(ia, scheduler)){ 26 | return; 27 | } 28 | if(!MusicUtils.checkMusicPermissions(ia, scheduler)){ 29 | return; 30 | } 31 | var newPos = options.getLong("seconds") * 1000; 32 | var lavalinkPlayer = scheduler.getPlayer(); 33 | if(newPos > scheduler.getPlayingTrack().getInfo().getLength()){ 34 | scheduler.next(true); 35 | ia.reply("Skipped to next track"); 36 | return; 37 | } 38 | lavalinkPlayer.seekTo(newPos); 39 | ia.reply("Sought to `" + TimeUtils.formatDuration(newPos) + "`"); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/RewindCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionInteger; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.utils.MusicUtils; 10 | import de.kittybot.kittybot.utils.TimeUtils; 11 | 12 | @SuppressWarnings("unused") 13 | public class RewindCommand extends RunGuildCommand{ 14 | 15 | public RewindCommand(){ 16 | super("rewind", "Rewinds the current song by given amount of seconds", Category.MUSIC); 17 | addOptions( 18 | new CommandOptionInteger("seconds", "Seconds to rewind").required() 19 | ); 20 | } 21 | 22 | @Override 23 | public void run(Options options, GuildInteraction ia){ 24 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 25 | if(!MusicUtils.checkCommandRequirements(ia, scheduler)){ 26 | return; 27 | } 28 | if(!MusicUtils.checkMusicPermissions(ia, scheduler)){ 29 | return; 30 | } 31 | var rewind = options.getInt("seconds") * 1000; 32 | var lavalinkPlayer = scheduler.getPlayer(); 33 | var position = lavalinkPlayer.getTrackPosition(); 34 | var newPos = position - rewind; 35 | if(newPos <= 0){ 36 | newPos = 0; 37 | } 38 | lavalinkPlayer.seekTo(newPos); 39 | ia.reply("Rewinded track to `" + TimeUtils.formatDuration(newPos) + "`"); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/tags/tags/UnpublishCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.tags.tags; 2 | 3 | import de.kittybot.kittybot.modules.TagsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 5 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 6 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 7 | import de.kittybot.kittybot.slashcommands.interaction.Options; 8 | import net.dv8tion.jda.api.Permission; 9 | import net.dv8tion.jda.api.utils.MarkdownSanitizer; 10 | 11 | public class UnpublishCommand extends GuildSubCommand{ 12 | 13 | public UnpublishCommand(){ 14 | super("unpublish", "Unpublishes a published tag from slash commands"); 15 | addOptions( 16 | new CommandOptionString("name", "Tag name").required() 17 | ); 18 | addPermissions(Permission.MANAGE_SERVER); 19 | } 20 | 21 | @Override 22 | public void run(Options options, GuildInteraction ia){ 23 | var name = options.getString("name"); 24 | var tagsModule = ia.get(TagsModule.class); 25 | var tag = tagsModule.get(name, ia.getGuildId()); 26 | if(tag == null){ 27 | ia.error("Tag with name `" + MarkdownSanitizer.escape(name) + "` not found"); 28 | return; 29 | } 30 | if(tag.getCommandId() == -1L){ 31 | ia.error("Tag with name `" + MarkdownSanitizer.escape(name) + "` is not published"); 32 | return; 33 | } 34 | var res = tagsModule.removePublishedTag(ia.getGuildId(), tag.getCommandId()); 35 | if(!res){ 36 | ia.error("Something went wrong while removing your tag from slash commands"); 37 | return; 38 | } 39 | ia.reply("Successfully removed tag from slash commands"); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/SubBaseCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 5 | import de.kittybot.kittybot.slashcommands.application.PermissionHolder; 6 | import net.dv8tion.jda.api.Permission; 7 | import net.dv8tion.jda.api.utils.data.DataObject; 8 | 9 | import java.util.Arrays; 10 | import java.util.HashSet; 11 | import java.util.Set; 12 | import java.util.stream.Collectors; 13 | 14 | public abstract class SubBaseCommand extends CommandOption implements PermissionHolder{ 15 | 16 | private final Set permissions; 17 | private boolean devOnly; 18 | 19 | public SubBaseCommand(String name, String description){ 20 | super(CommandOptionType.SUB_COMMAND, name, description); 21 | this.devOnly = false; 22 | this.permissions = new HashSet<>(); 23 | } 24 | 25 | public void devOnly(){ 26 | this.devOnly = true; 27 | } 28 | 29 | public boolean isDevOnly(){ 30 | return this.devOnly; 31 | } 32 | 33 | public void addPermissions(Permission... permissions){ 34 | this.permissions.addAll(Arrays.asList(permissions)); 35 | } 36 | 37 | public Set getPermissions(){ 38 | return this.permissions; 39 | } 40 | 41 | @Override 42 | public Void parseValue(Object value){ 43 | throw new UnsupportedOperationException("This is SubCommand"); 44 | } 45 | 46 | @Override 47 | public DataObject toDetailedJSON(){ 48 | return super.toDetailedJSON() 49 | .put("permissions", this.permissions.stream().map(Permission::getName).collect(Collectors.toList())) 50 | .put("dev_only", this.devOnly); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/slashcommands/application/options/SubCommandGroup.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.slashcommands.application.options; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.CommandOption; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOptionType; 5 | import de.kittybot.kittybot.slashcommands.application.PermissionHolder; 6 | import net.dv8tion.jda.api.Permission; 7 | import net.dv8tion.jda.api.utils.data.DataObject; 8 | 9 | import java.util.Arrays; 10 | import java.util.HashSet; 11 | import java.util.Set; 12 | import java.util.stream.Collectors; 13 | 14 | public class SubCommandGroup extends CommandOption implements PermissionHolder{ 15 | 16 | private final Set permissions; 17 | private boolean devOnly; 18 | 19 | public SubCommandGroup(String name, String description){ 20 | super(CommandOptionType.SUB_COMMAND_GROUP, name, description); 21 | this.devOnly = false; 22 | this.permissions = new HashSet<>(); 23 | } 24 | 25 | public void devOnly(){ 26 | this.devOnly = true; 27 | } 28 | 29 | public boolean isDevOnly(){ 30 | return this.devOnly; 31 | } 32 | 33 | public void addPermissions(Permission... permissions){ 34 | this.permissions.addAll(Arrays.asList(permissions)); 35 | } 36 | 37 | public Set getPermissions(){ 38 | return this.permissions; 39 | } 40 | 41 | @Override 42 | public Void parseValue(Object value){ 43 | throw new UnsupportedOperationException("This is SubCommand group"); 44 | } 45 | 46 | @Override 47 | public DataObject toDetailedJSON(){ 48 | return super.toDetailedJSON() 49 | .put("permissions", this.permissions.stream().map(Permission::getName).collect(Collectors.toList())) 50 | .put("dev_only", this.devOnly); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/data/Paginator.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.data; 2 | 3 | import net.dv8tion.jda.api.EmbedBuilder; 4 | import net.dv8tion.jda.api.entities.Message; 5 | import net.dv8tion.jda.api.entities.MessageEmbed; 6 | 7 | import java.util.function.BiFunction; 8 | 9 | public class Paginator{ 10 | 11 | private final long guildId, channelId, messageId, authorId; 12 | private final int maxPages; 13 | private final BiFunction embedFunction; 14 | private int currentPage; 15 | 16 | public Paginator(Message message, long authorId, int maxPages, BiFunction embedFunction){ 17 | this.guildId = message.getGuild().getIdLong(); 18 | this.channelId = message.getChannel().getIdLong(); 19 | this.messageId = message.getIdLong(); 20 | this.authorId = authorId; 21 | this.currentPage = 0; 22 | this.maxPages = maxPages; 23 | this.embedFunction = embedFunction; 24 | } 25 | 26 | public long getGuildId(){ 27 | return this.guildId; 28 | } 29 | 30 | public long getChannelId(){ 31 | return this.channelId; 32 | } 33 | 34 | public long getMessageId(){ 35 | return this.messageId; 36 | } 37 | 38 | public long getAuthorId(){ 39 | return this.authorId; 40 | } 41 | 42 | public int getCurrentPage(){ 43 | return this.currentPage; 44 | } 45 | 46 | public int getMaxPages(){ 47 | return this.maxPages; 48 | } 49 | 50 | public void previousPage(){ 51 | this.currentPage--; 52 | } 53 | 54 | public void nextPage(){ 55 | this.currentPage++; 56 | } 57 | 58 | public MessageEmbed constructEmbed(){ 59 | return this.embedFunction.apply(this.currentPage, new EmbedBuilder().setFooter("Page " + (this.currentPage + 1) + "/" + this.maxPages)).build(); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/modules/LavalinkModule.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.modules; 2 | 3 | import de.kittybot.kittybot.objects.module.Module; 4 | import de.kittybot.kittybot.utils.Config; 5 | import lavalink.client.io.jda.JdaLavalink; 6 | import lavalink.client.io.jda.JdaLink; 7 | import net.dv8tion.jda.api.events.GenericEvent; 8 | import net.dv8tion.jda.api.hooks.VoiceDispatchInterceptor; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import javax.annotation.Nonnull; 13 | import java.net.URI; 14 | import java.net.URISyntaxException; 15 | 16 | public class LavalinkModule extends Module{ 17 | 18 | private static final Logger LOG = LoggerFactory.getLogger(LavalinkModule.class); 19 | 20 | private JdaLavalink lavalink; 21 | 22 | @Override 23 | public void onEnable(){ 24 | this.lavalink = new JdaLavalink(String.valueOf(Config.BOT_ID), 1, guildId -> modules.getJDA(guildId)); 25 | try{ 26 | for(var node : Config.LAVALINK_NODES){ 27 | lavalink.addNode(new URI(node.getProtocol() + "://" + node.getHost() + ":" + node.getPort()), node.getPassword()); 28 | } 29 | } 30 | catch(URISyntaxException e){ 31 | LOG.error("Error while connecting to lavalink node", e); 32 | } 33 | } 34 | 35 | public JdaLink getLink(long guildId){ 36 | return this.lavalink.getLink(guildId); 37 | } 38 | 39 | protected JdaLink getExistingLink(long guildId){ 40 | return this.lavalink.getExistingLink(guildId); 41 | } 42 | 43 | public JdaLavalink getLavalink(){ 44 | return this.lavalink; 45 | } 46 | 47 | @Override 48 | public void onGenericEvent(@Nonnull GenericEvent event){ 49 | this.lavalink.onEvent(event); 50 | } 51 | 52 | public VoiceDispatchInterceptor getVoiceInterceptor(){ 53 | return this.lavalink.getVoiceInterceptor(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/music/ForwardCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.music; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionInteger; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.utils.MusicUtils; 10 | import de.kittybot.kittybot.utils.TimeUtils; 11 | 12 | @SuppressWarnings("unused") 13 | public class ForwardCommand extends RunGuildCommand{ 14 | 15 | public ForwardCommand(){ 16 | super("forward", "Forwards the current song by given amount of seconds", Category.MUSIC); 17 | addOptions( 18 | new CommandOptionInteger("seconds", "Seconds to forward").required() 19 | ); 20 | } 21 | 22 | @Override 23 | public void run(Options options, GuildInteraction ia){ 24 | var scheduler = ia.get(MusicModule.class).getScheduler(ia.getGuildId()); 25 | if(!MusicUtils.checkCommandRequirements(ia, scheduler)){ 26 | return; 27 | } 28 | if(!MusicUtils.checkMusicPermissions(ia, scheduler)){ 29 | return; 30 | } 31 | var forward = options.getInt("seconds") * 1000; 32 | var lavalinkPlayer = scheduler.getPlayer(); 33 | var position = lavalinkPlayer.getTrackPosition(); 34 | var newPos = position + forward; 35 | if(newPos > scheduler.getPlayingTrack().getInfo().getLength()){ 36 | scheduler.next(true); 37 | ia.reply("Skipped to next track"); 38 | return; 39 | } 40 | lavalinkPlayer.seekTo(newPos); 41 | ia.reply("Forwarded track to `" + TimeUtils.formatDuration(newPos) + "`"); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/resources/messages/join_messages.txt: -------------------------------------------------------------------------------- 1 | ${user} just joined the server - glhf! 2 | ${user} just joined. Everyone, look busy! 3 | ${user} just joined. Can I get a heal? 4 | ${user} joined your party. 5 | ${user} joined. You must construct additional pylons. 6 | Ermagherd. ${user} is here. 7 | Welcome, ${user}. Stay awhile and listen. 8 | Welcome, ${user}. We were expecting you ( ͡° ͜ʖ ͡°) 9 | Welcome, ${user}. We hope you brought pizza. 10 | Welcome ${user}. Leave your weapons by the door. 11 | A wild ${user} appeared. 12 | Swoooosh. ${user} just landed. 13 | Brace yourselves. ${user} just joined the server. 14 | ${user} just joined. Hide your bananas. 15 | ${user} just arrived. Seems OP - please nerf. 16 | ${user} just slid into the server. 17 | A ${user} has spawned in the server. 18 | Big ${user} showed up! 19 | Where’s ${user}? In the server! 20 | ${user} hopped into the server. Kangaroo!! 21 | ${user} just showed up. Hold my beer. 22 | Challenger approaching - ${user} has appeared! 23 | It's a bird! It's a plane! Nevermind, it's just ${user}. 24 | It's ${user}! Praise the sun! \\\\[T]/ 25 | Never gonna give ${user} up. Never gonna let ${user} down. 26 | Ha! ${user} has joined! You activated my trap card! 27 | Cheers, love! ${user}'s here! 28 | Hey! Listen! ${user} has joined! 29 | We've been expecting you ${user} 30 | It's dangerous to go alone, take ${user}! 31 | ${user} has joined the server! It's super effective! 32 | Cheers, love! ${user} is here! 33 | ${user} is here, as the prophecy foretold. 34 | ${user} has arrived. Party's over. 35 | Ready player ${user} 36 | ${user} is here to kick butt and chew bubblegum. And ${user} is all out of gum. 37 | Hello. Is it ${user} you're looking for? 38 | ${user} has joined. Stay a while and listen! 39 | Roses are red, violets are blue, ${user} joined this server with you -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/enums/Neko.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.enums; 2 | 3 | public enum Neko{ 4 | 5 | BITE("bite", false, true), 6 | BLUSH("blush", false, true), 7 | CRY("cry", false, true), 8 | TICKLE("tickle", false, true), 9 | CUDDLE("cuddle", false, true), 10 | FEED("feed", false, true), 11 | DANCE("dance", false, true), 12 | EEVEE("eevee", false, true), 13 | EEVEE_GIF("eevee", false, false), 14 | HOLO("holo", false, false), 15 | HUG("hug", false, true), 16 | KISS("kiss", false, true), 17 | KITSUNE("kitsune", false, false), 18 | LICK("lick", false, true), 19 | NEKO_SFW("neko", false, false), 20 | NEKO_SFW_GIF("neko", false, true), 21 | PAT("pat", false, true), 22 | POKE("poke", false, true), 23 | SENKO("senko", false, false), 24 | SLAP("slap", false, true), 25 | SMILE("smile", false, true), 26 | TAIL("tail", false, true), 27 | FLUFF("fluff", false, true), 28 | 29 | ANAL("anal", true, true), 30 | BLOWJOB("blowjob", true, true), 31 | CUM("cum", true, true), 32 | FUCK("fuck", true, true), 33 | NEKO_NSFW("neko", true, false), 34 | NEKO_NSFW_GIF("neko", true, true), 35 | PUSSY_LICK("pussylick", true, true), 36 | SOLO("solo", true, true), 37 | THREESOME_FFF("threesome_fff", true, true), 38 | THREESOME_FFM("threesome_ffm", true, true), 39 | THREESOME_MMF("threesome_mmf", true, true), 40 | YAOI("yaoi", true, true), 41 | YURI("yuri", true, true); 42 | 43 | private final String name; 44 | private final boolean nsfw, gif; 45 | 46 | Neko(String name, boolean nsfw, boolean gif){ 47 | this.name = name; 48 | this.nsfw = nsfw; 49 | this.gif = gif; 50 | } 51 | 52 | public String getName(){ 53 | return this.name; 54 | } 55 | 56 | public boolean isNsfw(){ 57 | return this.nsfw; 58 | } 59 | 60 | public boolean isGIF(){ 61 | return this.gif; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/settings/Tag.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.settings; 2 | 3 | import de.kittybot.kittybot.jooq.tables.records.GuildTagsRecord; 4 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 5 | import de.kittybot.kittybot.slashcommands.interaction.response.InteractionResponse; 6 | import de.kittybot.kittybot.slashcommands.interaction.response.InteractionResponseType; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | public class Tag{ 11 | 12 | private final long id, guildId, userId, commandId; 13 | private final String name, content; 14 | private final LocalDateTime createdAt, updatedAt; 15 | 16 | public Tag(GuildTagsRecord record){ 17 | this.id = record.getId(); 18 | this.name = record.getName(); 19 | this.guildId = record.getGuildId(); 20 | this.userId = record.getUserId(); 21 | this.content = record.getContent(); 22 | this.createdAt = record.getCreatedAt(); 23 | this.updatedAt = record.getUpdatedAt(); 24 | this.commandId = record.getCommandId(); 25 | } 26 | 27 | public long getId(){ 28 | return this.id; 29 | } 30 | 31 | public String getName(){ 32 | return this.name; 33 | } 34 | 35 | public String getContent(){ 36 | return this.content; 37 | } 38 | 39 | public long getGuildId(){ 40 | return this.guildId; 41 | } 42 | 43 | public long getUserId(){ 44 | return this.userId; 45 | } 46 | 47 | public LocalDateTime getCreatedAt(){ 48 | return this.createdAt; 49 | } 50 | 51 | public LocalDateTime getUpdatedAt(){ 52 | return this.updatedAt; 53 | } 54 | 55 | public long getCommandId(){ 56 | return this.commandId; 57 | } 58 | 59 | public void process(GuildInteraction ia){ 60 | ia.reply(new InteractionResponse.Builder().setType(InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE).setContent(this.content).build()); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/settings/JoinMessageCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.settings; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionBoolean; 5 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 6 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | 10 | public class JoinMessageCommand extends GuildSubCommand{ 11 | 12 | public JoinMessageCommand(){ 13 | super("joinmessage", "Sets or enables/disables join messages"); 14 | addOptions( 15 | new CommandOptionBoolean("enabled", "Whether join messages are enabled"), 16 | new CommandOptionString("message", "The join message template") 17 | ); 18 | } 19 | 20 | @Override 21 | public void run(Options options, GuildInteraction ia){ 22 | var settings = ia.get(SettingsModule.class); 23 | var returnMessage = ""; 24 | if(options.has("enabled")){ 25 | var enabled = options.getBoolean("enabled"); 26 | settings.setJoinMessagesEnabled(ia.getGuildId(), enabled); 27 | returnMessage += "Join messages `" + (enabled ? "enabled" : "disabled") + "`\n"; 28 | } 29 | 30 | if(options.has("message")){ 31 | var message = options.getString("message"); 32 | settings.setJoinMessage(ia.getGuildId(), message); 33 | returnMessage += "Join message to:\n" + message + "\n"; 34 | } 35 | 36 | if(returnMessage.isBlank()){ 37 | ia.reply("Join message `" + (settings.areJoinMessagesEnabled(ia.getGuildId()) ? "enabled" : "disabled") + "` and set to:\n" + settings.getJoinMessage(ia.getGuildId())); 38 | return; 39 | } 40 | ia.reply(returnMessage); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/neko/ReactionCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.neko; 2 | 3 | import de.kittybot.kittybot.modules.RequestModule; 4 | import de.kittybot.kittybot.objects.enums.Neko; 5 | import de.kittybot.kittybot.slashcommands.application.Category; 6 | import de.kittybot.kittybot.slashcommands.application.RunCommand; 7 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionUser; 8 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 9 | import de.kittybot.kittybot.slashcommands.interaction.Options; 10 | import de.kittybot.kittybot.utils.annotations.Ignore; 11 | 12 | @Ignore 13 | public abstract class ReactionCommand extends RunCommand{ 14 | 15 | private final Neko neko; 16 | private final String text; 17 | 18 | protected ReactionCommand(Neko neko, String description, String text){ 19 | super(neko.getName(), description, Category.NEKO); 20 | this.neko = neko; 21 | this.text = text; 22 | addOptions( 23 | new CommandOptionUser("user", "The user to interact with").required() 24 | ); 25 | } 26 | 27 | @Override 28 | public void run(Options options, Interaction ia){ 29 | var user = options.getUser("user"); 30 | var message = new StringBuilder(); 31 | if(user.getIdLong() == ia.getUserId()){ 32 | message 33 | .append("You are not allowed to ") 34 | .append(getName()) 35 | .append(" yourself so I ") 36 | .append(getName()) 37 | .append(" you ") 38 | .append(ia.getUser().getAsMention()); 39 | } 40 | else{ 41 | message 42 | .append(ia.getUser().getAsMention()) 43 | .append(" ") 44 | .append(this.text) 45 | .append(" ") 46 | .append(user.getAsMention()); 47 | } 48 | ia.reply(builder -> builder 49 | .setDescription(message) 50 | .setImage(ia.get(RequestModule.class).getNeko(this.neko)) 51 | ); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/settings/LeaveMessageCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.settings; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionBoolean; 5 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 6 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | 10 | public class LeaveMessageCommand extends GuildSubCommand{ 11 | 12 | public LeaveMessageCommand(){ 13 | super("leavemessage", "Sets or enables/disables leave messages"); 14 | addOptions( 15 | new CommandOptionBoolean("enabled", "Whether leave messages are enabled"), 16 | new CommandOptionString("message", "The leave message template") 17 | ); 18 | } 19 | 20 | @Override 21 | public void run(Options options, GuildInteraction ia){ 22 | var settings = ia.get(SettingsModule.class); 23 | var returnMessage = ""; 24 | if(options.has("enabled")){ 25 | var enabled = options.getBoolean("enabled"); 26 | settings.setLeaveMessagesEnabled(ia.getGuildId(), enabled); 27 | returnMessage += "Leave messages `" + (enabled ? "enabled" : "disabled") + "`\n"; 28 | } 29 | 30 | if(options.has("message")){ 31 | var message = options.getString("message"); 32 | settings.setLeaveMessage(ia.getGuildId(), message); 33 | returnMessage += "Leave message to:\n" + message + "\n"; 34 | } 35 | 36 | if(returnMessage.isBlank()){ 37 | ia.reply("Leave message `" + (settings.areLeaveMessagesEnabled(ia.getGuildId()) ? "enabled" : "disabled") + "` and set to:\n" + settings.getLeaveMessage(ia.getGuildId())); 38 | return; 39 | } 40 | ia.reply(returnMessage); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/utils/EmoteHelper.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.utils; 2 | 3 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 4 | import de.kittybot.kittybot.slashcommands.interaction.response.InteractionResponse; 5 | import net.dv8tion.jda.api.entities.Icon; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.net.MalformedURLException; 10 | import java.net.URL; 11 | 12 | public class EmoteHelper{ 13 | 14 | private static final int MAX_EMOTE_SIZE = 256000; 15 | 16 | private EmoteHelper(){} 17 | 18 | public static void createEmote(GuildInteraction ia, String name, long emoteId, boolean animated){ 19 | createEmote(ia, name, "https://cdn.discordapp.com/emojis/" + emoteId + "." + (animated ? "gif" : "png")); 20 | } 21 | 22 | public static void createEmote(GuildInteraction ia, String name, String url){ 23 | try{ 24 | createEmote(ia, name, new URL(url).openStream()); 25 | } 26 | catch(MalformedURLException e){ 27 | ia.error("Please provide a valid url or emote id"); 28 | } 29 | catch(IOException e){ 30 | ia.error("Error creating emote please try again\nError: " + e.getMessage()); 31 | } 32 | } 33 | 34 | public static void createEmote(GuildInteraction ia, String name, InputStream inputStream){ 35 | ia.reply(new InteractionResponse.Builder().ephemeral().setContent("processing...").build()); 36 | try{ 37 | if(inputStream.available() > MAX_EMOTE_SIZE){ 38 | ia.followup("The image provided is bigger than 256kb"); 39 | return; 40 | } 41 | ia.getGuild().createEmote(name, Icon.from(inputStream)).queue(success -> ia.followup("Stole emote: " + success.getAsMention()), failure -> ia.followup("Error creating emote: " + failure.getMessage())); 42 | } 43 | catch(IOException e){ 44 | ia.followup("Error creating emote please try again\nError: " + e.getMessage()); 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/settings/StreamAnnouncement.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.settings; 2 | 3 | import de.kittybot.kittybot.jooq.tables.records.StreamUsersRecord; 4 | import de.kittybot.kittybot.objects.streams.StreamType; 5 | 6 | public class StreamAnnouncement{ 7 | 8 | private final long id, userId, guildId; 9 | private final String userName; 10 | private final StreamType streamType; 11 | private boolean isLive; 12 | 13 | public StreamAnnouncement(long userId, String userName, long guildId, StreamType streamType){ 14 | this.id = -1; 15 | this.userId = userId; 16 | this.userName = userName; 17 | this.guildId = guildId; 18 | this.streamType = streamType; 19 | this.isLive = false; 20 | } 21 | 22 | public StreamAnnouncement(StreamUsersRecord record){ 23 | this.id = record.getId(); 24 | this.userId = record.getUserId(); 25 | this.userName = record.getUserName(); 26 | this.guildId = record.getGuildId(); 27 | this.streamType = StreamType.byId(record.getStreamType()); 28 | this.isLive = record.getIsLive(); 29 | } 30 | 31 | public long getId(){ 32 | return this.id; 33 | } 34 | 35 | public long getUserId(){ 36 | return this.userId; 37 | } 38 | 39 | public String getUserName(){ 40 | return this.userName; 41 | } 42 | 43 | public long getGuildId(){ 44 | return this.guildId; 45 | } 46 | 47 | public StreamType getStreamType(){ 48 | return this.streamType; 49 | } 50 | 51 | public boolean isLive(){ 52 | return this.isLive; 53 | } 54 | 55 | public void setLive(boolean isLive){ 56 | this.isLive = isLive; 57 | } 58 | 59 | public String getStreamUrl(){ 60 | if(this.streamType == StreamType.TWITCH){ 61 | return this.streamType.getBaseUrl() + this.userName; 62 | } 63 | if(this.streamType == StreamType.YOUTUBE){ 64 | return this.streamType.getBaseUrl() + "c/" + this.userName; 65 | } 66 | return null; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/objects/settings/Notification.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.objects.settings; 2 | 3 | import de.kittybot.kittybot.jooq.tables.records.NotificationsRecord; 4 | 5 | import java.time.LocalDateTime; 6 | 7 | public class Notification{ 8 | 9 | private final long id, guildId, channelId, messageId, userId; 10 | private final String content; 11 | private final LocalDateTime notificationTime; 12 | private final LocalDateTime createdAt; 13 | 14 | public Notification(long id, long guildId, long channelId, long messageId, long userId, String content, LocalDateTime createdAt, LocalDateTime notificationTime){ 15 | this.id = id; 16 | this.guildId = guildId; 17 | this.channelId = channelId; 18 | this.messageId = messageId; 19 | this.userId = userId; 20 | this.content = content; 21 | this.createdAt = createdAt; 22 | this.notificationTime = notificationTime; 23 | } 24 | 25 | public Notification(NotificationsRecord record){ 26 | this.id = record.getId(); 27 | this.guildId = record.getGuildId(); 28 | this.channelId = record.getChannelId(); 29 | this.messageId = record.getMessageId(); 30 | this.userId = record.getUserId(); 31 | this.content = record.getContent(); 32 | this.createdAt = record.getCreatedAt(); 33 | this.notificationTime = record.getNotificationTime(); 34 | } 35 | 36 | public long getId(){ 37 | return this.id; 38 | } 39 | 40 | public long getGuildId(){ 41 | return this.guildId; 42 | } 43 | 44 | public long getChannelId(){ 45 | return this.channelId; 46 | } 47 | 48 | public long getMessageId(){ 49 | return this.messageId; 50 | } 51 | 52 | public long getUserId(){ 53 | return this.userId; 54 | } 55 | 56 | public String getContent(){ 57 | return this.content; 58 | } 59 | 60 | public LocalDateTime getCreatedAt(){ 61 | return this.createdAt; 62 | } 63 | 64 | public LocalDateTime getNotificationTime(){ 65 | return this.notificationTime; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/info/AvatarCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.info; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.Category; 4 | import de.kittybot.kittybot.slashcommands.application.CommandOptionChoice; 5 | import de.kittybot.kittybot.slashcommands.application.RunCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionInteger; 7 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionUser; 8 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 9 | import de.kittybot.kittybot.slashcommands.interaction.Options; 10 | import de.kittybot.kittybot.utils.MessageUtils; 11 | 12 | @SuppressWarnings("unused") 13 | public class AvatarCommand extends RunCommand{ 14 | 15 | public AvatarCommand(){ 16 | super("avatar", "Gets the avatar of a user", Category.INFORMATION); 17 | addOptions( 18 | new CommandOptionUser("user", "The user to get the avatar from"), 19 | new CommandOptionInteger("size", "The image size") 20 | .addChoices( 21 | new CommandOptionChoice<>("16px", 16), 22 | new CommandOptionChoice<>("32px", 32), 23 | new CommandOptionChoice<>("64px", 64), 24 | new CommandOptionChoice<>("128px", 128), 25 | new CommandOptionChoice<>("256px", 256), 26 | new CommandOptionChoice<>("512px", 512), 27 | new CommandOptionChoice<>("1024px", 1024), 28 | new CommandOptionChoice<>("2048px", 2048) 29 | ) 30 | ); 31 | } 32 | 33 | @Override 34 | public void run(Options options, Interaction ia){ 35 | var user = options.has("user") ? options.getUser("user") : ia.getUser(); 36 | var size = options.has("size") ? options.getInt("size") : 1024; 37 | 38 | ia.reply(builder -> builder 39 | .setTitle(user.getAsTag() + " Avatar") 40 | .setThumbnail(user.getEffectiveAvatarUrl()) 41 | .setDescription(MessageUtils.maskLink(size + "px", user.getEffectiveAvatarUrl() + "?size=" + size)) 42 | ); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/user/GetUserInfoRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.user; 2 | 3 | import de.kittybot.kittybot.modules.DashboardSessionModule; 4 | import de.kittybot.kittybot.modules.WebModule; 5 | import de.kittybot.kittybot.objects.data.GuildData; 6 | import de.kittybot.kittybot.objects.module.Modules; 7 | import io.javalin.http.*; 8 | import net.dv8tion.jda.api.exceptions.HttpException; 9 | import net.dv8tion.jda.api.utils.data.DataArray; 10 | import net.dv8tion.jda.api.utils.data.DataObject; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.List; 14 | import java.util.stream.Collectors; 15 | 16 | public class GetUserInfoRoute implements Handler{ 17 | 18 | private final Modules modules; 19 | 20 | public GetUserInfoRoute(Modules modules){ 21 | this.modules = modules; 22 | } 23 | 24 | @Override 25 | public void handle(@NotNull Context ctx){ 26 | var userId = this.modules.get(WebModule.class).getUserId(ctx); 27 | var dashboardSessionModule = this.modules.get(DashboardSessionModule.class); 28 | List guilds; 29 | try{ 30 | guilds = dashboardSessionModule.getGuilds(userId); 31 | } 32 | catch(HttpException e){ 33 | throw new UnauthorizedResponse("Please login again"); 34 | } 35 | if(guilds == null){ 36 | throw new InternalServerErrorResponse("Failed to retrieve user guilds"); 37 | } 38 | var user = this.modules.getShardManager().retrieveUserById(userId).complete(); 39 | if(user == null){ 40 | throw new NotFoundResponse("User not found"); 41 | } 42 | var guildData = DataArray.fromCollection(guilds.stream().map(guild -> 43 | DataObject.empty().put("id", guild.getIdString()).put("name", guild.getName()).put("icon", guild.getIconUrl()) 44 | ).collect(Collectors.toSet())); 45 | 46 | WebModule.ok(ctx, DataObject.empty().put("name", user.getName()).put("id", String.valueOf(userId)).put("icon", user.getEffectiveAvatarUrl()).put("guilds", guildData)); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/info/InfoCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.info; 2 | 3 | import de.kittybot.kittybot.slashcommands.application.Category; 4 | import de.kittybot.kittybot.slashcommands.application.RunCommand; 5 | import de.kittybot.kittybot.slashcommands.interaction.Interaction; 6 | import de.kittybot.kittybot.slashcommands.interaction.Options; 7 | import de.kittybot.kittybot.utils.Config; 8 | import de.kittybot.kittybot.utils.Utils; 9 | import net.dv8tion.jda.api.JDAInfo; 10 | 11 | import java.lang.management.ManagementFactory; 12 | 13 | @SuppressWarnings("unused") 14 | public class InfoCommand extends RunCommand{ 15 | 16 | public InfoCommand(){ 17 | super("info", "Shows some bot info", Category.INFORMATION); 18 | } 19 | 20 | @Override 21 | public void run(Options options, Interaction ia){ 22 | var shardManager = ia.getModules().getShardManager(); 23 | var runtime = Runtime.getRuntime(); 24 | ia.reply(builder -> builder 25 | .setAuthor("KittyBot Information", Config.ORIGIN_URL, Category.INFORMATION.getEmoteUrl()) 26 | 27 | .addField("JVM Version:", System.getProperty("java.version"), true) 28 | .addField("JDA Version:", JDAInfo.VERSION, true) 29 | .addBlankField(true) 30 | 31 | .addField("Total Shards:", String.valueOf(shardManager.getShardsTotal()), true) 32 | .addField("Current Shard:", String.valueOf(ia.getJDA().getShardInfo().getShardId()), true) 33 | .addBlankField(true) 34 | 35 | .addField("Total Guilds:", String.valueOf(shardManager.getGuildCache().size()), true) 36 | .addField("Total Users:", String.valueOf(Utils.getUserCount(shardManager)), true) 37 | .addBlankField(true) 38 | 39 | .addField("Memory Usage:", ((runtime.totalMemory() - runtime.freeMemory()) >> 20) + "MB / " + (runtime.maxMemory() >> 20) + "MB", true) 40 | .addField("Thread Count:", String.valueOf(ManagementFactory.getThreadMXBean().getThreadCount()), true) 41 | .addBlankField(true) 42 | ); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/roles/UnassignCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.roles; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.Category; 5 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 6 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionRole; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | 10 | @SuppressWarnings("unused") 11 | public class UnassignCommand extends RunGuildCommand{ 12 | 13 | public UnassignCommand(){ 14 | super("unassign", "Unassigns yourself a self assignable roles", Category.ROLES); 15 | addOptions( 16 | new CommandOptionRole("role", "The role to unassign").required() 17 | ); 18 | } 19 | 20 | @Override 21 | public void run(Options options, GuildInteraction ia){ 22 | var role = options.getRole("role"); 23 | if(role == null){ 24 | ia.error("Unknown role provided"); 25 | return; 26 | } 27 | var settings = ia.get(SettingsModule.class).getSettings(ia.getGuildId()); 28 | var selfAssignableRoles = settings.getSelfAssignableRoles(); 29 | if(selfAssignableRoles == null || selfAssignableRoles.isEmpty()){ 30 | ia.error("No self assignable roles configured"); 31 | return; 32 | } 33 | 34 | var selfAssignableRole = selfAssignableRoles.stream().filter(r -> role.getIdLong() == r.getRoleId()).findFirst().orElse(null); 35 | if(selfAssignableRole == null){ 36 | ia.error("This role is not self assignable"); 37 | return; 38 | } 39 | 40 | if(!ia.getSelfMember().canInteract(role)){ 41 | ia.error("I don't have the permissions to unassign you this role"); 42 | return; 43 | } 44 | ia.getGuild().removeRoleFromMember(ia.getMember(), role) 45 | .reason("self unassigned with kittybot") 46 | .queue(unused -> ia.reply("Unassigned " + role.getAsMention())); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/utils/MessageUtils.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.utils; 2 | 3 | import de.kittybot.kittybot.objects.enums.Emoji; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.Collection; 8 | 9 | public class MessageUtils{ 10 | 11 | private static final Logger LOG = LoggerFactory.getLogger(MessageUtils.class); 12 | 13 | private static final String UNSET = "unset"; 14 | 15 | private MessageUtils(){} 16 | 17 | public static String trimIfTooLong(String message){ 18 | return message.length() > 2048 ? message.substring(0, 2045) + "..." : message; 19 | } 20 | 21 | public static String getBoolEmote(boolean bool){ 22 | return bool ? Emoji.CHECK.get() : Emoji.X.get(); 23 | } 24 | 25 | public static String maskLink(String title, String url){ 26 | return "[" + title + "](" + url + ")"; 27 | } 28 | 29 | public static String pluralize(String text, Collection collection){ 30 | return pluralize(text, collection.size()); 31 | } 32 | 33 | public static String pluralize(String text, int count){ 34 | return count == 1 ? text : text + "s"; 35 | } 36 | 37 | public static String getUserMention(long userId){ 38 | if(userId == -1L){ 39 | return UNSET; 40 | } 41 | return "<@!" + userId + ">"; 42 | } 43 | 44 | public static String getRoleMention(long roleId){ 45 | if(roleId == -1L){ 46 | return UNSET; 47 | } 48 | return "<@&" + roleId + ">"; 49 | } 50 | 51 | public static String getChannelMention(long channelId){ 52 | if(channelId == -1L){ 53 | return UNSET; 54 | } 55 | return "<#" + channelId + ">"; 56 | } 57 | 58 | public static String getEmoteMention(long emoteId){ 59 | if(emoteId == -1L){ 60 | return UNSET; 61 | } 62 | return "<:i:" + emoteId + ">"; 63 | } 64 | 65 | public static String getMessageLink(long guildId, long channelId, long messageId){ 66 | return String.format("https://discord.com/channels/%d/%d/%d", guildId, channelId, messageId); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/guilds/GetAllGuildsRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.guilds; 2 | 3 | import de.kittybot.kittybot.modules.MusicModule; 4 | import de.kittybot.kittybot.modules.WebModule; 5 | import de.kittybot.kittybot.objects.module.Modules; 6 | import de.kittybot.kittybot.utils.Config; 7 | import io.javalin.http.Context; 8 | import io.javalin.http.ForbiddenResponse; 9 | import io.javalin.http.Handler; 10 | import net.dv8tion.jda.api.utils.data.DataArray; 11 | import net.dv8tion.jda.api.utils.data.DataObject; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.stream.Collectors; 15 | 16 | public class GetAllGuildsRoute implements Handler{ 17 | 18 | private final Modules modules; 19 | 20 | public GetAllGuildsRoute(Modules modules){ 21 | this.modules = modules; 22 | } 23 | 24 | @Override 25 | public void handle(@NotNull Context ctx){ 26 | var userId = this.modules.get(WebModule.class).getUserId(ctx); 27 | if(!Config.DEV_IDS.contains(userId)){ 28 | throw new ForbiddenResponse("Only bot devs have access to this"); 29 | } 30 | var players = this.modules.get(MusicModule.class).getPlayers(); 31 | var data = DataArray.fromCollection( 32 | this.modules.getShardManager().getGuildCache().stream().map(guild -> { 33 | var json = DataObject.empty() 34 | .put("id", guild.getId()) 35 | .put("name", guild.getName()) 36 | .put("icon", guild.getIconUrl()) 37 | .put("count", guild.getMemberCount()) 38 | .put("owner", guild.getOwnerId()); 39 | var player = players.get(guild.getIdLong()); 40 | var playsMusic = player != null; 41 | json.put("plays_music", playsMusic) 42 | .put("queue_size", playsMusic ? player.getScheduler().getQueue().size() : 0) 43 | .put("history_size", playsMusic ? player.getScheduler().getHistory().size() : 0); 44 | return json; 45 | }).collect(Collectors.toSet()) 46 | ); 47 | WebModule.ok(ctx, DataObject.empty().put("guilds", data)); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/admin/settings/LogMessagesCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.admin.settings; 2 | 3 | import de.kittybot.kittybot.modules.SettingsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionBoolean; 5 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionChannel; 6 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.utils.MessageUtils; 10 | 11 | public class LogMessagesCommand extends GuildSubCommand{ 12 | 13 | public LogMessagesCommand(){ 14 | super("logmessages", "Sets the logging channel or enables/disables log messages"); 15 | addOptions( 16 | new CommandOptionBoolean("enabled", "Whether log messages are enabled"), 17 | new CommandOptionChannel("channel", "The log message channel") 18 | ); 19 | } 20 | 21 | @Override 22 | public void run(Options options, GuildInteraction ia){ 23 | var settings = ia.get(SettingsModule.class); 24 | var returnMessage = ""; 25 | if(options.has("enabled")){ 26 | var enabled = options.getBoolean("enabled"); 27 | settings.setLogMessagesEnabled(ia.getGuildId(), enabled); 28 | returnMessage += "Log messages `" + (enabled ? "enabled" : "disabled") + "`\n"; 29 | } 30 | 31 | if(options.has("channel")){ 32 | var channel = options.getTextChannel("channel"); 33 | settings.setLogChannelId(ia.getGuildId(), channel.getIdLong()); 34 | returnMessage += "Log channel to:\n" + channel.getAsMention() + "\n"; 35 | } 36 | 37 | if(returnMessage.isBlank()){ 38 | ia.reply("Log message `" + (settings.areLogMessagesEnabled(ia.getGuildId()) ? "enabled" : "disabled") + "` and send to channel " + 39 | MessageUtils.getChannelMention(settings.getLogChannelId(ia.getGuildId()))); 40 | return; 41 | } 42 | ia.reply(returnMessage); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/modules/StatusModule.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.modules; 2 | 3 | import de.kittybot.kittybot.objects.module.Module; 4 | import de.kittybot.kittybot.utils.FileUtils; 5 | import de.kittybot.kittybot.utils.Utils; 6 | import net.dv8tion.jda.api.OnlineStatus; 7 | import net.dv8tion.jda.api.entities.Activity; 8 | import net.dv8tion.jda.api.events.ReadyEvent; 9 | import net.dv8tion.jda.api.sharding.ShardManager; 10 | 11 | import javax.annotation.Nonnull; 12 | import java.util.List; 13 | import java.util.concurrent.ThreadLocalRandom; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | @SuppressWarnings("unused") 17 | public class StatusModule extends Module{ 18 | 19 | private List statusMessages; 20 | 21 | @Override 22 | public void onEnable(){ 23 | this.statusMessages = FileUtils.loadMessageFile("status"); 24 | } 25 | 26 | @Override 27 | public void onReady(@Nonnull ReadyEvent event){ 28 | this.modules.scheduleAtFixedRate(this::newRandomStatus, 0, 2, TimeUnit.MINUTES); 29 | } 30 | 31 | public void newRandomStatus(){ 32 | var shardManager = this.modules.getShardManager(); 33 | shardManager.setPresence(OnlineStatus.ONLINE, generateRandomMessage(shardManager)); 34 | } 35 | 36 | private Activity generateRandomMessage(ShardManager shardManager){ 37 | if(statusMessages.isEmpty()){ 38 | return Activity.watching("you \uD83D\uDC40"); 39 | } 40 | var randomMessage = statusMessages.get(ThreadLocalRandom.current().nextInt(statusMessages.size() - 1)); 41 | 42 | var activityMessage = randomMessage.split("\\s+", 2); 43 | var type = activityMessage[0].toUpperCase(); 44 | var message = activityMessage[1]; 45 | 46 | message = message.replace("${total_users}", String.valueOf(Utils.getUserCount(this.modules.getShardManager()))); 47 | message = message.replace("${total_guilds}", String.valueOf(shardManager.getGuildCache().size())); 48 | return Activity.of(Activity.ActivityType.valueOf(type.equals("PLAYING") ? "DEFAULT" : type), message); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/snipe/SnipeCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.snipe; 2 | 3 | import de.kittybot.kittybot.modules.MessageModule; 4 | import de.kittybot.kittybot.modules.SettingsModule; 5 | import de.kittybot.kittybot.slashcommands.application.Category; 6 | import de.kittybot.kittybot.slashcommands.application.RunGuildCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | 10 | import java.awt.Color; 11 | 12 | @SuppressWarnings("unused") 13 | public class SnipeCommand extends RunGuildCommand{ 14 | 15 | public SnipeCommand(){ 16 | super("snipe", "Snipes the last deleted message", Category.SNIPE); 17 | } 18 | 19 | @Override 20 | public void run(Options options, GuildInteraction ia){ 21 | if(!ia.get(SettingsModule.class).areSnipesEnabled(ia.getGuildId())){ 22 | ia.error("Snipes are disabled for this guild"); 23 | } 24 | if(ia.get(SettingsModule.class).areSnipesDisabledInChannel(ia.getGuildId(), ia.getChannelId())){ 25 | ia.error("Snipes are disabled for this channel"); 26 | } 27 | var lastDeletedMessage = ia.get(MessageModule.class).getLastDeletedMessage(ia.getChannelId()); 28 | if(lastDeletedMessage == null){ 29 | ia.reply(builder -> builder.setColor(Color.RED).setDescription("There are no deleted messages to snipe")); 30 | return; 31 | } 32 | ia.getJDA().retrieveUserById(lastDeletedMessage.getAuthorId()).queue(user -> 33 | ia.reply(builder -> { 34 | builder.setAuthor("Sniped " + user.getName(), lastDeletedMessage.getJumpUrl()) 35 | .setDescription(lastDeletedMessage.getContent()) 36 | .setFooter("from " + user.getName(), user.getEffectiveAvatarUrl()) 37 | .setTimestamp(lastDeletedMessage.getTimeCreated()); 38 | if(!lastDeletedMessage.getAttachments().isEmpty()){ 39 | lastDeletedMessage.getAttachments().forEach(attachment -> builder.addField("Attachment", attachment, true)); 40 | } 41 | }) 42 | ); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/web/login/PostLoginRoute.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.web.login; 2 | 3 | import com.jagrosh.jdautilities.oauth2.exceptions.InvalidStateException; 4 | import de.kittybot.kittybot.modules.DashboardSessionModule; 5 | import de.kittybot.kittybot.modules.WebModule; 6 | import de.kittybot.kittybot.objects.module.Modules; 7 | import de.kittybot.kittybot.objects.session.DashboardSession; 8 | import io.javalin.http.*; 9 | import io.jsonwebtoken.Jwts; 10 | import net.dv8tion.jda.api.exceptions.HttpException; 11 | import net.dv8tion.jda.api.utils.data.DataObject; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.io.IOException; 15 | import java.util.Date; 16 | 17 | public class PostLoginRoute implements Handler{ 18 | 19 | private final Modules modules; 20 | 21 | public PostLoginRoute(Modules modules){ 22 | this.modules = modules; 23 | } 24 | 25 | @Override 26 | public void handle(@NotNull Context ctx){ 27 | var json = DataObject.fromJson(ctx.body()); 28 | var code = json.getString("code", null); 29 | var state = json.getString("state", null); 30 | if(code == null || code.isBlank() || state == null || state.isBlank()){ 31 | throw new UnauthorizedResponse("State or code is invalid"); 32 | } 33 | try{ 34 | var sessionManager = this.modules.get(DashboardSessionModule.class); 35 | var session = (DashboardSession) sessionManager.getOAuth2Client().startSession(code, state, "", DashboardSessionModule.getScopes()).complete(); 36 | WebModule.accepted(ctx, DataObject.empty().put("token", Jwts.builder().setIssuedAt(new Date()).setSubject(String.valueOf(session.getUserId())).signWith(sessionManager.getSecretKey()).compact())); 37 | } 38 | catch(HttpException e){ 39 | throw new BadRequestResponse("Don't spam login"); 40 | } 41 | catch(InvalidStateException e){ 42 | throw new UnauthorizedResponse("State invalid/expired. Please try again"); 43 | } 44 | catch(IOException e){ 45 | throw new ForbiddenResponse("Could not login"); 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/tags/tags/CreateCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.tags.tags; 2 | 3 | import de.kittybot.kittybot.modules.TagsModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionLong; 5 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 6 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | 10 | public class CreateCommand extends GuildSubCommand{ 11 | 12 | public CreateCommand(){ 13 | super("create", "Used to create a tag"); 14 | addOptions( 15 | new CommandOptionString("name", "Tag name").required(), 16 | new CommandOptionString("content", "Tag content"), 17 | new CommandOptionLong("message-id", "The message id to create a tag from") 18 | ); 19 | } 20 | 21 | @Override 22 | public void run(Options options, GuildInteraction ia){ 23 | var tagName = options.getString("name"); 24 | if(tagName.length() > 64){ 25 | ia.error("Tag names must be 64 or less characters"); 26 | return; 27 | } 28 | if(!options.has("content") && !options.has("message-id")){ 29 | ia.reply("Please provide either content or message-id"); 30 | return; 31 | } 32 | var content = ""; 33 | if(options.has("content")){ 34 | content = options.getString("content"); 35 | } 36 | else{ 37 | var message = ia.getChannel().retrieveMessageById(options.getLong("message-id")).complete(); 38 | if(message == null){ 39 | ia.error("Please provide a recent message id"); 40 | return; 41 | } 42 | content = message.getContentRaw(); 43 | } 44 | 45 | var created = ia.get(TagsModule.class).create(tagName, content, ia.getGuildId(), ia.getUserId()); 46 | 47 | if(created){ 48 | ia.reply("Created tag with name `" + tagName + "`"); 49 | return; 50 | } 51 | ia.error("A tag with the name `" + tagName + "` already exists"); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/de/kittybot/kittybot/commands/notification/notification/CreateCommand.java: -------------------------------------------------------------------------------- 1 | package de.kittybot.kittybot.commands.notification.notification; 2 | 3 | import de.kittybot.kittybot.modules.NotificationModule; 4 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionString; 5 | import de.kittybot.kittybot.slashcommands.application.options.CommandOptionTime; 6 | import de.kittybot.kittybot.slashcommands.application.options.GuildSubCommand; 7 | import de.kittybot.kittybot.slashcommands.interaction.GuildInteraction; 8 | import de.kittybot.kittybot.slashcommands.interaction.Options; 9 | import de.kittybot.kittybot.utils.TimeUtils; 10 | 11 | import java.time.LocalDateTime; 12 | import java.time.temporal.ChronoUnit; 13 | 14 | public class CreateCommand extends GuildSubCommand{ 15 | 16 | public CreateCommand(){ 17 | super("create", "Creates a notification"); 18 | addOptions( 19 | new CommandOptionTime("time", "When to notif you. Format: `HH:mm dd.MM.yyyy` or 1y2w3d4h5m6s").required(), 20 | new CommandOptionString("message", "The notif message").required()/*, 21 | new CommandOptionBoolean("notif-in-dms", "If I should notif you in dms")*/ 22 | ); 23 | } 24 | 25 | @Override 26 | public void run(Options options, GuildInteraction ia){ 27 | var time = options.getTime("time"); 28 | if(time.isBefore(LocalDateTime.now())){ 29 | ia.error("Please provide a valid time or duration in this format: "); 30 | return; 31 | } 32 | var message = options.getString("message"); 33 | var notif = ia.get(NotificationModule.class).create( 34 | ia.getGuildId(), 35 | ia.getChannelId(), 36 | -1, 37 | ia.getUser().getIdLong(), 38 | message, 39 | time 40 | ); 41 | if(notif == null){ 42 | ia.error("There was an unexpected error while creating your notification"); 43 | return; 44 | } 45 | ia.reply("Notification at `" + TimeUtils.formatDuration(notif.getCreatedAt().until(notif.getNotificationTime(), ChronoUnit.MILLIS)) + "` created with id: `" + notif.getId() + "`"); 46 | 47 | } 48 | 49 | } 50 | --------------------------------------------------------------------------------