├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── appveyor.yml ├── pom.xml └── src └── main ├── java └── pl │ └── bmstefanski │ └── garbanzo │ ├── .gitkeep │ ├── ApplicationBootstrap.java │ ├── command │ ├── .gitkeep │ ├── CommitCommand.java │ ├── EightBallCommand.java │ ├── FactCommand.java │ ├── GitHubCommand.java │ ├── RegisterAccountCommand.java │ ├── SayCommand.java │ └── defaults │ │ ├── Command.java │ │ ├── CommandExecutor.java │ │ ├── CommandInfo.java │ │ ├── CommandSender.java │ │ └── impl │ │ ├── CommandBuilder.java │ │ ├── CommandImpl.java │ │ ├── CommandRegistry.java │ │ └── CommandSenderImpl.java │ ├── component │ └── MessageComponent.java │ ├── configuration │ ├── GarbanzoProperties.java │ └── SpringApplicationConfiguration.java │ ├── controller │ ├── RestErrorController.java │ └── UserController.java │ ├── entity │ ├── Entity.java │ ├── UserEntity.java │ └── impl │ │ └── UserEntityImpl.java │ ├── listener │ └── GuildMemberJoinListener.java │ ├── repository │ └── UserRepository.java │ ├── service │ ├── GarbanzoService.java │ └── impl │ │ └── GarbanzoServiceImpl.java │ └── util │ ├── Buildable.java │ └── RestServiceType.java └── resources ├── banner.txt ├── garbanzo.properties └── locale └── messages.properties /.gitignore: -------------------------------------------------------------------------------- 1 | Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | 4 | # Sensitive or high-churn files 5 | .idea/ 6 | target/ 7 | 8 | # CMake 9 | cmake-build-debug/ 10 | cmake-build-release/ 11 | 12 | # File-based project format 13 | *.iws 14 | 15 | # IntelliJ 16 | *.iml 17 | out/ 18 | 19 | # mpeltonen/sbt-idea plugin 20 | .idea_modules/ 21 | 22 | # JIRA plugin 23 | atlassian-ide-plugin.xml 24 | 25 | # Editor config 26 | .editorconfig 27 | 28 | # Crashlytics plugin (for Android Studio and IntelliJ) 29 | com_crashlytics_export_strings.xml 30 | crashlytics.properties 31 | crashlytics-build.properties 32 | fabric.properties 33 | 34 | # Compiled class file 35 | *.class 36 | 37 | # Log file 38 | *.log 39 | 40 | # BlueJ files 41 | *.ctxt 42 | 43 | # Mobile Tools for Java (J2ME) 44 | .mtj.tmp/ 45 | 46 | # Package Files # 47 | *.jar 48 | *.war 49 | *.nar 50 | *.ear 51 | *.zip 52 | *.tar.gz 53 | *.rar 54 | 55 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 56 | hs_err_pid* 57 | 58 | # spring boot 59 | application.properties 60 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | dist: trusty 3 | sudo: false 4 | 5 | os: 6 | - linux 7 | - osx 8 | 9 | jdk: 10 | - openjdk9 11 | - openjdk10 12 | 13 | matrix: 14 | fast_finish: true 15 | include: 16 | - os: linux 17 | jdk: openjdk8 18 | allow_failures: 19 | - jdk: openjdk11 20 | - jdk: openjdk-ea 21 | - jdk: oraclejdk-ea 22 | 23 | before_install: 24 | - unset _JAVA_OPTIONS 25 | 26 | script: 27 | - mvn clean install spring-boot:repackage 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Friendly Garbanzo 2 | Discord all-purpose bot, made using Spring Boot, JPA, Hibernate, REST, HikariCP. Written for fun, do not take this serious 3 | 4 | ## Services 5 | | Type | Badges | 6 | | --------------------------- | -------------------------------------------------------------------- | 7 | | **Code quality:** | [![maintability-icon]][maintability] | 8 | | **Continuous Integration:** | [![travis-icon]][travis] [![appveyor-icon]][appveyor] | 9 | 10 | ## Endpoints 11 | 12 | | Method | Optional query parameters | Success status codes | Error status codes | 13 | | -------------------------------------------------- | -------------------------- | --------------------- | ------------------ | 14 | | **GET /api/users** | page, size | 200 | | 15 | | **GET /api/users/by-id/{id}** | | 200 | 404 | 16 | | **GET /api/users/by-name/{name}** | | 200 | 404 | 17 | 18 | ## Features 19 | - [x] Storing all user's data to mysql database 20 | - [x] Public rest api without oauth 21 | - [x] Github command, that shows infos about your github profile 22 | - [x] Commit command - displays commits' count 23 | - [x] Say command, that talks in json 24 | 25 | ## Configuration 26 | Create file named `application.properties` in your resource directory, with the following content: 27 | ```properties 28 | # DATA SOURCE 29 | spring.datasource.url=jdbc:mysql://localhost:3306/garbanzo 30 | spring.datasource.username=root 31 | spring.datasource.password=root 32 | # JPA HIBERNATE 33 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect 34 | spring.jpa.properties.hibernate.format_sql=true 35 | spring.jpa.hibernate.use-new-id-generator-mappings=false 36 | spring.jpa.open-in-view=false 37 | # I18N 38 | spring.messages.basename=locale/messages 39 | spring.messages.encoding=UTF-8 40 | spring.messages.fallback-to-system-locale=true 41 | # JDA 42 | jda.discord.token=your discord key 43 | # JACKSON 44 | spring.jackson.serialization.indent_output=true 45 | ``` 46 | 47 | ## Contributing 48 | - fork it 49 | - create your own branch, like so: `command/xx/8ball`, where `xx` are your initials. 50 | - commit and push your changes 51 | - create pull request 52 | - wait for the review 53 | 54 | The first rule, the only rule, is that you need use [Google Code Style][google-code-style] 55 | 56 | ## License 57 | See the [License][license] file. 58 | 59 | [maintability-icon]: https://api.codeclimate.com/v1/badges/c3999fe48e9f82826c72/maintainability 60 | [maintability]: https://codeclimate.com/github/bmstefanski/friendly-garbanzo/maintainability 61 | [appveyor-icon]: https://ci.appveyor.com/api/projects/status/qekeotnyecdnpr2c/branch/master?svg=true 62 | [appveyor]: https://ci.appveyor.com/project/bmstefanski/friendly-garbanzo/branch/master 63 | [travis-icon]: https://travis-ci.org/bmstefanski/spring-discord-bot.svg?branch=master 64 | [travis]: https://travis-ci.org/bmstefanski/spring-discord-bot 65 | [license]: https://github.com/bmstefanski/spring-discord-bot/blob/master/LICENSE 66 | [google-code-style]: https://github.com/google/styleguide/blob/gh-pages/intellij-java-google-style.xml 67 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 4 | 5 | install: 6 | - java -version 7 | - mvn --version 8 | 9 | build_script: 10 | - mvn clean install spring-boot:repackage 11 | 12 | cache: 13 | - C:\maven\ 14 | - C:\Users\appveyor\.m2 15 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | pl.bmstefanski 8 | friendly-garbanzo 9 | jar 10 | 1.0-SNAPSHOT 11 | Friendly Garbanzo 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 2.0.2.RELEASE 17 | 18 | 19 | 20 | 21 | UTF-8 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | jcenter 29 | jcenter-bintray 30 | http://jcenter.bintray.com 31 | 32 | 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-data-jpa 38 | 39 | 40 | 41 | mysql 42 | mysql-connector-java 43 | runtime 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | 53 | net.dv8tion 54 | JDA 55 | 3.6.0_373 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-configuration-processor 61 | true 62 | 63 | 64 | 65 | org.springframework.boot 66 | spring-boot-starter-web 67 | 68 | 69 | 70 | com.mashape.unirest 71 | unirest-java 72 | 1.4.9 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.springframework.boot 80 | spring-boot-maven-plugin 81 | 82 | 83 | 84 | org.eluder.coveralls 85 | coveralls-maven-plugin 86 | 4.3.0 87 | 88 | false 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bmstefanski/spring-discord-bot/d0faf769bd6683801df5425d44eb41b9dccb7be6/src/main/java/pl/bmstefanski/garbanzo/.gitkeep -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/ApplicationBootstrap.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo; 2 | 3 | import org.springframework.boot.CommandLineRunner; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 7 | import pl.bmstefanski.garbanzo.command.CommitCommand; 8 | import pl.bmstefanski.garbanzo.command.EightBallCommand; 9 | import pl.bmstefanski.garbanzo.command.FactCommand; 10 | import pl.bmstefanski.garbanzo.command.GitHubCommand; 11 | import pl.bmstefanski.garbanzo.command.RegisterAccountCommand; 12 | import pl.bmstefanski.garbanzo.command.SayCommand; 13 | import pl.bmstefanski.garbanzo.command.defaults.impl.CommandRegistry; 14 | import pl.bmstefanski.garbanzo.listener.GuildMemberJoinListener; 15 | import pl.bmstefanski.garbanzo.service.GarbanzoService; 16 | 17 | @EnableConfigurationProperties 18 | @SpringBootApplication 19 | public class ApplicationBootstrap implements CommandLineRunner { 20 | 21 | private final GarbanzoService garbanzoService; 22 | private final CommandRegistry commandRegistry; 23 | 24 | public ApplicationBootstrap(GarbanzoService garbanzoService, CommandRegistry commandRegistry) { 25 | this.garbanzoService = garbanzoService; 26 | this.commandRegistry = commandRegistry; 27 | } 28 | 29 | public static void main(String[] args) { 30 | SpringApplication.run(ApplicationBootstrap.class, args); 31 | } 32 | 33 | @Override 34 | public void run(String... args) throws Exception { 35 | this.garbanzoService.startBot(); 36 | 37 | this.garbanzoService.registerListeners( 38 | new GuildMemberJoinListener() 39 | ); 40 | 41 | this.commandRegistry.registerByExecutors( 42 | new RegisterAccountCommand(), 43 | new GitHubCommand(), 44 | new CommitCommand(), 45 | new SayCommand(), 46 | new FactCommand(), 47 | new EightBallCommand() 48 | ); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bmstefanski/spring-discord-bot/d0faf769bd6683801df5425d44eb41b9dccb7be6/src/main/java/pl/bmstefanski/garbanzo/command/.gitkeep -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/CommitCommand.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command; 2 | 3 | import com.mashape.unirest.http.HttpResponse; 4 | import com.mashape.unirest.http.JsonNode; 5 | import com.mashape.unirest.http.Unirest; 6 | import java.awt.Color; 7 | import java.util.List; 8 | import java.util.concurrent.ExecutionException; 9 | import net.dv8tion.jda.core.EmbedBuilder; 10 | import net.dv8tion.jda.core.entities.MessageEmbed; 11 | import org.json.JSONArray; 12 | import org.json.JSONObject; 13 | import org.springframework.stereotype.Component; 14 | import pl.bmstefanski.garbanzo.command.defaults.CommandExecutor; 15 | import pl.bmstefanski.garbanzo.command.defaults.CommandInfo; 16 | import pl.bmstefanski.garbanzo.command.defaults.CommandSender; 17 | import pl.bmstefanski.garbanzo.util.RestServiceType; 18 | 19 | @Component 20 | public class CommitCommand implements CommandExecutor { 21 | 22 | @CommandInfo(value = "commit", minArguments = 1, maxArguments = 2, usage = " [Yyyy-Mm-Dd]") 23 | @Override 24 | public void execute(CommandSender commandSender, List args) { 25 | try { 26 | HttpResponse httpResponse = Unirest 27 | .get(RestServiceType.GITHUB_ACTIVITY_API_URL) 28 | .header("Accept", "application/json") 29 | .routeParam("username", args.get(0)) 30 | .asJsonAsync() 31 | .get(); 32 | 33 | JSONArray yearsJsonArray = httpResponse.getBody().getObject().getJSONArray("years"); 34 | 35 | if (yearsJsonArray.length() == 0) { 36 | String footerMessage = commandSender.getMessage("wrong-username"); 37 | MessageEmbed messageEmbeds = new EmbedBuilder() 38 | .setColor(Color.RED) 39 | .setFooter(footerMessage, null) 40 | .build(); 41 | 42 | commandSender.sendEmbedMessage(messageEmbeds); 43 | return; 44 | } 45 | 46 | String titleMessage = commandSender.getMessage("activity-title", args.get(0)); 47 | 48 | if (args.size() == 1) { 49 | EmbedBuilder embedBuilder = new EmbedBuilder() 50 | .setColor(Color.GREEN) 51 | .setTitle(titleMessage); 52 | 53 | for (int i = 0; i < yearsJsonArray.length(); i++) { 54 | String fieldMessage = commandSender 55 | .getMessage("year", yearsJsonArray.getJSONObject(i).getString("year")); 56 | embedBuilder.addField(fieldMessage, 57 | String.valueOf(yearsJsonArray.getJSONObject(i).getInt("total")), true); 58 | } 59 | 60 | commandSender.sendEmbedMessage(embedBuilder.build()); 61 | return; 62 | } 63 | 64 | JSONArray contributionsJsonArray = httpResponse.getBody().getObject() 65 | .getJSONArray("contributions"); 66 | 67 | String footerMessage = commandSender.getMessage("no-activity", args.get(1)); 68 | EmbedBuilder embedBuilder = new EmbedBuilder() 69 | .setColor(Color.RED) 70 | .setFooter(footerMessage, null); 71 | 72 | for (int i = 0; i < contributionsJsonArray.length(); i++) { 73 | JSONObject jsonObject = contributionsJsonArray.getJSONObject(i); 74 | 75 | if (args.get(1).equals(jsonObject.getString("date"))) { 76 | embedBuilder.setTitle(titleMessage); 77 | embedBuilder.setColor(Color.decode(jsonObject.getString("color"))); 78 | embedBuilder.addField(commandSender.getMessage("searching-date"), args.get(1), true); 79 | embedBuilder.addField(commandSender.getMessage("contributions"), 80 | String.valueOf(jsonObject.getInt("count")), true); 81 | embedBuilder.setFooter(null, null); 82 | } 83 | 84 | } 85 | 86 | commandSender.sendEmbedMessage(embedBuilder.build()); 87 | } catch (InterruptedException | ExecutionException e) { 88 | e.printStackTrace(); 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/EightBallCommand.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command; 2 | 3 | import com.mashape.unirest.http.HttpResponse; 4 | import com.mashape.unirest.http.JsonNode; 5 | import com.mashape.unirest.http.Unirest; 6 | import com.mashape.unirest.http.exceptions.UnirestException; 7 | import java.awt.Color; 8 | import java.util.List; 9 | import net.dv8tion.jda.core.EmbedBuilder; 10 | import net.dv8tion.jda.core.entities.MessageChannel; 11 | import net.dv8tion.jda.core.entities.MessageEmbed; 12 | import org.springframework.stereotype.Component; 13 | import pl.bmstefanski.garbanzo.command.defaults.CommandExecutor; 14 | import pl.bmstefanski.garbanzo.command.defaults.CommandInfo; 15 | import pl.bmstefanski.garbanzo.command.defaults.CommandSender; 16 | import pl.bmstefanski.garbanzo.util.RestServiceType; 17 | 18 | @Component 19 | public class EightBallCommand implements CommandExecutor { 20 | 21 | @CommandInfo(value = "8ball", minArguments = 1, maxArguments = Integer.MAX_VALUE) 22 | @Override 23 | public void execute(CommandSender commandSender, List args) { 24 | try { 25 | HttpResponse httpResponse = Unirest 26 | .get(RestServiceType.ANIME_API_URL + "/img/8ball") 27 | .header("Accept", "application/json") 28 | .asJson(); 29 | 30 | StringBuilder stringBuilder = new StringBuilder(); 31 | 32 | for (String arg : args) { 33 | stringBuilder.append(arg).append(" "); 34 | } 35 | 36 | MessageChannel messageChannel = commandSender.getMessageChannel(); 37 | String lastMessageId = messageChannel.getLatestMessageId(); 38 | String lastMessage = messageChannel.getMessageById(lastMessageId).complete().getContentRaw() 39 | .split(" ")[1]; 40 | String properMessage = stringBuilder.toString(); 41 | 42 | System.out.println("proper: " + properMessage); 43 | System.out.println("last: " + lastMessage); 44 | 45 | if (!properMessage.contains("?")) { 46 | MessageEmbed messageEmbed = new EmbedBuilder() 47 | .setColor(Color.RED) 48 | .setFooter("Do you know, that every question has a question mark at the end of it?", null) 49 | .build(); 50 | 51 | commandSender.sendEmbedMessage(messageEmbed); 52 | return; 53 | } 54 | 55 | MessageEmbed messageEmbed = new EmbedBuilder() 56 | .setColor(Color.decode("#3b5998")) 57 | .setTitle(stringBuilder.toString()) 58 | .setImage(httpResponse.getBody().getObject().getString("url")) 59 | .build(); 60 | 61 | commandSender.sendEmbedMessage(messageEmbed); 62 | } catch (UnirestException e) { 63 | e.printStackTrace(); 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/FactCommand.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command; 2 | 3 | import com.mashape.unirest.http.HttpResponse; 4 | import com.mashape.unirest.http.JsonNode; 5 | import com.mashape.unirest.http.Unirest; 6 | import java.awt.Color; 7 | import java.util.List; 8 | import java.util.concurrent.ExecutionException; 9 | import net.dv8tion.jda.core.EmbedBuilder; 10 | import net.dv8tion.jda.core.entities.MessageEmbed; 11 | import org.springframework.stereotype.Component; 12 | import pl.bmstefanski.garbanzo.command.defaults.CommandExecutor; 13 | import pl.bmstefanski.garbanzo.command.defaults.CommandInfo; 14 | import pl.bmstefanski.garbanzo.command.defaults.CommandSender; 15 | import pl.bmstefanski.garbanzo.util.RestServiceType; 16 | 17 | @Component 18 | public class FactCommand implements CommandExecutor { 19 | 20 | @CommandInfo("fact") 21 | @Override 22 | public void execute(CommandSender commandSender, List args) { 23 | try { 24 | HttpResponse httpResponse = Unirest.get(RestServiceType.ANIME_API_URL + "/fact") 25 | .header("Accept", "application/json") 26 | .asJsonAsync() 27 | .get(); 28 | 29 | String factMessage = httpResponse.getBody().getObject().getString("fact"); 30 | 31 | MessageEmbed messageEmbed = new EmbedBuilder() 32 | .setColor(Color.decode("#ff6666")) 33 | .setTitle("Did you know that..") 34 | .setDescription(factMessage) 35 | .build(); 36 | 37 | commandSender.sendEmbedMessage(messageEmbed); 38 | } catch (InterruptedException | ExecutionException e) { 39 | e.printStackTrace(); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/GitHubCommand.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command; 2 | 3 | import com.mashape.unirest.http.HttpResponse; 4 | import com.mashape.unirest.http.JsonNode; 5 | import com.mashape.unirest.http.Unirest; 6 | import java.awt.Color; 7 | import java.util.List; 8 | import java.util.concurrent.ExecutionException; 9 | import net.dv8tion.jda.core.EmbedBuilder; 10 | import net.dv8tion.jda.core.entities.MessageEmbed; 11 | import org.json.JSONObject; 12 | import org.springframework.stereotype.Component; 13 | import pl.bmstefanski.garbanzo.command.defaults.CommandExecutor; 14 | import pl.bmstefanski.garbanzo.command.defaults.CommandInfo; 15 | import pl.bmstefanski.garbanzo.command.defaults.CommandSender; 16 | import pl.bmstefanski.garbanzo.util.RestServiceType; 17 | 18 | @Component 19 | public class GitHubCommand implements CommandExecutor { 20 | 21 | @CommandInfo(value = "github", minArguments = 1, maxArguments = 1, usage = "") 22 | @Override 23 | public void execute(CommandSender commandSender, List args) { 24 | try { 25 | HttpResponse httpResponse = Unirest.get(RestServiceType.GITHUB_API_URL) 26 | .header("Accept", "application/json") 27 | .routeParam("username", args.get(0)) 28 | .asJsonAsync() 29 | .get(); 30 | 31 | if (httpResponse.getStatus() == 404) { 32 | String footerMessage = commandSender.getMessage("wrong-username"); 33 | MessageEmbed messageEmbeds = new EmbedBuilder() 34 | .setColor(Color.RED) 35 | .setFooter(footerMessage, null) 36 | .build(); 37 | 38 | commandSender.sendEmbedMessage(messageEmbeds); 39 | return; 40 | } 41 | 42 | JSONObject jsonObject = httpResponse.getBody().getObject(); 43 | 44 | String login = jsonObject.getString("login"); 45 | String profileUrl = jsonObject.getString("html_url"); 46 | String bio = jsonObject.isNull("bio") ? "" : String.valueOf(jsonObject.get("bio")); 47 | String location = jsonObject.isNull("location") ? "" : String.valueOf(jsonObject.get("location")); 48 | String registrationDate = jsonObject.getString("created_at"); 49 | String avatarUrl = jsonObject.getString("avatar_url"); 50 | int followers = jsonObject.getInt("followers"); 51 | int following = jsonObject.getInt("following"); 52 | int repositories = jsonObject.getInt("public_repos"); 53 | int gists = jsonObject.getInt("public_gists"); 54 | 55 | MessageEmbed messageEmbed = new EmbedBuilder() 56 | .setColor(Color.decode("#2b2b2b")) 57 | .setThumbnail(avatarUrl) 58 | .addField(commandSender.getMessage("name"), "[" + login + "]" + "(" + profileUrl + ")", true) 59 | .addField(commandSender.getMessage("bio"), bio, true) 60 | .addField(commandSender.getMessage("location"), location, true) 61 | .addField(commandSender.getMessage("registration"), registrationDate, true) 62 | .addField(commandSender.getMessage("followers"), String.valueOf(followers), true) 63 | .addField(commandSender.getMessage("following"), String.valueOf(following), true) 64 | .addField(commandSender.getMessage("repositories"), String.valueOf(repositories), true) 65 | .addField(commandSender.getMessage("gists"), String.valueOf(gists), true) 66 | .build(); 67 | 68 | commandSender.sendEmbedMessage(messageEmbed); 69 | } catch (InterruptedException | ExecutionException e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/RegisterAccountCommand.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command; 2 | 3 | import java.awt.Color; 4 | import java.sql.Date; 5 | import java.time.Instant; 6 | import java.util.List; 7 | import java.util.Optional; 8 | import net.dv8tion.jda.core.EmbedBuilder; 9 | import net.dv8tion.jda.core.entities.MessageEmbed; 10 | import net.dv8tion.jda.core.entities.User; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | import pl.bmstefanski.garbanzo.command.defaults.CommandExecutor; 14 | import pl.bmstefanski.garbanzo.command.defaults.CommandInfo; 15 | import pl.bmstefanski.garbanzo.command.defaults.CommandSender; 16 | import pl.bmstefanski.garbanzo.entity.impl.UserEntityImpl; 17 | import pl.bmstefanski.garbanzo.repository.UserRepository; 18 | 19 | @Component 20 | public class RegisterAccountCommand implements CommandExecutor { 21 | 22 | private final UserRepository userRepository; 23 | 24 | @Autowired 25 | public RegisterAccountCommand(UserRepository userRepository) { 26 | this.userRepository = userRepository; 27 | } 28 | 29 | public RegisterAccountCommand() { 30 | this(null); 31 | } 32 | 33 | @CommandInfo("register") 34 | @Override 35 | public void execute(CommandSender commandSender, List args) { 36 | long userId = commandSender.getJdaUser().getIdLong(); 37 | 38 | Optional optionalUserEntity = userRepository.findById(userId); 39 | 40 | if (optionalUserEntity.isPresent()) { 41 | String footer = commandSender.getMessage("already-registered"); 42 | 43 | MessageEmbed messageEmbed = new EmbedBuilder() 44 | .setColor(Color.RED) 45 | .setFooter(footer, null) 46 | .build(); 47 | 48 | commandSender.sendEmbedMessage(messageEmbed); 49 | return; 50 | } 51 | 52 | User jdaUser = commandSender.getJdaUser(); 53 | 54 | UserEntityImpl userEntity = new UserEntityImpl.Builder() 55 | .withIdentifier(jdaUser.getIdLong()) 56 | .withName(jdaUser.getName()) 57 | .setRegistrationDate(Date.from(Instant.now())) 58 | .build(); 59 | 60 | this.userRepository.save(userEntity); 61 | 62 | String title = commandSender.getMessage("successfully-registered"); 63 | String nickname = commandSender.getMessage("nickname"); 64 | String identifier = commandSender.getMessage("identifier"); 65 | String date = commandSender.getMessage("date"); 66 | 67 | MessageEmbed messageEmbed = new EmbedBuilder() 68 | .setColor(Color.GREEN) 69 | .setTitle(title) 70 | .addField(nickname, userEntity.getName(), true) 71 | .addField(identifier, userEntity.getIdentifier().toString(), true) 72 | .addField(date, userEntity.getRegistrationDate().toString(), true) 73 | .build(); 74 | 75 | commandSender.sendEmbedMessage(messageEmbed); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/SayCommand.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command; 2 | 3 | import java.awt.Color; 4 | import java.util.List; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | import net.dv8tion.jda.core.EmbedBuilder; 8 | import net.dv8tion.jda.core.entities.MessageEmbed; 9 | import org.json.JSONObject; 10 | import org.springframework.stereotype.Component; 11 | import pl.bmstefanski.garbanzo.command.defaults.CommandExecutor; 12 | import pl.bmstefanski.garbanzo.command.defaults.CommandInfo; 13 | import pl.bmstefanski.garbanzo.command.defaults.CommandSender; 14 | 15 | @Component 16 | public class SayCommand implements CommandExecutor { 17 | 18 | @CommandInfo(value = "say", minArguments = 1, maxArguments = Integer.MAX_VALUE, usage = "(?:{\"type\":\")(.*?)(?:\",.\"message\":\")(.*?)(?:\"})") 19 | @Override 20 | public void execute(CommandSender commandSender, List args) { 21 | 22 | StringBuilder stringBuilder = new StringBuilder(); 23 | 24 | for (String arg : args) { 25 | stringBuilder.append(arg).append(" "); 26 | } 27 | 28 | Pattern pattern = Pattern 29 | .compile("\\{\\s*\"type\"\\s*:\\s*(.*?)\\s*,\\s*\"message\"\\s*:\\s*(.*?)}"); 30 | Matcher matcher = pattern.matcher(stringBuilder.toString()); 31 | 32 | if (!matcher.find()) { 33 | this.performMessageFooter(commandSender, commandSender.getMessage("invalid-json"), Color.RED); 34 | return; 35 | } 36 | 37 | JSONObject jsonObject = new JSONObject(stringBuilder.toString()); 38 | 39 | switch (jsonObject.getString("type")) { 40 | case "normal": 41 | commandSender.sendRawMessage(String.valueOf(jsonObject.get("message"))); 42 | break; 43 | case "footer": 44 | this.performMessageFooter(commandSender, String.valueOf(jsonObject.get("message")), 45 | Color.decode("#2b2b2b")); 46 | break; 47 | default: 48 | this.performMessageFooter(commandSender, commandSender.getMessage("wrong-message-type"), Color.RED); 49 | } 50 | } 51 | 52 | private void performMessageFooter(CommandSender commandSender, String message, Color color) { 53 | MessageEmbed messageEmbed = new EmbedBuilder() 54 | .setColor(color) 55 | .setFooter(message, null) 56 | .build(); 57 | 58 | commandSender.sendEmbedMessage(messageEmbed); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/defaults/Command.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command.defaults; 2 | 3 | public interface Command { 4 | 5 | void setName(String name); 6 | 7 | void setUsage(String usage); 8 | 9 | void setMinArguments(int minArguments); 10 | 11 | void setMaxArguments(int maxArguments); 12 | 13 | void setExecutor(CommandExecutor executor); 14 | 15 | String getName(); 16 | 17 | String getUsage(); 18 | 19 | int getMinArguments(); 20 | 21 | int getMaxArguments(); 22 | 23 | CommandExecutor getExecutor(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/defaults/CommandExecutor.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command.defaults; 2 | 3 | import java.util.List; 4 | 5 | public interface CommandExecutor { 6 | 7 | void execute(CommandSender commandSender, List args); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/defaults/CommandInfo.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command.defaults; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface CommandInfo { 11 | 12 | String value(); 13 | 14 | String usage() default ""; 15 | 16 | int minArguments() default 0; 17 | 18 | int maxArguments() default 0; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/defaults/CommandSender.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command.defaults; 2 | 3 | import java.util.List; 4 | import net.dv8tion.jda.core.entities.Message; 5 | import net.dv8tion.jda.core.entities.MessageChannel; 6 | import net.dv8tion.jda.core.entities.MessageEmbed; 7 | import net.dv8tion.jda.core.entities.User; 8 | 9 | public interface CommandSender { 10 | 11 | void sendRawMessage(String message, Object... arguments); 12 | 13 | void sendRawMessage(List messages, Object... arguments); 14 | 15 | void sendMessage(String key, String... arguments); 16 | 17 | void sendMessage(List keys, String... arguments); 18 | 19 | String getMessage(String key, String... arguments); 20 | 21 | void sendEmbedMessage(MessageEmbed message); 22 | 23 | MessageChannel getMessageChannel(); 24 | 25 | User getJdaUser(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/defaults/impl/CommandBuilder.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command.defaults.impl; 2 | 3 | import pl.bmstefanski.garbanzo.command.defaults.CommandExecutor; 4 | import pl.bmstefanski.garbanzo.command.defaults.Command; 5 | import pl.bmstefanski.garbanzo.util.Buildable; 6 | 7 | public class CommandBuilder implements Buildable { 8 | 9 | private String name; 10 | private String usage = ""; 11 | private int minArguments = 0; 12 | private int maxArguments = 0; 13 | private CommandExecutor executor; 14 | 15 | public CommandBuilder withName(String name) { 16 | this.name = name; 17 | return this; 18 | } 19 | 20 | public CommandBuilder withUsage(String usage) { 21 | this.usage = usage; 22 | return this; 23 | } 24 | 25 | public CommandBuilder withMinArguments(int minArguments) { 26 | this.minArguments = minArguments; 27 | return this; 28 | } 29 | 30 | public CommandBuilder withMaxArguments(int maxArguments) { 31 | this.maxArguments = maxArguments; 32 | return this; 33 | } 34 | 35 | public CommandBuilder withCommandExecutor(CommandExecutor commandExecutor) { 36 | this.executor = commandExecutor; 37 | return this; 38 | } 39 | 40 | public String getName() { 41 | return this.name; 42 | } 43 | 44 | public String getUsage() { 45 | return this.usage; 46 | } 47 | 48 | public int getMinArguments() { 49 | return this.minArguments; 50 | } 51 | 52 | public int getMaxArguments() { 53 | return this.maxArguments; 54 | } 55 | 56 | public CommandExecutor getExecutor() { 57 | return this.executor; 58 | } 59 | 60 | @Override 61 | public Command build() { 62 | return new CommandImpl(this); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/defaults/impl/CommandImpl.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command.defaults.impl; 2 | 3 | import pl.bmstefanski.garbanzo.command.defaults.CommandExecutor; 4 | import pl.bmstefanski.garbanzo.command.defaults.Command; 5 | 6 | public class CommandImpl implements Command { 7 | 8 | private String name; 9 | private String usage; 10 | private int minArguments; 11 | private int maxArguments; 12 | private CommandExecutor executor; 13 | 14 | CommandImpl(CommandBuilder commandBuilder) { 15 | this.name = commandBuilder.getName(); 16 | this.usage = commandBuilder.getUsage(); 17 | this.minArguments = commandBuilder.getMinArguments(); 18 | this.maxArguments = commandBuilder.getMaxArguments(); 19 | this.executor = commandBuilder.getExecutor(); 20 | } 21 | 22 | @Override 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | 27 | @Override 28 | public void setUsage(String usage) { 29 | this.usage = usage; 30 | } 31 | 32 | @Override 33 | public void setMinArguments(int minArguments) { 34 | this.minArguments = minArguments; 35 | } 36 | 37 | @Override 38 | public void setMaxArguments(int maxArguments) { 39 | this.maxArguments = maxArguments; 40 | } 41 | 42 | @Override 43 | public void setExecutor(CommandExecutor executor) { 44 | this.executor = executor; 45 | } 46 | 47 | @Override 48 | public String getName() { 49 | return this.name; 50 | } 51 | 52 | @Override 53 | public String getUsage() { 54 | return this.usage; 55 | } 56 | 57 | @Override 58 | public int getMinArguments() { 59 | return this.minArguments; 60 | } 61 | 62 | @Override 63 | public int getMaxArguments() { 64 | return this.maxArguments; 65 | } 66 | 67 | @Override 68 | public CommandExecutor getExecutor() { 69 | return this.executor; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/defaults/impl/CommandRegistry.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command.defaults.impl; 2 | 3 | import java.awt.Color; 4 | import java.lang.reflect.Method; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | import net.dv8tion.jda.core.EmbedBuilder; 9 | import net.dv8tion.jda.core.entities.MessageChannel; 10 | import net.dv8tion.jda.core.entities.MessageEmbed; 11 | import net.dv8tion.jda.core.events.message.MessageReceivedEvent; 12 | import net.dv8tion.jda.core.hooks.AnnotatedEventManager; 13 | import net.dv8tion.jda.core.hooks.SubscribeEvent; 14 | import pl.bmstefanski.garbanzo.command.defaults.Command; 15 | import pl.bmstefanski.garbanzo.command.defaults.CommandExecutor; 16 | import pl.bmstefanski.garbanzo.command.defaults.CommandInfo; 17 | import pl.bmstefanski.garbanzo.command.defaults.CommandSender; 18 | import pl.bmstefanski.garbanzo.component.MessageComponent; 19 | import pl.bmstefanski.garbanzo.configuration.GarbanzoProperties; 20 | import pl.bmstefanski.garbanzo.service.GarbanzoService; 21 | 22 | public class CommandRegistry { 23 | 24 | private final MessageComponent messageComponent; 25 | private final GarbanzoService garbanzoService; 26 | private final GarbanzoProperties properties; 27 | 28 | public CommandRegistry(MessageComponent messageComponent, GarbanzoService garbanzoService, 29 | GarbanzoProperties properties) { 30 | this.messageComponent = messageComponent; 31 | this.garbanzoService = garbanzoService; 32 | this.properties = properties; 33 | } 34 | 35 | public void registerByClasses(Class... classes) { 36 | try { 37 | for (Class clazz : classes) { 38 | CommandExecutor commandExecutor = clazz.newInstance(); 39 | this.registerByExecutors(commandExecutor); 40 | } 41 | } catch (InstantiationException | IllegalAccessException e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | 46 | public void registerByExecutors(CommandExecutor... commandExecutors) { 47 | for (CommandExecutor commandExecutor : commandExecutors) { 48 | Method[] methods = commandExecutor.getClass().getMethods(); 49 | 50 | for (Method method : methods) { 51 | if (method.isAnnotationPresent(CommandInfo.class)) { 52 | CommandInfo commandInfo = method.getAnnotation(CommandInfo.class); 53 | 54 | Command command = new CommandBuilder() 55 | .withName(commandInfo.value()) 56 | .withUsage(commandInfo.usage()) 57 | .withMinArguments(commandInfo.minArguments()) 58 | .withMaxArguments(commandInfo.maxArguments()) 59 | .withCommandExecutor(commandExecutor) 60 | .build(); 61 | 62 | this.garbanzoService.getJda().addEventListener(new AnnotatedEventManager() { 63 | 64 | @SubscribeEvent 65 | public void messageReceivedEvent(MessageReceivedEvent event) { 66 | MessageChannel messageChannel = event.getChannel(); 67 | String messageContent = event.getMessage().getContentRaw(); 68 | CommandSender commandSender = new CommandSenderImpl(messageChannel, messageComponent, 69 | event.getAuthor()); 70 | 71 | String prefix = properties.getPrefix(); 72 | 73 | if (messageContent.startsWith(prefix + command.getName())) { 74 | List args = Arrays.stream(messageContent.split(" ")).skip(1) 75 | .collect(Collectors.toList()); 76 | 77 | if ((args.size() < command.getMinArguments()) || (args.size() > command 78 | .getMaxArguments())) { 79 | 80 | String usage = prefix + command.getName() + " " + command.getUsage(); 81 | MessageEmbed messageEmbed = new EmbedBuilder() 82 | .setColor(Color.RED) 83 | .setFooter(messageComponent.get("invalid-pattern", usage), null) 84 | .build(); 85 | messageChannel.sendMessage(messageEmbed).queue(); 86 | return; 87 | } 88 | 89 | commandExecutor.execute(commandSender, args); 90 | } 91 | } 92 | 93 | }); 94 | 95 | } 96 | } 97 | } 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/command/defaults/impl/CommandSenderImpl.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.command.defaults.impl; 2 | 3 | import java.util.List; 4 | import net.dv8tion.jda.core.entities.MessageChannel; 5 | import net.dv8tion.jda.core.entities.MessageEmbed; 6 | import net.dv8tion.jda.core.entities.User; 7 | import pl.bmstefanski.garbanzo.command.defaults.CommandSender; 8 | import pl.bmstefanski.garbanzo.component.MessageComponent; 9 | 10 | public class CommandSenderImpl implements CommandSender { 11 | 12 | private final MessageChannel messageChannel; 13 | private final MessageComponent messageComponent; 14 | private final User user; 15 | 16 | public CommandSenderImpl(MessageChannel messageChannel, 17 | MessageComponent messageComponent, User user) { 18 | this.messageChannel = messageChannel; 19 | this.messageComponent = messageComponent; 20 | this.user = user; 21 | } 22 | 23 | @Override 24 | public void sendRawMessage(String message, Object... arguments) { 25 | this.messageChannel.sendMessageFormat(message, arguments).queue(); 26 | } 27 | 28 | @Override 29 | public void sendRawMessage(List messages, Object... arguments) { 30 | messages.forEach(message -> this.sendRawMessage(message, arguments)); 31 | } 32 | 33 | @Override 34 | public void sendMessage(String key, String... arguments) { 35 | this.messageChannel.sendMessage(this.messageComponent.get(key, arguments)).queue(); 36 | } 37 | 38 | @Override 39 | public void sendMessage(List keys, String... arguments) { 40 | keys.forEach(key -> this.sendMessage(key, arguments)); 41 | } 42 | 43 | @Override 44 | public String getMessage(String key, String... arguments) { 45 | return this.messageComponent.get(key, arguments); 46 | } 47 | 48 | @Override 49 | public void sendEmbedMessage(MessageEmbed message) { 50 | this.messageChannel.sendMessage(message).queue(); 51 | } 52 | 53 | @Override 54 | public MessageChannel getMessageChannel() { 55 | return this.messageChannel; 56 | } 57 | 58 | @Override 59 | public User getJdaUser() { 60 | return this.user; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/component/MessageComponent.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.component; 2 | 3 | import javax.annotation.PostConstruct; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.MessageSource; 6 | import org.springframework.context.support.MessageSourceAccessor; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class MessageComponent { 11 | 12 | private final MessageSource messageSource; 13 | private MessageSourceAccessor messageSourceAccessor; 14 | 15 | @Autowired 16 | public MessageComponent(MessageSource messageSource) { 17 | this.messageSource = messageSource; 18 | } 19 | 20 | @PostConstruct 21 | private void initialize() { 22 | this.messageSourceAccessor = new MessageSourceAccessor(this.messageSource); 23 | } 24 | 25 | public String get(String key, String... args) { 26 | return this.messageSourceAccessor.getMessage(key, args); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/configuration/GarbanzoProperties.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.configuration; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.context.annotation.PropertySource; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | @PropertySource("classpath:garbanzo.properties") 9 | @ConfigurationProperties 10 | public class GarbanzoProperties { 11 | 12 | private String prefix; 13 | 14 | public String getPrefix() { 15 | return prefix; 16 | } 17 | 18 | public void setPrefix(String prefix) { 19 | this.prefix = prefix; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/configuration/SpringApplicationConfiguration.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.configuration; 2 | 3 | import javax.annotation.PostConstruct; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import pl.bmstefanski.garbanzo.command.defaults.impl.CommandRegistry; 7 | import pl.bmstefanski.garbanzo.component.MessageComponent; 8 | import pl.bmstefanski.garbanzo.service.GarbanzoService; 9 | import pl.bmstefanski.garbanzo.service.impl.GarbanzoServiceImpl; 10 | 11 | @Configuration 12 | public class SpringApplicationConfiguration { 13 | 14 | private final MessageComponent messageComponent; 15 | private final GarbanzoProperties garbanzoProperties; 16 | 17 | public SpringApplicationConfiguration(MessageComponent messageComponent, 18 | GarbanzoProperties garbanzoProperties) { 19 | this.messageComponent = messageComponent; 20 | this.garbanzoProperties = garbanzoProperties; 21 | } 22 | 23 | @Bean 24 | public GarbanzoService garbanzoService() { 25 | return new GarbanzoServiceImpl(); 26 | } 27 | 28 | @Bean 29 | public CommandRegistry commandRegistryBean() { 30 | return new CommandRegistry(this.messageComponent, this.garbanzoService(), 31 | this.garbanzoProperties); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/controller/RestErrorController.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.controller; 2 | 3 | import java.util.Map; 4 | import javax.servlet.http.HttpServletResponse; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.web.servlet.error.ErrorAttributes; 7 | import org.springframework.boot.web.servlet.error.ErrorController; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import org.springframework.web.context.request.WebRequest; 11 | 12 | @RestController 13 | public class RestErrorController implements ErrorController { 14 | 15 | private final ErrorAttributes errorAttributes; 16 | 17 | @Autowired 18 | public RestErrorController(ErrorAttributes errorAttributes) { 19 | this.errorAttributes = errorAttributes; 20 | } 21 | 22 | @GetMapping("/error") 23 | public ErrorJson error(WebRequest request, HttpServletResponse response) { 24 | return new ErrorJson(response.getStatus(), getErrorAttributes(request)); 25 | } 26 | 27 | private Map getErrorAttributes(WebRequest request) { 28 | return errorAttributes.getErrorAttributes(request, false); 29 | } 30 | 31 | @Override 32 | public String getErrorPath() { 33 | return "/error"; 34 | } 35 | 36 | private static class ErrorJson { 37 | 38 | String timeStamp; 39 | Integer status; 40 | String error; 41 | String message; 42 | String path; 43 | 44 | ErrorJson(int status, Map errorAttributes) { 45 | this.timeStamp = String.valueOf(errorAttributes.get("timestamp")); 46 | this.status = status; 47 | this.error = String.valueOf(errorAttributes.get("error")); 48 | this.message = String.valueOf(errorAttributes.get("message")); 49 | this.path = String.valueOf(errorAttributes.get("path")); 50 | } 51 | 52 | public String getTimeStamp() { 53 | return this.timeStamp; 54 | } 55 | 56 | public Integer getStatus() { 57 | return this.status; 58 | } 59 | 60 | public String getError() { 61 | return this.error; 62 | } 63 | 64 | public String getMessage() { 65 | return this.message; 66 | } 67 | 68 | public String getPath() { 69 | return this.path; 70 | } 71 | 72 | public void setTimeStamp(String timeStamp) { 73 | this.timeStamp = timeStamp; 74 | } 75 | 76 | public void setStatus(Integer status) { 77 | this.status = status; 78 | } 79 | 80 | public void setError(String error) { 81 | this.error = error; 82 | } 83 | 84 | public void setMessage(String message) { 85 | this.message = message; 86 | } 87 | 88 | public void setPath(String path) { 89 | this.path = path; 90 | } 91 | 92 | } 93 | 94 | } -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.controller; 2 | 3 | import java.util.List; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.PageRequest; 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestParam; 12 | import org.springframework.web.bind.annotation.RestController; 13 | import pl.bmstefanski.garbanzo.entity.impl.UserEntityImpl; 14 | import pl.bmstefanski.garbanzo.repository.UserRepository; 15 | 16 | @RequestMapping("/api/v1/users") 17 | @RestController 18 | public class UserController { 19 | 20 | private final UserRepository userRepository; 21 | 22 | public UserController(UserRepository userRepository) { 23 | this.userRepository = userRepository; 24 | } 25 | 26 | @GetMapping("/by-id/{id}") 27 | public ResponseEntity getUserById(@PathVariable long id) { 28 | return this.userRepository.findById(id) 29 | .map(ResponseEntity::ok) 30 | .orElseGet(() -> ResponseEntity.notFound().build()); 31 | } 32 | 33 | @GetMapping("/by-name/{name}") 34 | public ResponseEntity getUserByName(@PathVariable String name) { 35 | return this.userRepository.findByName(name) 36 | .map(ResponseEntity::ok) 37 | .orElseGet(() -> ResponseEntity.notFound().build()); 38 | } 39 | 40 | @GetMapping("/") 41 | public ResponseEntity> getAllUsers(@RequestParam(required = false, defaultValue = "0") int page, 42 | @RequestParam(required = false, defaultValue = "100") int size) { 43 | 44 | if (page < 0 || size < 1) { 45 | return ResponseEntity.badRequest().build(); 46 | } 47 | 48 | Pageable pageable = PageRequest.of(page, size); 49 | Page entities = this.userRepository.findAll(pageable); 50 | 51 | if (page > (entities.getTotalPages() - 1)) { 52 | return ResponseEntity.notFound().build(); 53 | } 54 | 55 | return ResponseEntity.ok(entities.getContent()); 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/entity/Entity.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.entity; 2 | 3 | public interface Entity { 4 | 5 | T getIdentifier(); 6 | 7 | void setIdentifier(T identifier); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/entity/UserEntity.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.entity; 2 | 3 | import java.util.Date; 4 | 5 | public interface UserEntity extends Entity { 6 | 7 | String getName(); 8 | 9 | void setName(String name); 10 | 11 | Date getRegistrationDate(); 12 | 13 | void setRegistrationDate(Date registrationDate); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/entity/impl/UserEntityImpl.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.entity.impl; 2 | 3 | import java.util.Date; 4 | import javax.persistence.Column; 5 | import javax.persistence.Entity; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | import javax.persistence.Temporal; 9 | import javax.persistence.TemporalType; 10 | import pl.bmstefanski.garbanzo.entity.UserEntity; 11 | import pl.bmstefanski.garbanzo.util.Buildable; 12 | 13 | @Entity 14 | @Table(name = "users") 15 | public class UserEntityImpl implements UserEntity { 16 | 17 | @Column(nullable = false) 18 | private String name; 19 | 20 | @Id 21 | @Column(nullable = false) 22 | private Long identifier; 23 | 24 | @Column(name = "registration", nullable = false) 25 | @Temporal(TemporalType.TIMESTAMP) 26 | private Date registrationDate; 27 | 28 | public UserEntityImpl() { 29 | } 30 | 31 | private UserEntityImpl(Builder builder) { 32 | this.name = builder.name; 33 | this.identifier = builder.identifier; 34 | this.registrationDate = builder.registrationDate; 35 | } 36 | 37 | @Override 38 | public String getName() { 39 | return this.name; 40 | } 41 | 42 | @Override 43 | public void setName(String name) { 44 | this.name = name; 45 | } 46 | 47 | @Override 48 | public Long getIdentifier() { 49 | return this.identifier; 50 | } 51 | 52 | @Override 53 | public void setIdentifier(Long identifier) { 54 | this.identifier = identifier; 55 | } 56 | 57 | @Override 58 | public Date getRegistrationDate() { 59 | return this.registrationDate; 60 | } 61 | 62 | @Override 63 | public void setRegistrationDate(Date registrationDate) { 64 | this.registrationDate = registrationDate; 65 | } 66 | 67 | public static class Builder implements Buildable { 68 | 69 | private String name; 70 | private Long identifier; 71 | private Date registrationDate; 72 | 73 | public Builder withName(String name) { 74 | this.name = name; 75 | return this; 76 | } 77 | 78 | public Builder withIdentifier(Long identifier) { 79 | this.identifier = identifier; 80 | return this; 81 | } 82 | 83 | public Builder setRegistrationDate(Date registrationDate) { 84 | this.registrationDate = registrationDate; 85 | return this; 86 | } 87 | 88 | @Override 89 | public UserEntityImpl build() { 90 | return new UserEntityImpl(this); 91 | } 92 | 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/listener/GuildMemberJoinListener.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.listener; 2 | 3 | import java.sql.Date; 4 | import java.time.Instant; 5 | import java.util.Optional; 6 | import net.dv8tion.jda.core.entities.User; 7 | import net.dv8tion.jda.core.events.guild.member.GuildMemberJoinEvent; 8 | import net.dv8tion.jda.core.hooks.SubscribeEvent; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Component; 11 | import pl.bmstefanski.garbanzo.entity.impl.UserEntityImpl; 12 | import pl.bmstefanski.garbanzo.repository.UserRepository; 13 | 14 | @Component 15 | public class GuildMemberJoinListener { 16 | 17 | private final UserRepository userRepository; 18 | 19 | @Autowired 20 | public GuildMemberJoinListener(UserRepository userRepository) { 21 | this.userRepository = userRepository; 22 | } 23 | 24 | public GuildMemberJoinListener() { 25 | this(null); 26 | } 27 | 28 | @SubscribeEvent 29 | public void execute(GuildMemberJoinEvent event) { 30 | User user = event.getUser(); 31 | 32 | Optional optionalUserEntity = this.userRepository.findById(user.getIdLong()); 33 | 34 | if (optionalUserEntity.isPresent()) { 35 | return; 36 | } 37 | 38 | UserEntityImpl userEntity = new UserEntityImpl.Builder() 39 | .withIdentifier(user.getIdLong()) 40 | .withName(user.getName()) 41 | .setRegistrationDate(Date.from(Instant.now())) 42 | .build(); 43 | 44 | this.userRepository.save(userEntity); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.repository; 2 | 3 | import java.util.Optional; 4 | import org.springframework.data.repository.PagingAndSortingRepository; 5 | import pl.bmstefanski.garbanzo.entity.impl.UserEntityImpl; 6 | 7 | public interface UserRepository extends PagingAndSortingRepository { 8 | 9 | Optional findByName(String name); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/service/GarbanzoService.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.service; 2 | 3 | import javax.security.auth.login.LoginException; 4 | import net.dv8tion.jda.core.JDA; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service 8 | public interface GarbanzoService { 9 | 10 | void startBot() throws LoginException, InterruptedException; 11 | 12 | void shutdownBot(); 13 | 14 | void registerListeners(Object... listeners); 15 | 16 | JDA getJda(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/service/impl/GarbanzoServiceImpl.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.service.impl; 2 | 3 | import javax.security.auth.login.LoginException; 4 | import net.dv8tion.jda.core.AccountType; 5 | import net.dv8tion.jda.core.JDA; 6 | import net.dv8tion.jda.core.JDABuilder; 7 | import net.dv8tion.jda.core.hooks.AnnotatedEventManager; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import pl.bmstefanski.garbanzo.service.GarbanzoService; 10 | 11 | public class GarbanzoServiceImpl implements GarbanzoService { 12 | 13 | private JDA jda; 14 | 15 | @Value("${jda.discord.token}") 16 | private String token; 17 | 18 | @Override 19 | public void startBot() throws LoginException, InterruptedException { 20 | this.jda = new JDABuilder(AccountType.BOT) 21 | .setToken(token) 22 | .setEventManager(new AnnotatedEventManager()) 23 | .buildAsync(); 24 | } 25 | 26 | @Override 27 | public void shutdownBot() { 28 | this.jda.shutdown(); 29 | } 30 | 31 | @Override 32 | public void registerListeners(Object... listeners) { 33 | this.jda.addEventListener(listeners); 34 | } 35 | 36 | @Override 37 | public JDA getJda() { 38 | return this.jda; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/util/Buildable.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.util; 2 | 3 | public interface Buildable { 4 | 5 | T build(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/pl/bmstefanski/garbanzo/util/RestServiceType.java: -------------------------------------------------------------------------------- 1 | package pl.bmstefanski.garbanzo.util; 2 | 3 | public final class RestServiceType { 4 | 5 | public static final String GITHUB_API_URL = "https://api.github.com/users/{username}"; 6 | public static final String GITHUB_ACTIVITY_API_URL = "https://github-contributions-api.now.sh/v1/{username}"; 7 | public static final String ANIME_API_URL = "https://nekos.life/api/v2/"; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | 2 | ${AnsiColor.BRIGHT_BLUE}████████████████████████████████████████████████████████████████████████████████ 3 | ${AnsiColor.BRIGHT_BLUE}████████████████████████████████████████████████████████████████████████████████ 4 | ${AnsiColor.RED}██████████████████${AnsiColor.BRIGHT_BLUE}████████████████${AnsiColor.BLACK}██████████████████████████████${AnsiColor.BRIGHT_BLUE}████████████████ 5 | ${AnsiColor.RED}████████████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████████████████████████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██████████████ 6 | ${AnsiColor.BRIGHT_RED}████${AnsiColor.RED}██████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.MAGENTA}██████████████████████${AnsiColor.WHITE}██████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████████████ 7 | ${AnsiColor.BRIGHT_RED}██████████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.MAGENTA}████████████████${AnsiColor.BLACK}████${AnsiColor.MAGENTA}██████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██${AnsiColor.BLACK}████${AnsiColor.BRIGHT_BLUE}██████ 8 | ${AnsiColor.BRIGHT_RED}██████████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.MAGENTA}██████${AnsiColor.WHITE}██${AnsiColor.BLACK}████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████ 9 | ${AnsiColor.BRIGHT_YELLOW}██████████████████${AnsiColor.BRIGHT_RED}████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.MAGENTA}██████${AnsiColor.WHITE}██${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████ 10 | ${AnsiColor.BRIGHT_YELLOW}██████████████████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_YELLOW}██████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}████████${AnsiColor.WHITE}████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████ 11 | ${AnsiColor.BRIGHT_YELLOW}████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.BLACK}██${AnsiColor.BRIGHT_YELLOW}████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████████████████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████ 12 | ${AnsiColor.BRIGHT_GREEN}██████████████████${AnsiColor.BRIGHT_YELLOW}██${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.BLACK}████████${AnsiColor.WHITE}██${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████████████████████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██ 13 | ${AnsiColor.BRIGHT_GREEN}██████████████████████${AnsiColor.WHITE}████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BRIGHT_YELLOW}██${AnsiColor.WHITE}██████████${AnsiColor.BRIGHT_YELLOW}██${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██ 14 | ${AnsiColor.BRIGHT_GREEN}██████████████████████${AnsiColor.BLACK}████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.BLACK}████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██ 15 | ${AnsiColor.BLUE}██████████████████${AnsiColor.BRIGHT_GREEN}████████${AnsiColor.BLACK}██████${AnsiColor.WHITE}██${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.MAGENTA}████${AnsiColor.WHITE}████████████████${AnsiColor.MAGENTA}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██ 16 | ${AnsiColor.BLUE}██████████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}████████████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████ 17 | ${AnsiColor.BRIGHT_BLUE}██████████████████${AnsiColor.BLUE}████${AnsiColor.BLUE}██████${AnsiColor.BLACK}████${AnsiColor.WHITE}██████${AnsiColor.MAGENTA}██████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████████████████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██████ 18 | ${AnsiColor.BRIGHT_BLUE}██████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██${AnsiColor.BLACK}████${AnsiColor.WHITE}████████████████████${AnsiColor.BLACK}██████████████████${AnsiColor.BRIGHT_BLUE}████████ 19 | ${AnsiColor.BRIGHT_BLUE}████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}██████${AnsiColor.BLACK}████████████████████████████████${AnsiColor.WHITE}██${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████████████ 20 | ${AnsiColor.BRIGHT_BLUE}████████████████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}██${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.BRIGHT_BLUE}████████████${AnsiColor.BLACK}██${AnsiColor.WHITE}████${AnsiColor.BLACK}████${AnsiColor.WHITE}████${AnsiColor.BLACK}██${AnsiColor.BRIGHT_BLUE}████████████ 21 | ${AnsiColor.BRIGHT_BLUE}████████████████████████${AnsiColor.BLACK}██████${AnsiColor.BRIGHT_BLUE}████${AnsiColor.BLACK}██████${AnsiColor.BRIGHT_BLUE}████████████${AnsiColor.BLACK}██████${AnsiColor.BRIGHT_BLUE}████${AnsiColor.BLACK}██████${AnsiColor.BRIGHT_BLUE}████████████ 22 | ████████████████████████████████████████████████████████████████████████████████ 23 | ${AnsiColor.BRIGHT_BLUE}:: Meow :: Running Spring Boot ${spring-boot.version} :: \ö/${AnsiColor.BLACK} -------------------------------------------------------------------------------- /src/main/resources/garbanzo.properties: -------------------------------------------------------------------------------- 1 | prefix=g! 2 | -------------------------------------------------------------------------------- /src/main/resources/locale/messages.properties: -------------------------------------------------------------------------------- 1 | invalid-pattern=Invalid command pattern, try this: {0} 2 | already-registered=Your account has already been registered! 3 | successfully-registered=Successfully registered! 4 | nickname=Nickname 5 | identifier=Identifier 6 | date=Date 7 | wrong-username=Username doesn't match to any account! 8 | activity-title={0} 's activity 9 | year=Year ({0}): 10 | no-activity=Cannot find activity from: {0} 11 | searching-date=Searching date: 12 | contributions=Contributions count 13 | name=Name 14 | bio=Bio 15 | location=Location 16 | registration=Registration Date 17 | followers=Followers 18 | following=Following 19 | repositories=Repositories 20 | gists=Gists 21 | wrong-message-type=Wrong message type: [normal, footer] 22 | invalid-json=Invalid json format! --------------------------------------------------------------------------------