diff --git a/.idea/misc.xml b/.idea/misc.xml index 7122aeb..2dbd315 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,5 +4,5 @@ - + \ No newline at end of file diff --git a/README.md b/README.md index 6bbf52d..fe5e084 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,83 @@ -**MISSINGIDENTIFIER a Utility Discord Bot** +# MissingIdentifier -This is a Utility Discord providing some helpfull and some not so helpfull features. -It uses the [JDA](https://github.com/DV8FromTheWorld/JDA) wrapper. +This is a Utility Discord providing some helpful and some not so helpful features. It uses the [JDA wrapper](https://github.com/DV8FromTheWorld/JDA). -**Features:** -* ANNOY Members without a role will get messaged once a day with a custom text -* FOLD Shows some statistics for a given [Folding@Home](https://foldingathome.org/) team -* SHUFFLEROLE A given role gets a new color one a while -* LOBBY Temporary voicechannels -* QUOTE Save quotes and show random quotes -* RANDOMRESPONSE Response if text contains a trigger word -* AUTOSELECT Give members roles by reacting -* DICE Role a dice -* PRUGE Delete Messages -* LOVECALC Calculate chances between two members -* WELCOME Welcome new members with a custom text -* STATS Show some Serverstats -* ONLINEHIGHLIGHT Gives User a given Role if they are playing one of a given set of games -* SECRETCHANNEL Add Users to Secretchat if they mention given keywords -* VOICELOBBY Moves Users joining a given Voicechannel to a temporary VoiceChannel +## Features -**INVITE** -[CLICK](https://discordapp.com/oauth2/authorize?client_id=550770123946983440&scope=bot&permissions=285961296) + * ANNOY: Sends a message to guild members who did not choose a role yet + * AUTOSELECT: Grands users a role when they react to a given reaction + * DICE: Rolles a dice + * FOLD: Show some statistics about a [Folding@home](https://foldingathome.org) team. + * LOVECALC: Chances of two users falling in love (no guarantee) + * ONLINEHIGHLIGHT: Gives users a role who play a certain game + * PURGE: Bulk delete messages + * QUOTE: Saves quotes and displays them randomly + * RANDOMRESPONDE: Answer to given trigger words + * SECRETCHANNEL: Grants members access to channels if they mention keywords + * SHUFFLE: Color changing role + * STATS: Some guild stats + * VOICELOBBY: Temporary voice channels via command or joining certain channels + * WELCOME: Messages for new members -note: on default only the Guildowner is able to use the bot! he have to set a Admin/Modrole, so others can configurate the bot! `!admin setmodrole @role` +## How to use MissingIdentifier -**COMMANDS** -Please use `!help` to get a full command list +### Using my Bot hosted by me + +1. Invite bot to your Discord guild using this [LINK](https://discordapp.com/oauth2/authorize?client_id=550770123946983440&scope=bot&permissions=285961296) (You may want to adjust the preset bot permissions to your linking). +2. Change bot prefix if other bots use the same (and use it from now on instead of `!`): + +``` +!admin setprefix +``` +3. Set a Mod-Role so non guild owner are able to configure this bot (preferably the admin role) + +``` +!admin setmodrole <@MODROLE> +``` + +4. Use the `help` command to get an overview of the available modules and commands. +5. Activate modules to your liking: + +``` +!admin +``` +6. Reenter the `help` command to get overview of new settings and commands available + +### Self host the bot + +1. Create Discord Bot-User + 1. Go to the [Discord developer](https://discord.com/developers/applications) page + 2. Create a new application and edit it to your liking + 3. navigate to `BOT` and hit `add bot` + 4. may activate `Privileged Gateway Intents` (right now bot uses them, may a non presence mode be implemented) + 5. Copy bot token +2. Copy release .jar executable +3. Copy sample config to .jar location +4. Enter bot token from step one into config file +5. run bot (`java -jar .jar`) + +#### Updating + +Just replace the .jar executable + +### Building the bot your self + +1. Clone Repo +2. Run `gradle fatJar` +3. .jar executable is located in ./build/libs/ + +(run the bot via `gradle run` should work fine too) + +## Contributing + +Uhm may just ask me to get started (COMING SOON) + +## Bug report + +(COMING SOON) + +## Contact + +Well find me ... i am using the name `Hiajen` + +or just text me via [Matrix](https://matrix.to/#/@hiajen:matrix.hiajen.de) (`@hiajen:matrix.hiajen.de`) diff --git a/build.gradle b/build.gradle index dac17f7..3b59dc2 100644 --- a/build.gradle +++ b/build.gradle @@ -5,31 +5,33 @@ plugins { group 'BOT' -version '1.0.0' +version '1.0.1' -def jdaVersion = '4.2.0_225' +def jdaVersion = '4.4.0_350' def jsonsimpleVersion = '1.1.1' -def jodatimeVersion = '2.10.6' -def self4JVersion = '1.7.30' -def log4jVersion = '2.13.3' -def JSON = '4.12.0' +def jodatimeVersion = '2.10.13' +def self4JVersion = '1.7.32' +def JSON = '4.13.0' mainClassName = 'MissingIDent' sourceCompatibility = 1.8 compileJava.options.encoding = 'UTF-8' repositories { - jcenter() + mavenCentral() + maven { + name 'm2-dv8tion' + url 'https://m2.dv8tion.net/releases' + } } dependencies { - compile "net.dv8tion:JDA:$jdaVersion" - compile group: 'com.googlecode.json-simple', name: 'json-simple', version: jsonsimpleVersion - compile group: 'joda-time', name: 'joda-time', version: jodatimeVersion - compile group: 'org.slf4j', name: 'slf4j-api', version: self4JVersion - compile group: 'org.slf4j', name: 'slf4j-log4j12', version: self4JVersion - compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: log4jVersion - compile group: 'com.cedarsoftware', name: 'json-io', version: JSON + implementation "net.dv8tion:JDA:$jdaVersion" + implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: jsonsimpleVersion + implementation group: 'joda-time', name: 'joda-time', version: jodatimeVersion + implementation group: 'org.slf4j', name: 'slf4j-api', version: self4JVersion + implementation group: 'org.slf4j', name: 'slf4j-jdk14', version: self4JVersion + implementation group: 'com.cedarsoftware', name: 'json-io', version: JSON } //create a single Jar with all dependencies diff --git a/src/main/java/Controll/Admin.java b/src/main/java/Controll/Admin.java index 4a63189..2ca4237 100644 --- a/src/main/java/Controll/Admin.java +++ b/src/main/java/Controll/Admin.java @@ -18,7 +18,7 @@ public class Admin extends SuperModule { public static final String command = "admin"; public Admin(GuildController guildController) { - super(command, guildController, null); + super(command, guildController); } @Override diff --git a/src/main/java/Controll/Controller.java b/src/main/java/Controll/Controller.java index 0324de1..607cf46 100644 --- a/src/main/java/Controll/Controller.java +++ b/src/main/java/Controll/Controller.java @@ -4,6 +4,7 @@ import IO.JSON; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.events.GenericEvent; import net.dv8tion.jda.api.events.ReadyEvent; +import net.dv8tion.jda.api.events.ShutdownEvent; import net.dv8tion.jda.api.events.guild.GenericGuildEvent; import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; @@ -98,6 +99,9 @@ public class Controller extends ListenerAdapter { @Override public void onGenericEvent(@NotNull GenericEvent event){ + if (guilds == null) + return; + if (event instanceof GuildJoinEvent) onGuildJoin((GuildJoinEvent) event); else if (event instanceof GuildLeaveEvent) @@ -133,6 +137,7 @@ public class Controller extends ListenerAdapter { reload(event.getJDA()); } + @Override public void onGuildJoin(@NotNull GuildJoinEvent event){ //Check if guild exists for (GuildController guildController : guilds){ @@ -156,6 +161,7 @@ public class Controller extends ListenerAdapter { } + @Override public void onGuildLeave(@NotNull GuildLeaveEvent event){ JSONArray guilds = JSON.loadJson(GUILD_CONFIG_FILE); @@ -170,4 +176,12 @@ public class Controller extends ListenerAdapter { } JSON.saveJson(guilds, GUILD_CONFIG_FILE); } + + @Override + public void onShutdown(@NotNull ShutdownEvent shutdownEvent){ + for (GuildController guildController: guilds){ + guildController.shutdown(); + } + logger.debug("Shutdown complete"); + } } diff --git a/src/main/java/Controll/GuildController.java b/src/main/java/Controll/GuildController.java index 93445d3..45e05f3 100644 --- a/src/main/java/Controll/GuildController.java +++ b/src/main/java/Controll/GuildController.java @@ -103,7 +103,6 @@ public class GuildController { if (checkForActivate(Purge.COMMAND)) modules.add(new Purge(this)); - if (checkForActivate(Quote.command)) modules.add(new Quote(this)); @@ -141,6 +140,14 @@ public class GuildController { modules.add(new Help(this)); } + protected void shutdown(){ + for (Module module: modules){ + if (module instanceof SuperModule) + ((SuperModule) module).shutdown(); + } + logger.debug("Shutdown Modules for Guild: " + getGUILD_ID()); + } + private boolean checkForActivate(String moduleName){ if (moduleConf.containsKey(moduleName)){ logger.info("activate " + moduleName + " in " +getGUILD_ID()); diff --git a/src/main/java/Controll/Help.java b/src/main/java/Controll/Help.java index f24f088..c9c447c 100644 --- a/src/main/java/Controll/Help.java +++ b/src/main/java/Controll/Help.java @@ -14,7 +14,7 @@ public class Help extends SuperModule { public static final String command = "help"; public Help( GuildController guildController){ - super(command, guildController, null); + super(command, guildController); } @Override diff --git a/src/main/java/Controll/SuperModule.java b/src/main/java/Controll/SuperModule.java index 88135e8..03c3c89 100644 --- a/src/main/java/Controll/SuperModule.java +++ b/src/main/java/Controll/SuperModule.java @@ -5,6 +5,9 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import org.json.simple.JSONObject; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -13,6 +16,10 @@ public abstract class SuperModule implements Module { private GuildController guildController; private JSONObject config; private final String command; + /** + * May temporary data but save worthy (active timer etc) + */ + private Map temporaryData; /** * Construcker of a Module @@ -23,12 +30,24 @@ public abstract class SuperModule implements Module { this.command = command; this.guildController = guildController; this.config = config; + + temporaryData = (Map)config.get("TemporaryData"); + if (temporaryData != null) { + this.config.remove("TemporaryData"); + safeConfig(); + } else { + temporaryData = new HashMap<>(); + } + + } public SuperModule(String command, GuildController guildController){ this.command = command; this.guildController = guildController; this.config = null; + + temporaryData = new HashMap<>(); } /** @@ -118,4 +137,16 @@ public abstract class SuperModule implements Module { protected void safeConfig(){ safeConfig(getConfig()); } + + /** + * On shutdown safe temporary data what should be saved + */ + protected void shutdown(){ + getConfig().put("TemporaryData", temporaryData); + safeConfig(); + } + + protected Map getTemporaryData(){ + return temporaryData; + } } diff --git a/src/main/java/MissingIDent.java b/src/main/java/MissingIDent.java index 6ef6620..6e0a12a 100644 --- a/src/main/java/MissingIDent.java +++ b/src/main/java/MissingIDent.java @@ -1,5 +1,4 @@ import Controll.Controller; -import net.dv8tion.jda.api.AccountType; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Activity; @@ -11,6 +10,8 @@ import org.json.simple.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.logging.LogManager; + /** * @author https://www.Hiajen.de */ @@ -23,6 +24,9 @@ public class MissingIDent { ***************************************/ public static void main(String[] args) throws Exception { + LogManager loggerMG = java.util.logging.LogManager.getLogManager(); + loggerMG.readConfiguration(MissingIDent.class.getClassLoader().getResourceAsStream("logging.properties")); + Logger logger = LoggerFactory.getLogger(MissingIDent.class); logger.info("Bot Started"); diff --git a/src/main/java/Modules/Fold.java b/src/main/java/Modules/Fold.java index 5b18039..dce4a20 100644 --- a/src/main/java/Modules/Fold.java +++ b/src/main/java/Modules/Fold.java @@ -36,7 +36,7 @@ public class Fold extends SuperModule{ userFile = "/home/bots/MissingIdentifier/MissingIdent/user_summary.txt"; public Fold(GuildController guildController){ - super(COMMAND, guildController, null); + super(COMMAND, guildController); } @Override diff --git a/src/main/java/Modules/Purge.java b/src/main/java/Modules/Purge.java index 8a63b0e..9dc5bfa 100644 --- a/src/main/java/Modules/Purge.java +++ b/src/main/java/Modules/Purge.java @@ -19,7 +19,7 @@ public class Purge extends SuperModule{ public static final String COMMAND = "purge"; public Purge(GuildController guildController){ - super(COMMAND, guildController, null); + super(COMMAND, guildController); } @Override diff --git a/src/main/java/Modules/VoiceLobby.java b/src/main/java/Modules/VoiceLobby.java index 0c234dc..e21780f 100644 --- a/src/main/java/Modules/VoiceLobby.java +++ b/src/main/java/Modules/VoiceLobby.java @@ -31,7 +31,6 @@ public class VoiceLobby extends SuperModule { private long groupCategory; private long launchpadChannel; - private HashSet tmpChannel = new HashSet<>(); private Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -98,7 +97,7 @@ public class VoiceLobby extends SuperModule { // move User event.getGuild().moveVoiceMember(((GuildMessageReceivedEvent) event).getMember(), newChannel).queue(); - tmpChannel.add(newChannel.getIdLong()); + ((HashSet)getTemporaryData().get("tmpChannel")).add(newChannel.getIdLong()); } else { thisEvent.getChannel().sendMessage("Please Join a Voice Channel first!").queue(e -> e.delete().queueAfter(1, TimeUnit.MINUTES)); @@ -185,7 +184,7 @@ public class VoiceLobby extends SuperModule { //check if user left a temp channel if ((thisEvent.getChannelLeft() != null && thisEvent.getChannelLeft().getParent().getIdLong() == groupCategory)) { //check if channel is now empty - if (thisEvent.getChannelLeft().getMembers().size() < 1 && tmpChannel.contains(thisEvent.getChannelLeft().getIdLong())) { + if (thisEvent.getChannelLeft().getMembers().size() < 1 && ((HashSet)getTemporaryData().get("tmpChannel")).contains(thisEvent.getChannelLeft().getIdLong())) { logger.debug("may remove channel: " + thisEvent.getChannelLeft().getId()); //wait for 30 seconds and check again @@ -197,7 +196,7 @@ public class VoiceLobby extends SuperModule { logger.debug("remove channel: " + thisEvent.getChannelLeft().getId()); thisEvent.getChannelLeft().delete().queue(); - tmpChannel.remove(thisEvent.getChannelLeft().getIdLong()); + ((HashSet)getTemporaryData().get("tmpChannel")).remove(thisEvent.getChannelLeft().getIdLong()); } else { logger.debug("dont remove channel: " + thisEvent.getChannelLeft().getId()); } @@ -215,7 +214,7 @@ public class VoiceLobby extends SuperModule { // move User event.getGuild().moveVoiceMember(thisEvent.getEntity(), newChannel).queue(); - tmpChannel.add(newChannel.getIdLong()); + ((HashSet)getTemporaryData().get("tmpChannel")).add(newChannel.getIdLong()); } } } diff --git a/src/main/resources/logging.properties b/src/main/resources/logging.properties new file mode 100644 index 0000000..8922a24 --- /dev/null +++ b/src/main/resources/logging.properties @@ -0,0 +1,15 @@ +handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler + +java.util.logging.FileHandler.level=ALL +java.util.logging.FileHandler.limit=10485760 +java.util.logging.FileHandler.count=2 +java.util.logging.FileHandler.append=true +java.util.logging.FileHandler.pattern=MissingIdent%g.log +java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter + +java.util.logging.ConsoleHandler.level=ALL +java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter + +java.util.logging.SimpleFormatter.format=[%1$TF-%1$TT][%2$s][%4$s] : %5$s %6$s %n + +net.dv8tion.jda.level=WARNING \ No newline at end of file