sxcybot

Discord bot for OSRS based channels
git clone git://git.wimdupont.com/sxcybot.git
Log | Files | Refs | README | LICENSE

commit 43189fb4cb6fbb09b98f67540088d1dcfad4ec5a
Author: WimDupont <WimDupont@users.noreply.gitlab.com>
Date:   Sun, 20 Jun 2021 18:31:57 +0200

init

Diffstat:
A.gitignore | 37+++++++++++++++++++++++++++++++++++++
A.mvn/wrapper/MavenWrapperDownloader.java | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A.mvn/wrapper/maven-wrapper.jar | 0
A.mvn/wrapper/maven-wrapper.properties | 2++
ALICENSE | 339+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amvnw | 310+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amvnw.cmd | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apom.xml | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/SxcyBotApplication.java | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/client/ClientErrorHandler.java | 22++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/client/GrandExchangeClient.java | 33+++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/client/HiScoreClient.java | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/config/PersistenceConfig.java | 23+++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/enums/Command.java | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/enums/OsrsCombatStat.java | 17+++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/enums/PvmRole.java | 14++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/exceptions/EntityNotFoundException.java | 8++++++++
Asrc/main/java/com/sxcy/sxcybot/exceptions/InsufficientPrivilegesException.java | 10++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/AdminCommandListener.java | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/CommandListener.java | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/EventWaiterUtil.java | 35+++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/GuildMemberEventListener.java | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/Listener.java | 7+++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/PollReactionListener.java | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/PrivateListener.java | 9+++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/TimeOutRunner.java | 28++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/BanlistListener.java | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/EditBanlistListener.java | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/EditPvmListener.java | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/EditRoleListener.java | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/EditRuleListener.java | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/RoleAssignListener.java | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/banlist/AddBanlistUserListener.java | 46++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/banlist/DeleteBanlistUserListener.java | 40++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/banlist/UpdateBanlistUserListener.java | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/pvmrole/AddPvmListener.java | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/pvmrole/DeletePvmListener.java | 45+++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/pvmrole/UpdatePvmListener.java | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/role/AddRoleListener.java | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/role/DeleteRoleListener.java | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/role/UpdateRoleListener.java | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/rule/AddRuleListener.java | 39+++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/rule/DeleteRuleListener.java | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/admin/rule/UpdateRuleListener.java | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/BB8Listener.java | 25+++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/CombatStatsListener.java | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/CustomPollListener.java | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/EventListener.java | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/ForumListener.java | 31+++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/HelpListener.java | 35+++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/HiscoreBossListener.java | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/KillCountListener.java | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/PingListener.java | 19+++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/PollListener.java | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/PriceListener.java | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/PvmListListener.java | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/RuleListener.java | 45+++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/RulesListener.java | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/listeners/member/StatsListener.java | 31+++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/model/CombatDto.java | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/model/EditListenerDto.java | 25+++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/model/HiScoreBuilder.java | 11+++++++++++
Asrc/main/java/com/sxcy/sxcybot/model/OsrsBossKc.java | 14++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/model/OsrsItem.java | 20++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/model/OsrsStat.java | 14++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/ChannelDetailRepository.java | 9+++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/GuildEventDmerRepository.java | 9+++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/GuildRoleRepository.java | 18++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/PollRepository.java | 13+++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/RuleRepository.java | 14++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/UserRepository.java | 16++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/dao/ChannelDetail.java | 29+++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/dao/Event.java | 20++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/dao/GuildEventDmer.java | 27+++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/dao/GuildRole.java | 27+++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/dao/Poll.java | 37+++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/dao/Rule.java | 30++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/dao/User.java | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/PvmKcSnapshotRepository.java | 14++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/PvmRoleUserRepository.java | 13+++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/dao/PvmKcSnapshot.java | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/dao/PvmRoleUser.java | 40++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/dao/PvmUserKc.java | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/osrs/OsrsHiscoreBossRepository.java | 13+++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/osrs/OsrsHiscoreStatRepository.java | 9+++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/osrs/dao/OsrsHiscoreBoss.java | 27+++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/repository/osrs/dao/OsrsHiscoreStat.java | 25+++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/CleanuperScheduler.java | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/PvMRoleScheduler.java | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/ChannelDetailService.java | 10++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/GuildEventDmerService.java | 11+++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/GuildRoleService.java | 22++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/PollService.java | 17+++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/RuleService.java | 17+++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/UserService.java | 17+++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/impl/ChannelDetailServiceImpl.java | 25+++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/impl/GuildEventDmerServiceImpl.java | 25+++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/impl/GuildGuildRoleServiceImpl.java | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/impl/PollServiceImpl.java | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/impl/RuleServiceImpl.java | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/impl/UserServiceImpl.java | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmKcSnapshotService.java | 17+++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmRoleAssignerService.java | 17+++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmRoleSnapshotComparerService.java | 17+++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmRoleUserService.java | 18++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmKcSnapshotServiceImpl.java | 39+++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmRoleAssignerServiceImpl.java | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmRoleSnapshotComparerServiceImpl.java | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmRoleUserServiceImpl.java | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/osrs/CombatCalculatorService.java | 8++++++++
Asrc/main/java/com/sxcy/sxcybot/services/osrs/OsrsHiscoreBossService.java | 13+++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/osrs/OsrsHiscoreStatService.java | 10++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/osrs/StatMessageSender.java | 15+++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/osrs/impl/CombatCalculatorServiceImpl.java | 31+++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/osrs/impl/OsrsHiscoreBossServiceImpl.java | 32++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/osrs/impl/OsrsHiscoreStatServiceImpl.java | 25+++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/services/osrs/impl/StatMessageSenderImpl.java | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/util/Constants.java | 34++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/util/CustomPollFiller.java | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/util/DiscordMemberFinderUtil.java | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/util/EditListenerUtil.java | 47+++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/util/JdaUtil.java | 37+++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/util/NumberFormatter.java | 15+++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/util/ReleaseNotesUtil.java | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/java/com/sxcy/sxcybot/util/SpringSecurityAuditorAware.java | 20++++++++++++++++++++
Asrc/main/resources/application.properties | 19+++++++++++++++++++
Asrc/main/resources/db/migration/V1_0__db-init.sql | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/resources/db/migration/V1_1__insert_osrs_values.sql | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main/resources/db/migration/V1_2__db-update.sql | 2++
Asrc/main/resources/db/migration/V1_3__update_boss_tob_hard.sql | 6++++++
Asrc/main/resources/images/bb8.jpg | 0
Asrc/main/resources/todo.adoc | 20++++++++++++++++++++
Asrc/test/java/com/sxcy/sxcybot/SxcyBotApplicationTests.java | 15+++++++++++++++
133 files changed, 5767 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,37 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Spring Profile properties ### +/src/main/resources/application-*.properties +/src/test/java/scripts/testdata.sql diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar Binary files differ. diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/LICENSE b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + SxcyBot + Copyright (C) 2021 Wim Dupont + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/mvnw b/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>2.3.5.RELEASE</version> + <relativePath/> <!-- lookup parent from repository --> + </parent> + <groupId>com.sxcy</groupId> + <artifactId>sxcybot</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>sxcybot</name> + <description>Sxcy's OSRS oriented Discord Bot</description> + + <properties> + <java.version>11</java.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-jpa</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <optional>true</optional> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mariadb.jdbc</groupId> + <artifactId>mariadb-java-client</artifactId> + </dependency> + <dependency> + <groupId>com.jagrosh</groupId> + <artifactId>jda-utilities-commons</artifactId> + <version>3.0.5</version> + </dependency> + <dependency> + <groupId>net.dv8tion</groupId> + <artifactId>JDA</artifactId> + <version>4.2.0_249</version> + </dependency> + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <version>4.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.flywaydb</groupId> + <artifactId>flyway-core</artifactId> + </dependency> + <dependency> + <groupId>org.flywaydb</groupId> + <artifactId>flyway-maven-plugin</artifactId> + <version>7.3.1</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.flywaydb</groupId> + <artifactId>flyway-maven-plugin</artifactId> + <version>7.3.1</version> + <configuration> + <url>jdbc:mariadb://localhost:3306/sxcybot</url> + <user>test</user> + <password>test</password> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>11</source> + <target>11</target> + </configuration> + </plugin> + </plugins> + </build> + <repositories> + <repository> + <id>central</id> + <name>bintray</name> + <url>http://jcenter.bintray.com</url> + </repository> + <repository> + <id>dv8tion</id> + <name>m2-dv8tion</name> + <url>https://m2.dv8tion.net/releases</url> + </repository> + </repositories> + <profiles> + <profile> + <id>dev</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <properties> + <spring.profiles.active>dev</spring.profiles.active> + </properties> + </profile> + <profile> + <id>test</id> + <properties> + <spring.profiles.active>test</spring.profiles.active> + </properties> + </profile> + <profile> + <id>prod</id> + <properties> + <spring.profiles.active>prod</spring.profiles.active> + </properties> + </profile> + </profiles> + +</project> diff --git a/src/main/java/com/sxcy/sxcybot/SxcyBotApplication.java b/src/main/java/com/sxcy/sxcybot/SxcyBotApplication.java @@ -0,0 +1,83 @@ +package com.sxcy.sxcybot; + +import com.sxcy.sxcybot.enums.Command; +import com.sxcy.sxcybot.listeners.AdminCommandListener; +import com.sxcy.sxcybot.listeners.CommandListener; +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.GuildMemberEventListener; +import com.sxcy.sxcybot.listeners.PollReactionListener; +import com.sxcy.sxcybot.services.PvMRoleScheduler; +import com.sxcy.sxcybot.util.Constants.Commands; +import com.sxcy.sxcybot.util.ReleaseNotesUtil; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.entities.Activity; +import net.dv8tion.jda.api.requests.GatewayIntent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableScheduling; + +import javax.security.auth.login.LoginException; +import java.util.Arrays; + +@SpringBootApplication +@EnableScheduling +@ComponentScan +public class SxcyBotApplication implements CommandLineRunner { + + @Autowired + private CommandListener commandListener; + @Autowired + private AdminCommandListener adminCommandListener; + @Autowired + private EventWaiterUtil eventWaiterUtil; + @Autowired + private PollReactionListener pollReactionListener; + @Autowired + private GuildMemberEventListener guildMemberEventListener; + @Autowired + private ReleaseNotesUtil releaseNotesUtil; + @Autowired + private PvMRoleScheduler pvMRoleScheduler; + + @SuppressWarnings("unused") + @Value("${discord.bot.token}") + private String token; + + public static void main(String[] args) { + SpringApplication.run(SxcyBotApplication.class, args); + } + + @Override + public void run(String[] args) throws LoginException { + JDA jda = JDABuilder.createLight(token, + GatewayIntent.GUILD_MESSAGES, + GatewayIntent.DIRECT_MESSAGES, + GatewayIntent.GUILD_MESSAGE_REACTIONS, + GatewayIntent.GUILD_MEMBERS, + GatewayIntent.GUILD_BANS + ) + .addEventListeners(commandListener, adminCommandListener, eventWaiterUtil, guildMemberEventListener, pollReactionListener) + .setActivity(Activity.listening(Commands.COMMAND_PREFIX + Command.HELP.name().toLowerCase())) + .build(); + try { + jda.awaitReady(); + pvMRoleScheduler.setJda(jda); + processArgs(jda, args); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void processArgs(JDA jda, String... args){ + if (args.length == 0 || Arrays.stream(args).noneMatch("noNotes"::equalsIgnoreCase)) + releaseNotesUtil.showReleaseNotes(jda); + if (args.length > 0 && Arrays.stream(args).anyMatch("snap"::equalsIgnoreCase)) + pvMRoleScheduler.resolvePvMRoles(); + } + +} diff --git a/src/main/java/com/sxcy/sxcybot/client/ClientErrorHandler.java b/src/main/java/com/sxcy/sxcybot/client/ClientErrorHandler.java @@ -0,0 +1,22 @@ +package com.sxcy.sxcybot.client; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.MessageChannel; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.DefaultResponseErrorHandler; + +import java.io.IOException; + +@RequiredArgsConstructor +public class ClientErrorHandler extends DefaultResponseErrorHandler { + + @NonNull + private final MessageChannel channel; + + @Override + public void handleError(ClientHttpResponse response) throws IOException { + channel.sendMessage(String.format("No results found. (%s)", response.getStatusText())).queue(); + } + +} diff --git a/src/main/java/com/sxcy/sxcybot/client/GrandExchangeClient.java b/src/main/java/com/sxcy/sxcybot/client/GrandExchangeClient.java @@ -0,0 +1,33 @@ +package com.sxcy.sxcybot.client; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.model.OsrsItem; +import com.sxcy.sxcybot.util.NumberFormatter; +import com.fasterxml.jackson.databind.ObjectMapper; +import net.dv8tion.jda.api.entities.MessageChannel; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +@Component +public class GrandExchangeClient { + private static final String URL = "https://api.weirdgloop.org/exchange/history/osrs/latest?name=%s&lang=en"; + + @SuppressWarnings("unchecked") + public String getPrice(String itemName, MessageChannel channel) throws EntityNotFoundException { + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setErrorHandler(new ClientErrorHandler(channel)); + ObjectMapper objectMapper = new ObjectMapper(); + Object result = restTemplate.getForEntity(String.format(URL, itemName), Object.class).getBody(); + if (result != null) { + try { + return NumberFormatter.format(objectMapper.convertValue(((Map<String,Object>) result).values().iterator().next(), OsrsItem.class).getPrice()); + } catch (IllegalArgumentException e) { + throw new EntityNotFoundException(String.format("Item with name %s not found.", itemName)); + } + } else { + throw new EntityNotFoundException(String.format("Item with name %s not found.", itemName)); + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/client/HiScoreClient.java b/src/main/java/com/sxcy/sxcybot/client/HiScoreClient.java @@ -0,0 +1,81 @@ +package com.sxcy.sxcybot.client; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.model.HiScoreBuilder; +import com.sxcy.sxcybot.model.OsrsBossKc; +import com.sxcy.sxcybot.model.OsrsStat; +import com.sxcy.sxcybot.repository.osrs.dao.OsrsHiscoreBoss; +import com.sxcy.sxcybot.repository.osrs.dao.OsrsHiscoreStat; +import com.sxcy.sxcybot.services.osrs.OsrsHiscoreBossService; +import com.sxcy.sxcybot.services.osrs.OsrsHiscoreStatService; +import com.sxcy.sxcybot.util.NumberFormatter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.MessageChannel; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +public class HiScoreClient { + private static final String URL = "https://services.runescape.com/m=hiscore_oldschool/index_lite.ws?player=%s"; + + @NonNull + private final OsrsHiscoreBossService osrsHiscoreBossService; + @NonNull + private final OsrsHiscoreStatService osrsHiscoreStatService; + + public Optional<List<OsrsStat>> getHiScoreStats(String playername, MessageChannel channel) { + List<OsrsHiscoreStat> hiscoreStats = osrsHiscoreStatService.findAll(); + return getHiScores(playername, channel, (osrsStat, hiScoreStatValues, i) -> OsrsStat.builder() + .name(hiscoreStats.stream().filter(f -> f.getOrderValue() == i).findFirst().orElseThrow(() + -> new EntityNotFoundException("OsrsStatName for order not found!")) + .getName()) + .rank(NumberFormatter.format(hiScoreStatValues.get(0))) + .level(hiScoreStatValues.get(1)) + .experience(NumberFormatter.format(hiScoreStatValues.get(2))) + .build(), 0, 22); + } + + public Optional<List<OsrsBossKc>> getHiScoreBossKc(String playername, MessageChannel channel) { + List<OsrsHiscoreBoss> hiscoreBosses = osrsHiscoreBossService.findAll(); + return getHiScores(playername, channel, (osrsKc, hiScoreKcValues, i) -> OsrsBossKc.builder() + .name(hiscoreBosses.stream().filter(f -> f.getOrderValue() == i).findFirst().orElseThrow(() + -> new EntityNotFoundException("OsrsBoss for order not found!")) + .getName()) + .rank(hiScoreKcValues.get(0)) + .kc(hiScoreKcValues.get(1)).build() + , 36, 82); + } + + private <T> Optional<List<T>> getHiScores(String playername, MessageChannel channel, HiScoreBuilder<T> hiScoreBuilder, int fromIndex, int toIndex) { + List<T> hiScoreList = new ArrayList<>(); + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setErrorHandler(new ClientErrorHandler(channel)); + String result = restTemplate.getForObject(String.format(URL, playername), String.class); + if (result != null) { + int i = fromIndex; + List<String> hiScores = Arrays.stream(result.split("\n")).collect(Collectors.toList()); + try { + for (String osrsHiScoresStats : hiScores.subList(fromIndex, toIndex)) { + List<String> hiScoreStatValues = Arrays.stream(osrsHiScoresStats.split(",")).collect(Collectors.toList()); + try { + hiScoreList.add(hiScoreBuilder.accept(osrsHiScoresStats, hiScoreStatValues, i)); + } catch (EntityNotFoundException e) { + e.printStackTrace(); + } + i++; + } + } catch (RuntimeException e) { + return Optional.empty(); + } + } + return Optional.of(hiScoreList); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/config/PersistenceConfig.java b/src/main/java/com/sxcy/sxcybot/config/PersistenceConfig.java @@ -0,0 +1,23 @@ +package com.sxcy.sxcybot.config; + +import com.sxcy.sxcybot.util.SpringSecurityAuditorAware; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.domain.AuditorAware; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@Configuration +@EnableJpaAuditing(auditorAwareRef = "auditorProvider") +@RequiredArgsConstructor +public class PersistenceConfig { + + @NonNull + private final SpringSecurityAuditorAware springSecurityAuditorAware; + + @Bean + public AuditorAware<String> auditorProvider() { + return springSecurityAuditorAware; + } +} diff --git a/src/main/java/com/sxcy/sxcybot/enums/Command.java b/src/main/java/com/sxcy/sxcybot/enums/Command.java @@ -0,0 +1,44 @@ +package com.sxcy.sxcybot.enums; + +public enum Command { + + FORUM("Get forum link - BUMP IT UP!"), + PING("Get time in ms for bot to respond."), + RULE("Show rule by using command with rule number, separated by space."), + RULES("Show list of all the rules."), + // EVENT("Create an event."), + POLL("Start a poll with default options (Accept, Deny, Unsure), separate command by title with space."), + CPOLL("Start a custom poll - choose your own poll options and reaction emoji's, separate command by title with space."), + HELP("Show all commands with description."), + + + //-----OSRS----- + STATS("Check HiScores for all stats, separate command by playername with space."), + CBSTATS("Check HiScores for combat stats, separate command by playername with space."), + KC("Check HiScores for all kc's, separate command by playername with space."), + PRICE("Check the GE for the latest price of an item, separate command by name of item with space."), + PVMLIST("Show list of PvM Role competitors."), + BOSSLIST("Shows list of all hiscore bosses with their PvM Role point multipliers."); + + public enum Admin { + + EDITRULE("Add/Edit/Delete record of rulelist."), + EDITBANLIST("Add/Edit/Delete record of banlist."), + BANLIST("Show list of banned users."), + ROLE("Add/remove a role to/from a member."), + EDITROLE("Add/Delete record of roles."), + EDITPVM("Add/Edit/Delete record of the PvM Role competition"); + + public final String description; + + Admin(String description) { + this.description = description; + } + } + + public final String description; + + Command(String description) { + this.description = description; + } +} diff --git a/src/main/java/com/sxcy/sxcybot/enums/OsrsCombatStat.java b/src/main/java/com/sxcy/sxcybot/enums/OsrsCombatStat.java @@ -0,0 +1,17 @@ +package com.sxcy.sxcybot.enums; + +public enum OsrsCombatStat { + ATTACK("Attack"), + DEFENCE("Defence"), + HITPOINTS("Hitpoints"), + MAGIC("Magic"), + PRAYER("Prayer"), + RANGED("Ranged"), + STRENGTH("Strength"); + + public final String value; + + OsrsCombatStat(String value) { + this.value = value; + } +} diff --git a/src/main/java/com/sxcy/sxcybot/enums/PvmRole.java b/src/main/java/com/sxcy/sxcybot/enums/PvmRole.java @@ -0,0 +1,14 @@ +package com.sxcy.sxcybot.enums; + +public enum PvmRole { + UNUSED(0), + GENERAL(1), + RAIDS(2), + WILDERNESS(3); + + public final int value; + + PvmRole(int value) { + this.value = value; + } +} diff --git a/src/main/java/com/sxcy/sxcybot/exceptions/EntityNotFoundException.java b/src/main/java/com/sxcy/sxcybot/exceptions/EntityNotFoundException.java @@ -0,0 +1,8 @@ +package com.sxcy.sxcybot.exceptions; + +public class EntityNotFoundException extends Exception { + + public EntityNotFoundException(String msg) { + super(msg); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/exceptions/InsufficientPrivilegesException.java b/src/main/java/com/sxcy/sxcybot/exceptions/InsufficientPrivilegesException.java @@ -0,0 +1,10 @@ +package com.sxcy.sxcybot.exceptions; + +import java.util.List; + +public class InsufficientPrivilegesException extends Exception { + + public InsufficientPrivilegesException(List<String> rolelist) { + super(String.format("Only following ranks can execute this command: %s", rolelist)); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/AdminCommandListener.java b/src/main/java/com/sxcy/sxcybot/listeners/AdminCommandListener.java @@ -0,0 +1,119 @@ +package com.sxcy.sxcybot.listeners; + +import com.sxcy.sxcybot.enums.Command; +import com.sxcy.sxcybot.enums.Command.Admin; +import com.sxcy.sxcybot.exceptions.InsufficientPrivilegesException; +import com.sxcy.sxcybot.listeners.admin.BanlistListener; +import com.sxcy.sxcybot.listeners.admin.EditBanlistListener; +import com.sxcy.sxcybot.listeners.admin.EditPvmListener; +import com.sxcy.sxcybot.listeners.admin.EditRoleListener; +import com.sxcy.sxcybot.listeners.admin.EditRuleListener; +import com.sxcy.sxcybot.listeners.admin.RoleAssignListener; +import com.sxcy.sxcybot.repository.guild.dao.GuildRole; +import com.sxcy.sxcybot.services.guild.GuildRoleService; +import com.sxcy.sxcybot.util.Constants.Commands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Component +@RequiredArgsConstructor +public class AdminCommandListener extends ListenerAdapter { + + private static final int GOD = 0; + private static final int ADMIN_ROLE = 1; + private static final int SUB_ADMIN = 5; + private static final int STAFF_ROLE = 10; + + @NonNull + private final EditRuleListener editRuleListener; + @NonNull + private final EditBanlistListener editBanlistListener; + @NonNull + private final RoleAssignListener roleAssignListener; + @NonNull + private final BanlistListener banlistListener; + @NonNull + private final EditRoleListener editRoleListener; + @NonNull + private final EditPvmListener editPvmListener; + @NonNull + private final GuildRoleService guildRoleService; + + @Override + public void onMessageReceived(@Nonnull MessageReceivedEvent event) { + if (event.getChannelType().isGuild()) { + String msg = event.getMessage().getContentRaw().toLowerCase(); + if (msg.startsWith(Commands.COMMAND_PREFIX)) { + Optional<Admin> adminCommand = messageToAdminCommand(msg); + if (adminCommand.isPresent() && event.getMember() != null) { + Stream<Role> roleStream = event.getMember().getRoles().stream(); + try { + switch (adminCommand.get()) { + case EDITRULE: + isPrivileged(roleStream, event, ADMIN_ROLE); + editRuleListener.proces(event); + break; + case EDITBANLIST: + isPrivileged(roleStream, event, ADMIN_ROLE); + editBanlistListener.proces(event); + break; + case ROLE: + isPrivileged(roleStream, event, SUB_ADMIN); + roleAssignListener.proces(event); + break; + case BANLIST: + isPrivileged(roleStream, event, STAFF_ROLE); + banlistListener.proces(event); + break; + case EDITROLE: + isPrivileged(roleStream, event, GOD); + editRoleListener.proces(event); + break; + case EDITPVM: + isPrivileged(roleStream, event, STAFF_ROLE); + editPvmListener.proces(event); + break; + default: + break; + } + } catch (InsufficientPrivilegesException e) { + event.getChannel().sendMessage(e.getMessage()).queue(); + } + } + } + } + } + + private Optional<Command.Admin> messageToAdminCommand(String msg) { + for (Command.Admin adminCommand : Command.Admin.values()) { + if (msg.split(" ")[0].equals(Commands.COMMAND_PREFIX + adminCommand.name().toLowerCase())) { + return Optional.of(adminCommand); + } + } + return Optional.empty(); + } + + private void isPrivileged(Stream<Role> roleStream, MessageReceivedEvent event, int elevation) throws InsufficientPrivilegesException { + List<GuildRole> guildRoles = guildRoleService.findAllByElevationLessThanEqual(elevation); + if (roleStream.noneMatch(hasPrivilage(event, guildRoles))) + throw new InsufficientPrivilegesException(guildRoles.stream().map(GuildRole::getName).collect(Collectors.toList())); + } + + private Predicate<Role> hasPrivilage(MessageReceivedEvent event, List<GuildRole> guildRoles) { + return f -> f.hasPermission(Permission.ADMINISTRATOR) + || (event.getMember() != null && event.getMember().isOwner()) + || guildRoles.stream().map(GuildRole::getName).anyMatch(e -> e.equalsIgnoreCase(f.getName())); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/CommandListener.java b/src/main/java/com/sxcy/sxcybot/listeners/CommandListener.java @@ -0,0 +1,132 @@ +package com.sxcy.sxcybot.listeners; + +import com.sxcy.sxcybot.enums.Command; +import com.sxcy.sxcybot.listeners.member.BB8Listener; +import com.sxcy.sxcybot.listeners.member.CombatStatsListener; +import com.sxcy.sxcybot.listeners.member.CustomPollListener; +import com.sxcy.sxcybot.listeners.member.EventListener; +import com.sxcy.sxcybot.listeners.member.ForumListener; +import com.sxcy.sxcybot.listeners.member.HelpListener; +import com.sxcy.sxcybot.listeners.member.HiscoreBossListener; +import com.sxcy.sxcybot.listeners.member.KillCountListener; +import com.sxcy.sxcybot.listeners.member.PingListener; +import com.sxcy.sxcybot.listeners.member.PollListener; +import com.sxcy.sxcybot.listeners.member.PriceListener; +import com.sxcy.sxcybot.listeners.member.PvmListListener; +import com.sxcy.sxcybot.listeners.member.RuleListener; +import com.sxcy.sxcybot.listeners.member.RulesListener; +import com.sxcy.sxcybot.listeners.member.StatsListener; +import com.sxcy.sxcybot.util.Constants.Commands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.Optional; + +@Component +@RequiredArgsConstructor +public class CommandListener extends ListenerAdapter { + + @NonNull + private final BB8Listener bb8Listener; + @NonNull + private final RuleListener ruleListener; + @NonNull + private final RulesListener rulesListener; + @NonNull + private final PingListener pingListener; + @NonNull + private final EventListener eventListener; + @NonNull + private final ForumListener forumListener; + @NonNull + private final PollListener pollListener; + @NonNull + private final CustomPollListener customPollListener; + @NonNull + private final HelpListener helpListener; + @Nonnull + private final StatsListener statsListener; + @NonNull + private final CombatStatsListener combatStatsListener; + @NonNull + private final PriceListener priceListener; + @NonNull + private final KillCountListener killCountListener; + @NonNull + private final PvmListListener pvmListListener; + @NonNull + private final HiscoreBossListener hiscoreBossListener; + + @Override + public void onMessageReceived(@Nonnull MessageReceivedEvent event) { + if (event.getChannelType().isGuild()) { + String msg = event.getMessage().getContentRaw().toLowerCase(); + if (msg.startsWith(Commands.COMMAND_PREFIX)) { + Optional<Command> command = messageToCommand(msg); + if (command.isPresent()) { + switch (command.get()) { + case RULE: + ruleListener.proces(event); + break; + case RULES: + rulesListener.proces(event); + break; + case PING: + pingListener.proces(event); + break; +// case EVENT: +// eventListener.proces(event); +// break; + case CBSTATS: + combatStatsListener.proces(event); + break; + case STATS: + statsListener.proces(event); + break; + case PRICE: + priceListener.proces(event); + break; + case FORUM: + forumListener.proces(event); + break; + case POLL: + pollListener.proces(event); + break; + case CPOLL: + customPollListener.proces(event); + break; + case KC: + killCountListener.proces(event); + break; + case PVMLIST: + pvmListListener.proces(event); + break; + case BOSSLIST: + hiscoreBossListener.proces(event); + break; + case HELP: + helpListener.proces(event); + break; + default: + break; + } + } else if (Commands.BB8.equals(msg)) { + bb8Listener.proces(event); + } + } + } + } + + private Optional<Command> messageToCommand(String msg) { + for (Command command : Command.values()) { + if (msg.split(" ")[0].equals(Commands.COMMAND_PREFIX + command.name().toLowerCase())) { + return Optional.of(command); + } + } + return Optional.empty(); + } +} +\ No newline at end of file diff --git a/src/main/java/com/sxcy/sxcybot/listeners/EventWaiterUtil.java b/src/main/java/com/sxcy/sxcybot/listeners/EventWaiterUtil.java @@ -0,0 +1,35 @@ +package com.sxcy.sxcybot.listeners; + +import com.jagrosh.jdautilities.commons.waiter.EventWaiter; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Predicate; + +@Component +@RequiredArgsConstructor +public class EventWaiterUtil extends EventWaiter { + + public void waitForPrivateChannelEvent(Consumer<PrivateMessageReceivedEvent> action, PrivateMessageReceivedEvent event, PrivateChannel privateChannel) { + waitForEvent(PrivateMessageReceivedEvent.class, verifyAuthor(event), action, 1, TimeUnit.MINUTES, new TimeOutRunner(privateChannel)); + } + + public void waitForPrivateChannelEvent(Consumer<PrivateMessageReceivedEvent> action, MessageReceivedEvent event, PrivateChannel privateChannel) { + waitForEvent(PrivateMessageReceivedEvent.class, verifyAuthor(event), action, 1, TimeUnit.MINUTES, new TimeOutRunner(privateChannel)); + } + + private Predicate<PrivateMessageReceivedEvent> verifyAuthor(MessageReceivedEvent event) { + return messageReceivedEvent -> messageReceivedEvent.getAuthor().getId().equals(event.getAuthor().getId()); + } + + private Predicate<PrivateMessageReceivedEvent> verifyAuthor(PrivateMessageReceivedEvent event) { + return privateMessageReceivedEvent -> privateMessageReceivedEvent.getAuthor().getId().equals(event.getAuthor().getId()); + } + + +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/GuildMemberEventListener.java b/src/main/java/com/sxcy/sxcybot/listeners/GuildMemberEventListener.java @@ -0,0 +1,42 @@ +package com.sxcy.sxcybot.listeners; + +import com.sxcy.sxcybot.services.guild.GuildEventDmerService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent; +import net.dv8tion.jda.api.exceptions.RateLimitedException; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.Optional; + +@Component +@RequiredArgsConstructor +public class GuildMemberEventListener extends ListenerAdapter { + + @NonNull + private final GuildEventDmerService guildEventDmerService; + + @Override + public void onGuildMemberRemove(@Nonnull GuildMemberRemoveEvent event) { + guildEventDmerService.findAll().forEach(guildEventDmer -> + event.getGuild().loadMembers().onSuccess(memberList -> { + if (!memberList.isEmpty()) { + Optional<Member> member = memberList.stream().filter(f -> guildEventDmer.getName().equalsIgnoreCase(f.getUser().getName())).findFirst(); + if (member.isPresent()) { + try { + PrivateChannel privateChannel = member.get().getUser().openPrivateChannel().complete(true); + privateChannel.sendMessage(String.format("**%s** has been removed from channel _%s_", event.getUser().getName(), event.getGuild().getName())).queue(); + } catch (RateLimitedException e) { + e.printStackTrace(); + } + } + } + }) + ); + } +} + diff --git a/src/main/java/com/sxcy/sxcybot/listeners/Listener.java b/src/main/java/com/sxcy/sxcybot/listeners/Listener.java @@ -0,0 +1,7 @@ +package com.sxcy.sxcybot.listeners; + +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; + +public interface Listener { + void proces(MessageReceivedEvent event); +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/PollReactionListener.java b/src/main/java/com/sxcy/sxcybot/listeners/PollReactionListener.java @@ -0,0 +1,111 @@ +package com.sxcy.sxcybot.listeners; + +import com.sxcy.sxcybot.services.guild.PollService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.MessageEmbed.Field; +import net.dv8tion.jda.api.events.message.react.GenericMessageReactionEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class PollReactionListener extends ListenerAdapter { + + @NonNull + private final PollService pollService; + + @Override + public void onMessageReactionAdd(@Nonnull MessageReactionAddEvent event) { + if (isPoll(event)) { + event.getChannel().retrieveMessageById(event.getMessageId()).queue(message -> { + if (message.getEmbeds().size() == 1) { + MessageEmbed messageEmbed = message.getEmbeds().get(0); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setTitle(messageEmbed.getTitle()); + embedBuilder.setColor(messageEmbed.getColor()); + embedBuilder.setFooter(String.format("Last voted on %s", LocalDate.now()), event.getGuild().getIconUrl()); + String username = JdaUtil.getName(event); + for (MessageEmbed.Field field : messageEmbed.getFields()) { + List<String> nameSplit = field.getValue() != null ? new ArrayList<>(Arrays.asList(field.getValue().split(System.lineSeparator()))) : null; + if (field.getValue() != null && username != null && nameSplit.remove(username)) { + String value = String.join(System.lineSeparator(), nameSplit); + embedBuilder.addField(field); + embedBuilder.getFields() + .set(messageEmbed.getFields().indexOf(field), + new Field(getFieldNameWithCount(field, value), value, field.isInline())); + } else { + if (field.getName() != null && field.getName().contains(event.getReactionEmote().getEmoji())) { + String value = !field.getValue().contains("‎") + ? field.getValue() + System.lineSeparator() + username : username; + embedBuilder.addField(getFieldNameWithCount(field, value), value, field.isInline()); + } else { + embedBuilder.addField(field); + } + } + } + message.editMessage(embedBuilder.build()).queue(); + message.removeReaction(event.getReaction().getReactionEmote().getEmoji(), event.getUser()).queue(); + } + }); + } + } + + public String getFieldNameWithCount(Field field, String updatedValue) { + return field.getName().replaceAll("\\(+\\d+\\)+", String.format("(%s)", getCount(updatedValue))); + } + + private long getCount(String fieldValue) { + if (fieldValue.isEmpty()) { + return 0; + } + return Arrays.stream(fieldValue.split(System.lineSeparator())).count(); + + } +// @Override +// public void onMessageReactionRemove(@Nonnull MessageReactionRemoveEvent event) { +// //event.user is null here! +// if (pollService.findByMessageId(event.getMessageId()).isPresent()) { +// event.getJDA().retrieveUserById(event.getUserId()).queue(user -> { +// if (!user.isBot()) { +// event.getChannel().retrieveMessageById(event.getMessageId()).queue(message -> { +// if (message.getEmbeds().size() == 1) { +// MessageEmbed messageEmbed = message.getEmbeds().get(0); +// EmbedBuilder embedBuilder = new EmbedBuilder(); +// embedBuilder.setTitle(messageEmbed.getTitle()); +// embedBuilder.setColor(messageEmbed.getColor()); +// for (MessageEmbed.Field field : messageEmbed.getFields()) { +// embedBuilder.addField(field); +// if (field.getName() != null && field.getName().contains(event.getReactionEmote().getEmoji())) { +// if (field.getValue() != null) { +// embedBuilder.getFields() +// .set(messageEmbed.getFields().indexOf(field), +// new Field(field.getName(), field.getValue().replace(user.getName(), ""), field.isInline())); +// message.editMessage(embedBuilder.build()).queue(); +// } +// } +// } +// message.editMessage(embedBuilder.build()).queue(); +// } +// }); +// } +// }); +// } +// } + + private boolean isPoll(GenericMessageReactionEvent event) { + return event.getUser() != null + && !event.getUser().isBot() + && pollService.findByMessageId(event.getMessageId()).isPresent(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/PrivateListener.java b/src/main/java/com/sxcy/sxcybot/listeners/PrivateListener.java @@ -0,0 +1,9 @@ +package com.sxcy.sxcybot.listeners; + +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; + +public interface PrivateListener { + + void proces(PrivateMessageReceivedEvent privateEvent, MessageReceivedEvent event); +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/TimeOutRunner.java b/src/main/java/com/sxcy/sxcybot/listeners/TimeOutRunner.java @@ -0,0 +1,28 @@ +package com.sxcy.sxcybot.listeners; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.MessageChannel; + +@RequiredArgsConstructor +public class TimeOutRunner implements Runnable { + + @NonNull + private final MessageChannel messageChannel; + + /** + * When an object implementing interface {@code Runnable} is used + * to create a thread, starting the thread causes the object's + * {@code run} method to be called in that separately executing + * thread. + * <p> + * The general contract of the method {@code run} is that it may + * take any action whatsoever. + * + * @see Thread#run() + */ + @Override + public void run() { + messageChannel.sendMessage("Timed out... Please try again later.").queue(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/BanlistListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/BanlistListener.java @@ -0,0 +1,54 @@ +package com.sxcy.sxcybot.listeners.admin; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.repository.guild.dao.User; +import com.sxcy.sxcybot.services.guild.UserService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.exceptions.RateLimitedException; +import org.springframework.stereotype.Component; + +import java.awt.Color; +import java.util.List; + + +@Component +@RequiredArgsConstructor +public class BanlistListener implements Listener { + + @NonNull + private final UserService userService; + + @Override + public void proces(MessageReceivedEvent event) { + if (event.getMember() != null) { + try { + PrivateChannel privateChannel = event.getMember().getUser().openPrivateChannel().complete(true); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.red); + embedBuilder.setTitle("List of banned users:"); + List<User> bannedList = userService.findAllBanned(); + int i = 1; + for (User user : bannedList) { + embedBuilder.addField(user.getName(), + String.format("%s", user.getDescription()) + System.lineSeparator() + + String.format("||_By: %s - %s | Last edit: %s - %s_||", + user.getCreatedBy(), user.getCreatedDate(), user.getLastModifiedBy(), user.getLastModifiedDate()), + false); + + if (JdaUtil.requiresBuild(embedBuilder, bannedList.size(), i)) { + privateChannel.sendMessage(embedBuilder.build()).queue(); + embedBuilder.clear(); + } + i++; + } + } catch (RateLimitedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/EditBanlistListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/EditBanlistListener.java @@ -0,0 +1,50 @@ +package com.sxcy.sxcybot.listeners.admin; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.listeners.admin.banlist.AddBanlistUserListener; +import com.sxcy.sxcybot.listeners.admin.banlist.DeleteBanlistUserListener; +import com.sxcy.sxcybot.listeners.admin.banlist.UpdateBanlistUserListener; +import com.sxcy.sxcybot.model.EditListenerDto; +import com.sxcy.sxcybot.util.EditListenerUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.exceptions.RateLimitedException; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class EditBanlistListener implements Listener { + + @NonNull + private final AddBanlistUserListener addBanlistUserListener; + @NonNull + private final UpdateBanlistUserListener updateBanlistListener; + @NonNull + private final DeleteBanlistUserListener deleteBanlistListener; + @NonNull + private final EditListenerUtil editListenerUtil; + + @Override + public void proces(MessageReceivedEvent event) { + if (event.getMember() != null) { + try { + PrivateChannel privateChannel = event.getMember().getUser().openPrivateChannel().complete(true); + if (event.getMember() != null) { + EditListenerDto editListenerDto = EditListenerDto.builder() + .addListener(addBanlistUserListener) + .updateListener(updateBanlistListener) + .deleteListener(deleteBanlistListener) + .event(event) + .privateChannel(privateChannel) + .entityName("user to banlist") + .build(); + editListenerUtil.procesEditEvent(editListenerDto); + } + } catch (RateLimitedException e) { + e.printStackTrace(); + } + } + } +} +\ No newline at end of file diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/EditPvmListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/EditPvmListener.java @@ -0,0 +1,50 @@ +package com.sxcy.sxcybot.listeners.admin; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.listeners.admin.pvmrole.AddPvmListener; +import com.sxcy.sxcybot.listeners.admin.pvmrole.DeletePvmListener; +import com.sxcy.sxcybot.listeners.admin.pvmrole.UpdatePvmListener; +import com.sxcy.sxcybot.model.EditListenerDto; +import com.sxcy.sxcybot.util.EditListenerUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.exceptions.RateLimitedException; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class EditPvmListener implements Listener { + + @NonNull + private final EditListenerUtil editListenerUtil; + @NonNull + private final AddPvmListener addPvmListener; + @NonNull + private final UpdatePvmListener updatePvmListener; + @NonNull + private final DeletePvmListener deletePvmListener; + + @Override + public void proces(MessageReceivedEvent event) { + if (event.getMember() != null) { + try { + PrivateChannel privateChannel = event.getMember().getUser().openPrivateChannel().complete(true); + if (event.getMember() != null) { + EditListenerDto editListenerDto = EditListenerDto.builder() + .addListener(addPvmListener) + .updateListener(updatePvmListener) + .deleteListener(deletePvmListener) + .event(event) + .privateChannel(privateChannel) + .entityName("PvM competitor") + .build(); + editListenerUtil.procesEditEvent(editListenerDto); + } + } catch (RateLimitedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/EditRoleListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/EditRoleListener.java @@ -0,0 +1,52 @@ +package com.sxcy.sxcybot.listeners.admin; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.listeners.admin.role.AddRoleListener; +import com.sxcy.sxcybot.listeners.admin.role.DeleteRoleListener; +import com.sxcy.sxcybot.listeners.admin.role.UpdateRoleListener; +import com.sxcy.sxcybot.model.EditListenerDto; +import com.sxcy.sxcybot.util.EditListenerUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.exceptions.RateLimitedException; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class EditRoleListener implements Listener { + + @NonNull + private final AddRoleListener addRoleListener; + + @NonNull + private final UpdateRoleListener updateRoleListener; + + @NonNull + private final DeleteRoleListener deleteRoleListener; + + @NonNull + private final EditListenerUtil editListenerUtil; + + @Override + public void proces(MessageReceivedEvent event) { + if (event.getMember() != null) { + try { + PrivateChannel privateChannel = event.getMember().getUser().openPrivateChannel().complete(true); + if (event.getMember() != null) { + EditListenerDto editListenerDto = EditListenerDto.builder() + .addListener(addRoleListener) + .deleteListener(deleteRoleListener) + .event(event) + .privateChannel(privateChannel) + .entityName("role") + .build(); + editListenerUtil.procesEditEvent(editListenerDto); + } + } catch (RateLimitedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/EditRuleListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/EditRuleListener.java @@ -0,0 +1,50 @@ +package com.sxcy.sxcybot.listeners.admin; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.listeners.admin.rule.AddRuleListener; +import com.sxcy.sxcybot.listeners.admin.rule.DeleteRuleListener; +import com.sxcy.sxcybot.listeners.admin.rule.UpdateRuleListener; +import com.sxcy.sxcybot.model.EditListenerDto; +import com.sxcy.sxcybot.util.EditListenerUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.exceptions.RateLimitedException; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class EditRuleListener implements Listener { + + @NonNull + private final AddRuleListener addRuleListener; + @NonNull + private final UpdateRuleListener updateRuleListener; + @NonNull + private final DeleteRuleListener deleteRuleListener; + @NonNull + private final EditListenerUtil editListenerUtil; + + @Override + public void proces(MessageReceivedEvent event) { + if (event.getMember() != null) { + try { + PrivateChannel privateChannel = event.getMember().getUser().openPrivateChannel().complete(true); + if (event.getMember() != null) { + EditListenerDto editListenerDto = EditListenerDto.builder() + .addListener(addRuleListener) + .updateListener(updateRuleListener) + .deleteListener(deleteRuleListener) + .event(event) + .privateChannel(privateChannel) + .entityName("rule") + .build(); + editListenerUtil.procesEditEvent(editListenerDto); + } + } catch (RateLimitedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/RoleAssignListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/RoleAssignListener.java @@ -0,0 +1,94 @@ +package com.sxcy.sxcybot.listeners.admin; + +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.repository.guild.dao.GuildRole; +import com.sxcy.sxcybot.services.guild.GuildRoleService; +import com.sxcy.sxcybot.util.DiscordMemberFinderUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.exceptions.RateLimitedException; +import org.springframework.stereotype.Component; + +import java.awt.Color; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.sxcy.sxcybot.util.Constants.ADDED_ROLE_ELEVATION; + +@Component +@RequiredArgsConstructor +public class RoleAssignListener implements Listener { + + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @NonNull + private final GuildRoleService guildRoleService; + + @NonNull + private final DiscordMemberFinderUtil discordMemberFinderUtil; + + @Override + public void proces(MessageReceivedEvent event) { + if (event.getMember() != null) { + try { + PrivateChannel privateChannel = event.getMember().getUser().openPrivateChannel().complete(true); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.RED); + embedBuilder.setTitle("Role assigner"); + discordMemberFinderUtil.onMemberFoundVerification(event, embedBuilder, privateChannel, (member) -> { + EmbedBuilder roleListEmberBuilder = new EmbedBuilder(); + roleListEmberBuilder.setColor(Color.RED); + roleListEmberBuilder.setTitle("Type the number of the role to add, if the member already has this role it will get removed instead."); + List<GuildRole> rolesToAdd = guildRoleService.findAllByElevationGreaterThanEqual(ADDED_ROLE_ELEVATION) + .stream().sorted(Comparator.nullsLast(Comparator.comparing(GuildRole::getOrderValue))).collect(Collectors.toList()); + for (GuildRole guildRole : rolesToAdd) { + roleListEmberBuilder.addField(String.valueOf(guildRole.getOrderValue()), String.valueOf(guildRole.getName()), true); + } + privateChannel.sendMessage(roleListEmberBuilder.build()).queue(); + eventWaiterUtil.waitForPrivateChannelEvent(roleReceiver -> { + String roleMessage = roleReceiver.getMessage().getContentRaw(); + try { + int roleNumber = Integer.parseInt(roleMessage); + Optional<GuildRole> discordRole = rolesToAdd.stream().filter(f -> roleNumber == f.getOrderValue()).findFirst(); + if (discordRole.isPresent()) { + Optional<Role> role = event.getGuild().getRoles().stream().filter(f -> discordRole.get().getName().equalsIgnoreCase(f.getName())).findFirst(); + if (role.isPresent()) { + String action; + if (member.getRoles().contains(role.get())) { + event.getGuild().removeRoleFromMember(member, role.get()).queue(); + action = "removed"; + } else { + event.getGuild().addRoleToMember(member, role.get()).queue(); + action = "assigned"; + } + embedBuilder.clearFields(); + embedBuilder.addField(String.format("Role has been succesfully %s.", action), "", false); + privateChannel.sendMessage(embedBuilder.build()).queue(); + event.getChannel().sendMessage(String.format("Role \"%s\" has been %s to %s by %s", + role.get().getName(), action, member.getUser(), event.getMember().getUser().getName())).queue(); + } else { + privateChannel.sendMessage("No such role is available in the channel, please contact your channel owner.").queue(); + } + } else { + privateChannel.sendMessage(String.format("%s is not in the suggested list, please try again later.", roleMessage)).queue(); + } + } catch (NumberFormatException e) { + privateChannel.sendMessage(String.format("%s is not a valid number, please try again later.", roleMessage)).queue(); + } + }, event, privateChannel); + + }); + } catch (RateLimitedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/banlist/AddBanlistUserListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/banlist/AddBanlistUserListener.java @@ -0,0 +1,46 @@ +package com.sxcy.sxcybot.listeners.admin.banlist; + +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.dao.User; +import com.sxcy.sxcybot.services.guild.UserService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class AddBanlistUserListener implements PrivateListener { + + @NonNull + private final EventWaiterUtil eventWaiterUtil; + @NonNull + private final UserService userService; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateMessageReceivedEvent.getChannel(); + privateChannel.sendMessage("Name of the user you want to ban?").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(nameReceiver -> { + privateChannel.sendMessage("Description?").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(descriptionReceiver -> { + User userToBan = User.builder() + .name(nameReceiver.getMessage().getContentRaw()) + .description(descriptionReceiver.getMessage().getContentRaw()) + .banned(true) + .createdBy(JdaUtil.getName(event)) + .lastModifiedBy(JdaUtil.getName(event)) + .build(); + User bannedUser = userService.save(userToBan); + privateChannel.sendMessage(String.format("User %s has been succesfully banned.", bannedUser.getName())).queue(); + event.getChannel().sendMessage(String.format("User %s has been banned by %s. (%s)", + bannedUser.getName(), JdaUtil.getUser(event), bannedUser.getDescription() + )).queue(); + }, privateMessageReceivedEvent, privateChannel); + }, privateMessageReceivedEvent, privateChannel); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/banlist/DeleteBanlistUserListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/banlist/DeleteBanlistUserListener.java @@ -0,0 +1,40 @@ +package com.sxcy.sxcybot.listeners.admin.banlist; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.dao.User; +import com.sxcy.sxcybot.services.guild.UserService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class DeleteBanlistUserListener implements PrivateListener { + + @NonNull + private final UserService userService; + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @Override + public void proces(PrivateMessageReceivedEvent privateEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateEvent.getChannel(); + privateChannel.sendMessage("Name of the user you want to delete?").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(nameReceiver -> { + try { + User userToDelete = userService.findByName(nameReceiver.getMessage().getContentRaw()); + userService.delete(userToDelete); + privateChannel.sendMessage(String.format("%s succesfully deleted.", userToDelete)).queue(); + event.getChannel().sendMessage(String.format("User %s has been deleted from the banlist by %s", userToDelete, JdaUtil.getUser(event))).queue(); + } catch (EntityNotFoundException e) { + privateChannel.sendMessage(e.getMessage()).queue(); + } + }, event, privateChannel); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/banlist/UpdateBanlistUserListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/banlist/UpdateBanlistUserListener.java @@ -0,0 +1,60 @@ +package com.sxcy.sxcybot.listeners.admin.banlist; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.dao.User; +import com.sxcy.sxcybot.services.guild.UserService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.awt.Color; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +public class UpdateBanlistUserListener implements PrivateListener { + + @NonNull + private final EventWaiterUtil eventWaiterUtil; + @NonNull + private final UserService userService; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateMessageReceivedEvent.getChannel(); + privateChannel.sendMessage("Name of the user you want to update (\"showlist\" to show all names in banlist).").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(nameReceiver -> { + if (nameReceiver.getMessage().getContentRaw().equalsIgnoreCase("showlist")) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.red); + embedBuilder.setTitle("Banned users:"); + userService.findAllBanned().stream().map(User::getName).collect(Collectors.toList()).forEach(f -> + embedBuilder.addField(f, "", false)); + privateChannel.sendMessage(embedBuilder.build()).queue(); + this.proces(privateMessageReceivedEvent, event); + return; + } + try { + User userToUpdate = userService.findByName(nameReceiver.getMessage().getContentRaw()); + privateChannel.sendMessage(String.format("Type the new description for the ban of %s.", nameReceiver.getMessage().getContentRaw())).queue(); + eventWaiterUtil.waitForPrivateChannelEvent(descriptionReceiver -> { + User saved = userService.save(userToUpdate.toBuilder() + .description(descriptionReceiver.getMessage().getContentRaw()) + .lastModifiedBy(JdaUtil.getName(event)) + .build()); + privateChannel.sendMessage(saved + " edited.").queue(); + event.getChannel().sendMessage(String.format("Banned user %s has been edited by %s.", saved.getName(), JdaUtil.getUser(event))).queue(); + }, privateMessageReceivedEvent, privateChannel); + } catch (EntityNotFoundException e) { + privateChannel.sendMessage(e.getMessage()).queue(); + } + }, event, privateChannel); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/pvmrole/AddPvmListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/pvmrole/AddPvmListener.java @@ -0,0 +1,71 @@ +package com.sxcy.sxcybot.listeners.admin.pvmrole; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleSnapshotComparerService; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleUserService; +import com.sxcy.sxcybot.util.DiscordMemberFinderUtil; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.stereotype.Component; + +import java.awt.Color; + +@Component +@RequiredArgsConstructor +public class AddPvmListener implements PrivateListener { + + @NonNull + private final EventWaiterUtil eventWaiterUtil; + @NonNull + private final DiscordMemberFinderUtil discordMemberFinderUtil; + @NonNull + private final PvmRoleUserService pvmRoleUserService; + @NonNull + private final PvmRoleSnapshotComparerService pvmRoleSnapshotComparerService; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateMessageReceivedEvent.getChannel(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.RED); + embedBuilder.setTitle("Add member for PvM competition"); + discordMemberFinderUtil.onMemberFoundVerification(event, embedBuilder, privateChannel, (member) -> { + embedBuilder.addField("Type the RSN (RuneScape name) of the member.", "", true); + privateChannel.sendMessage(embedBuilder.build()).queue(); + embedBuilder.clearFields(); + eventWaiterUtil.waitForPrivateChannelEvent((rsnReceiver) -> { + String creator = JdaUtil.getName(event); + try { + PvmRoleUser pvmRoleUser = pvmRoleUserService.save(PvmRoleUser.builder() + .rsn(rsnReceiver.getMessage().getContentRaw()) + .discordName(member.getEffectiveName()) + .createdBy(creator) + .lastModifiedBy(creator) + .build() + ); + event.getChannel().sendMessage(String.format("%s (RSN: %s) has been added to the PvM competition by %s!", + member, pvmRoleUser.getRsn(), creator)).queue(); + privateChannel.sendMessage(String.format("%s (RSN: %s) has been succesfully added!", + member, pvmRoleUser.getRsn())).queue(); + try { + pvmRoleSnapshotComparerService.saveSnapshot(event.getChannel(), pvmRoleUser, true); + } catch (EntityNotFoundException e) { + event.getChannel().sendMessage(e.getMessage()).queue(); + } + } catch (DataIntegrityViolationException e) { + if (e.getMessage() != null) + privateChannel.sendMessage(e.getMessage()).queue(); + } + }, event, privateChannel); + }); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/pvmrole/DeletePvmListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/pvmrole/DeletePvmListener.java @@ -0,0 +1,45 @@ +package com.sxcy.sxcybot.listeners.admin.pvmrole; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmKcSnapshotService; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleUserService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class DeletePvmListener implements PrivateListener { + + @NonNull + private final PvmRoleUserService pvmRoleUserService; + @NonNull + private final PvmKcSnapshotService pvmKcSnapshotService; + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateMessageReceivedEvent.getChannel(); + privateChannel.sendMessage("Type the discord name of the user you want to delete.").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(discordNameReceiver -> { + String discordName = discordNameReceiver.getMessage().getContentRaw(); + try { + PvmRoleUser pvmRoleUser = pvmRoleUserService.findByDiscordName(discordName); + pvmKcSnapshotService.deleteAll(pvmKcSnapshotService.findAllByPvmRoleUser(pvmRoleUser)); + pvmRoleUserService.delete(pvmRoleUser); + privateChannel.sendMessage(String.format("%s has been succesfully deleted.", pvmRoleUser)).queue(); + event.getChannel().sendMessage(String.format("PvM competitor %s has been deleted by %s", discordName, JdaUtil.getUser(event))).queue(); + } catch (EntityNotFoundException e) { + privateChannel.sendMessage(e.getMessage()).queue(); + } + }, privateMessageReceivedEvent, privateChannel); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/pvmrole/UpdatePvmListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/pvmrole/UpdatePvmListener.java @@ -0,0 +1,81 @@ +package com.sxcy.sxcybot.listeners.admin.pvmrole; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleUserService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.stereotype.Component; + +import java.awt.Color; + +import static com.sxcy.sxcybot.enums.Command.PVMLIST; +import static com.sxcy.sxcybot.util.Constants.Commands.COMMAND_PREFIX; + +@Component +@RequiredArgsConstructor +public class UpdatePvmListener implements PrivateListener { + + @NonNull + private final PvmRoleUserService pvmRoleUserService; + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateMessageReceivedEvent.getChannel(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.RED); + embedBuilder.setTitle("Update user for PvM competition."); + embedBuilder.addField("Type the discord name of the user you want to update.", "", false); + privateChannel.sendMessage(embedBuilder.build()).queue(); + embedBuilder.clearFields(); + eventWaiterUtil.waitForPrivateChannelEvent(discordNameReceiver -> { + String discordName = discordNameReceiver.getMessage().getContentRaw(); + try { + PvmRoleUser oldPvmRoleUser = pvmRoleUserService.findByDiscordName(discordName); + embedBuilder.addField("Confirm by typing ``yes or y``.", + String.format("Is " + System.lineSeparator() + "Discord: %s | RSN: %s " + System.lineSeparator() + "the correct member?" + , oldPvmRoleUser.getDiscordName(), oldPvmRoleUser.getRsn()), false); + privateChannel.sendMessage(embedBuilder.build()).queue(); + embedBuilder.clearFields(); + eventWaiterUtil.waitForPrivateChannelEvent(memberVerifyReceiver -> { + String verifyMessage = memberVerifyReceiver.getMessage().getContentRaw(); + if ("y".equalsIgnoreCase(verifyMessage) || "yes".equalsIgnoreCase(verifyMessage)) { + embedBuilder.addField("Type the new RSN for the update.", "", false); + privateChannel.sendMessage(embedBuilder.build()).queue(); + embedBuilder.clearFields(); + eventWaiterUtil.waitForPrivateChannelEvent(newRsnReceiver -> { + String newRsn = newRsnReceiver.getMessage().getContentRaw(); + PvmRoleUser pvmRoleUser = oldPvmRoleUser.toBuilder() + .rsn(newRsn) + .lastModifiedBy(JdaUtil.getName(event)) + .build(); + try { + pvmRoleUser = pvmRoleUserService.save(pvmRoleUser); + newRsnReceiver.getChannel().sendMessage(pvmRoleUser + " edited").queue(); + event.getChannel().sendMessage(String.format("RSN for PvM competitor %s has been changed to %s by %s", + discordName, newRsn, JdaUtil.getUser(event))).queue(); + } catch (DataIntegrityViolationException e) { + if (e.getMessage() != null) + privateChannel.sendMessage(e.getMessage()).queue(); + } + }, privateMessageReceivedEvent, privateChannel); + } else { + privateChannel.sendMessage(String.format("You can check all competitors with the \"%s\" command.", COMMAND_PREFIX + PVMLIST.name().toLowerCase())).queue(); + } + }, privateMessageReceivedEvent, privateChannel); + } catch (EntityNotFoundException e) { + privateChannel.sendMessage(e.getMessage()).queue(); + } + }, privateMessageReceivedEvent, privateChannel); + } +} +\ No newline at end of file diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/role/AddRoleListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/role/AddRoleListener.java @@ -0,0 +1,55 @@ +package com.sxcy.sxcybot.listeners.admin.role; + +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.dao.GuildRole; +import com.sxcy.sxcybot.services.guild.GuildRoleService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.util.Comparator; +import java.util.Optional; + +import static com.sxcy.sxcybot.util.Constants.ADDED_ROLE_ELEVATION; + +@Component +@RequiredArgsConstructor +public class AddRoleListener implements PrivateListener { + + @NonNull + private final GuildRoleService guildRoleService; + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateMessageReceivedEvent.getChannel(); + privateChannel.sendMessage("Name of the role you want to add?").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(nameReceiver -> { + String roleName = nameReceiver.getMessage().getContentRaw(); + Optional<Role> role = event.getGuild().getRoles().stream().filter(f -> roleName.equalsIgnoreCase(f.getName())).findFirst(); + if (role.isPresent()) { + int orderValue = guildRoleService.findAll().stream().filter(f -> f.getOrderValue() != null).max(Comparator.comparing(GuildRole::getOrderValue)).map(GuildRole::getOrderValue).orElse(0) + 1; + GuildRole roleToAdd = GuildRole.builder() + .name(roleName) + .orderValue(orderValue) + .elevation(ADDED_ROLE_ELEVATION) + .build(); + GuildRole guildRole = guildRoleService.save(roleToAdd); + privateChannel.sendMessage(String.format("Role %s has been succesfully added.", guildRole.getName())).queue(); + event.getChannel().sendMessage(String.format("Role %s has been added by %s.", + guildRole.getName(), JdaUtil.getUser(event) + )).queue(); + } else { + privateChannel.sendMessage(String.format("Role with name %s is not available in the channel, please contact a channel owner to have it added.", roleName)).queue(); + } + }, privateMessageReceivedEvent, privateChannel); + + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/role/DeleteRoleListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/role/DeleteRoleListener.java @@ -0,0 +1,50 @@ +package com.sxcy.sxcybot.listeners.admin.role; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.dao.GuildRole; +import com.sxcy.sxcybot.services.guild.GuildRoleService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.util.stream.Collectors; + +import static com.sxcy.sxcybot.util.Constants.ADDED_ROLE_ELEVATION; + +@Component +@RequiredArgsConstructor +public class DeleteRoleListener implements PrivateListener { + + @NonNull + private final GuildRoleService guildRoleService; + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateMessageReceivedEvent.getChannel(); + privateChannel.sendMessage("Name of the role you want to delete?").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(nameReceiver -> { + try { + GuildRole guildRole = guildRoleService.findByName(nameReceiver.getMessage().getContentRaw()); + if (guildRole.getElevation() == ADDED_ROLE_ELEVATION){ + guildRoleService.delete(guildRole); + guildRoleService.findAll().stream().filter(f -> f.getOrderValue() != null && f.getOrderValue() > guildRole.getOrderValue()).collect(Collectors.toList()) + .forEach(f -> guildRoleService.save(f.toBuilder().orderValue(f.getOrderValue() - 1).build())); + privateChannel.sendMessage(String.format("%s succesfully deleted.", guildRole)).queue(); + event.getChannel().sendMessage(String.format("Role %s has been deleted by %s", guildRole, JdaUtil.getUser(event))).queue(); + } else { + privateChannel.sendMessage("Only roles that can be added with the bb-role command can be deleted.").queue(); + } + } catch (EntityNotFoundException e) { + privateChannel.sendMessage(e.getMessage()).queue(); + } + }, event, privateChannel); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/role/UpdateRoleListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/role/UpdateRoleListener.java @@ -0,0 +1,53 @@ +package com.sxcy.sxcybot.listeners.admin.role; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.dao.GuildRole; +import com.sxcy.sxcybot.services.guild.GuildRoleService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + +import static com.sxcy.sxcybot.util.Constants.ADDED_ROLE_ELEVATION; + +@Component +@RequiredArgsConstructor +public class UpdateRoleListener implements PrivateListener { + + @NonNull + private final GuildRoleService guildRoleService; + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateMessageReceivedEvent.getChannel(); + privateChannel.sendMessage("Type the name of the role you want to update.").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(oldRoleNameReceiver -> { + String roleName = oldRoleNameReceiver.getMessage().getContentRaw(); + privateChannel.sendMessage("Type the new name for the role.").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(newRoleNameReceiver -> { + try { + GuildRole oldRole = guildRoleService.findByName(roleName); + if (oldRole.getElevation() == ADDED_ROLE_ELEVATION) { + GuildRole guildRole = guildRoleService.save(guildRoleService.findByName(roleName) + .toBuilder() + .name(newRoleNameReceiver.getMessage().getContentRaw()) + .build()); + newRoleNameReceiver.getChannel().sendMessage(guildRole + " edited").queue(); + event.getChannel().sendMessage(String.format("Role %s has been changed to %s by %s", roleName, newRoleNameReceiver.getMessage().getContentRaw(), JdaUtil.getUser(event))).queue(); + } else { + privateChannel.sendMessage("Only roles that can be added with the bb-role command can be updated.").queue(); + } + } catch (EntityNotFoundException exc) { + oldRoleNameReceiver.getChannel().sendMessage(exc.getMessage()).queue(); + } + }, privateMessageReceivedEvent, privateChannel); + }, privateMessageReceivedEvent, privateChannel); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/rule/AddRuleListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/rule/AddRuleListener.java @@ -0,0 +1,39 @@ +package com.sxcy.sxcybot.listeners.admin.rule; + +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.dao.Rule; +import com.sxcy.sxcybot.services.guild.RuleService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.util.Comparator; + +@Component +@RequiredArgsConstructor +public class AddRuleListener implements PrivateListener { + + @NonNull + private final RuleService ruleService; + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + privateMessageReceivedEvent.getChannel().sendMessage("Type rule description please").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(e -> { + String msg = e.getMessage().getContentRaw(); + int number = ruleService.findAll().stream().max(Comparator.comparing(Rule::getNumber)).map(Rule::getNumber).orElse(0) + 1; + Rule rule = ruleService.save(Rule.builder() + .number(number) + .description(msg) + .build()); + e.getChannel().sendMessage(rule + " saved").queue(); + event.getChannel().sendMessage(String.format("Rule #%s has been added by %s.", number, JdaUtil.getUser(event))).queue(); + }, privateMessageReceivedEvent, privateMessageReceivedEvent.getChannel()); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/rule/DeleteRuleListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/rule/DeleteRuleListener.java @@ -0,0 +1,49 @@ +package com.sxcy.sxcybot.listeners.admin.rule; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.dao.Rule; +import com.sxcy.sxcybot.services.guild.RuleService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.util.stream.Collectors; + + +@Component +@RequiredArgsConstructor +public class DeleteRuleListener implements PrivateListener { + + @NonNull + private final RuleService ruleService; + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateMessageReceivedEvent.getChannel(); + privateChannel.sendMessage("Type the # of the rule you wish to delete please.").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(ruleDeleltionReceiver -> { + try { + int ruleNumber = Integer.parseInt(ruleDeleltionReceiver.getMessage().getContentRaw()); + Rule rule = ruleService.findByNumber(ruleNumber); + ruleService.delete(rule); + ruleService.findAll().stream().filter(f -> f.getNumber() > ruleNumber).collect(Collectors.toList()) + .forEach(f -> ruleService.save(f.toBuilder().number(f.getNumber() - 1).build())); + privateChannel.sendMessage(String.format("%s has been succesfully deleted.", rule)).queue(); + event.getChannel().sendMessage(String.format("Rule %s has been deleted by %s", rule, JdaUtil.getUser(event))).queue(); + } catch (NumberFormatException e) { + privateChannel.sendMessage("Please try again later with a valid rule number.").queue(); + } catch (EntityNotFoundException e) { + privateChannel.sendMessage(e.getMessage()).queue(); + } + }, privateMessageReceivedEvent, privateChannel); + + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/admin/rule/UpdateRuleListener.java b/src/main/java/com/sxcy/sxcybot/listeners/admin/rule/UpdateRuleListener.java @@ -0,0 +1,51 @@ +package com.sxcy.sxcybot.listeners.admin.rule; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.PrivateListener; +import com.sxcy.sxcybot.repository.guild.dao.Rule; +import com.sxcy.sxcybot.services.guild.RuleService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.stereotype.Component; + + +@Component +@RequiredArgsConstructor +public class UpdateRuleListener implements PrivateListener { + + @NonNull + private final RuleService ruleService; + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @Override + public void proces(PrivateMessageReceivedEvent privateMessageReceivedEvent, MessageReceivedEvent event) { + PrivateChannel privateChannel = privateMessageReceivedEvent.getChannel(); + privateChannel.sendMessage("Type the rule number you want to update.").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(ruleNumberReciever -> { + try { + int ruleNumber = Integer.parseInt(ruleNumberReciever.getMessage().getContentRaw()); + privateChannel.sendMessage(String.format("Type the new rule description for rule %s.", ruleNumber)).queue(); + eventWaiterUtil.waitForPrivateChannelEvent(descriptionReceiver -> { + try { + Rule rule = ruleService.save(ruleService.findByNumber(ruleNumber) + .toBuilder() + .description(descriptionReceiver.getMessage().getContentRaw()) + .build()); + descriptionReceiver.getChannel().sendMessage(rule + " edited").queue(); + event.getChannel().sendMessage(String.format("Rule #%s has been edited by %s", ruleNumber, JdaUtil.getUser(event))).queue(); + } catch (EntityNotFoundException exc) { + ruleNumberReciever.getChannel().sendMessage(exc.getMessage()).queue(); + } + }, privateMessageReceivedEvent, privateChannel); + } catch (NumberFormatException exc) { + ruleNumberReciever.getChannel().sendMessage("No valid rule number.").queue(); + } + }, privateMessageReceivedEvent, privateChannel); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/BB8Listener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/BB8Listener.java @@ -0,0 +1,25 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.listeners.Listener; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.io.InputStream; + +import static com.sxcy.sxcybot.util.Constants.Emoji.FLAMES; +import static com.sxcy.sxcybot.util.Constants.Emoji.THUMBS_UP; + +@Component +public class BB8Listener implements Listener { + + private static final String BB8_IMAGE = "/images/bb8.jpg"; + + @Override + public void proces(MessageReceivedEvent event) { + MessageChannel channel = event.getChannel(); + InputStream in = getClass().getResourceAsStream(BB8_IMAGE); + channel.sendMessage("BEEP BOOP! " + THUMBS_UP + " " + FLAMES) + .addFile(in, "bb8.jpg").queue(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/CombatStatsListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/CombatStatsListener.java @@ -0,0 +1,51 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.model.CombatDto; +import com.sxcy.sxcybot.model.OsrsStat; +import com.sxcy.sxcybot.services.osrs.CombatCalculatorService; +import com.sxcy.sxcybot.services.osrs.StatMessageSender; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; + +import static com.sxcy.sxcybot.enums.OsrsCombatStat.ATTACK; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.DEFENCE; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.HITPOINTS; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.MAGIC; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.PRAYER; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.RANGED; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.STRENGTH; +import static com.google.common.collect.Lists.newArrayList; + +@Component +@RequiredArgsConstructor +public class CombatStatsListener implements Listener { + + @NonNull + private final StatMessageSender statMessageSender; + @NonNull + private final CombatCalculatorService combatCalculatorService; + + private static final ArrayList<String> COMBAT_STAT_LIST = newArrayList(ATTACK.value, STRENGTH.value, DEFENCE.value, HITPOINTS.value, RANGED.value, PRAYER.value, MAGIC.value); + + @Override + public void proces(MessageReceivedEvent event) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + event.getChannel().sendTyping().queue(e -> + statMessageSender.sendStatMessage(event, embedBuilder, this::isCombatStat, + f -> embedBuilder.addField(f.getName(), "Level " + f.getLevel(), true) + , osrsStatList -> embedBuilder.addField("COMBAT", String.valueOf(combatCalculatorService.getCombatLevel(CombatDto.build(osrsStatList))), false) + ) + ); + } + + private boolean isCombatStat(OsrsStat osrsStat) { + return COMBAT_STAT_LIST.contains(osrsStat.getName()); + } + +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/CustomPollListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/CustomPollListener.java @@ -0,0 +1,47 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.util.CustomPollFiller; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.exceptions.RateLimitedException; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.awt.Color; +import java.util.LinkedHashSet; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +@RequiredArgsConstructor +public class CustomPollListener implements Listener { + @NonNull + private final CustomPollFiller customPollFiller; + + @Override + public void proces(MessageReceivedEvent event) { + String msg = event.getMessage().getContentRaw(); + try { + String title = msg.substring(msg.indexOf(" ")); + if (event.getMember() != null) { + try { + PrivateChannel privateChannel = event.getMember().getUser().openPrivateChannel().complete(true); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.red); + embedBuilder.setTitle(title); + embedBuilder.setFooter("Let the polling begin!", event.getGuild().getIconUrl()); + + customPollFiller.fillPoll(privateChannel, event, embedBuilder, new LinkedHashSet<>()); + } catch (RateLimitedException e) { + e.printStackTrace(); + } + } + } catch (StringIndexOutOfBoundsException e) { + event.getChannel().sendMessage("Please enter a descriptive title for the poll after the command, separated by space.").queue(); + } + } +} +\ No newline at end of file diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/EventListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/EventListener.java @@ -0,0 +1,55 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.repository.guild.dao.Event; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import net.dv8tion.jda.api.exceptions.RateLimitedException; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class EventListener implements Listener { + + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + @Override + public void proces(MessageReceivedEvent event) { + if (!event.getAuthor().isBot() && event.getMember() != null) { + try { + PrivateChannel privateChannel = event.getMember().getUser().openPrivateChannel().complete(true); + privateChannel.sendMessage("Name of the event?").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(nameReceiver -> { + privateChannel.sendMessage("Description?").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(descriptionReceiver -> { + privateChannel.sendMessage("TimeZone, UTC or PT?").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(timeZoneReceiver -> { + privateChannel.sendMessage("Date?").queue(); + eventWaiterUtil.waitForPrivateChannelEvent(dateReceiver -> + finishEventCreation(nameReceiver, descriptionReceiver, timeZoneReceiver, dateReceiver, event), event, privateChannel); + }, event, privateChannel); + }, event, privateChannel); + }, event, privateChannel); + } catch (RateLimitedException e) { + e.printStackTrace(); + } + } + } + + private void finishEventCreation(PrivateMessageReceivedEvent nameReceiver, + PrivateMessageReceivedEvent descriptionReceiver, + PrivateMessageReceivedEvent timeZoneReceiver, + PrivateMessageReceivedEvent dateReceiver, + MessageReceivedEvent event) { + Event createdEvent = Event.builder() + .name(nameReceiver.getMessage().getContentRaw()) + .description(descriptionReceiver.getMessage().getContentRaw()) + .build(); + event.getChannel().sendMessage("Event created :" + createdEvent).queue(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/ForumListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/ForumListener.java @@ -0,0 +1,31 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.services.guild.ChannelDetailService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.awt.Color; + +@Component +@RequiredArgsConstructor +public class ForumListener implements Listener { + + @NonNull + private final ChannelDetailService channelDetailService; + + @Override + public void proces(MessageReceivedEvent event) { + channelDetailService.findAll().stream().findAny().ifPresent(channelDetail -> { + MessageChannel channel = event.getChannel(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.RED); + embedBuilder.setTitle("Link to the forum post", channelDetail.getForumUrl()); + channel.sendMessage(embedBuilder.build()).queue(); + }); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/HelpListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/HelpListener.java @@ -0,0 +1,35 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.enums.Command; +import com.sxcy.sxcybot.enums.Command.Admin; +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.util.Constants.Commands; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.awt.Color; + +@Component +public class HelpListener implements Listener { + + @Override + public void proces(MessageReceivedEvent event) { + event.getChannel().sendTyping().queue(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + + embedBuilder.setColor(Color.red); + embedBuilder.setTitle("List of Commands"); + for (Command command : Command.values()) { + embedBuilder.addField(Commands.COMMAND_PREFIX + command.name().toLowerCase(), command.description, false); + } + EmbedBuilder adminEmbedBuilder = new EmbedBuilder(); + adminEmbedBuilder.setColor(Color.red); + adminEmbedBuilder.setTitle("List of Admin Commands"); + for (Admin admin : Admin.values()) { + adminEmbedBuilder.addField(Commands.COMMAND_PREFIX + admin.name().toLowerCase(), admin.description, false); + } + event.getChannel().sendMessage(embedBuilder.build()).queue(); + event.getChannel().sendMessage(adminEmbedBuilder.build()).queue(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/HiscoreBossListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/HiscoreBossListener.java @@ -0,0 +1,50 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.enums.PvmRole; +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.repository.osrs.dao.OsrsHiscoreBoss; +import com.sxcy.sxcybot.services.osrs.OsrsHiscoreBossService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.awt.Color; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class HiscoreBossListener implements Listener { + + @NonNull + private final OsrsHiscoreBossService osrsHiscoreBossService; + + @Override + public void proces(MessageReceivedEvent event) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.red); + List<OsrsHiscoreBoss> hiscoreBossList = osrsHiscoreBossService.findAll(); + for (PvmRole pvmRole : PvmRole.values()) { + int i = 1; + embedBuilder.setTitle(String.format("List of %s bosses:", pvmRole)); + for (OsrsHiscoreBoss osrsHiscoreBoss : hiscoreBossList) { + if (pvmRole.value == osrsHiscoreBoss.getPvmRole()) { + embedBuilder.addField(osrsHiscoreBoss.getName(), + String.format("Multiplier: %s", + osrsHiscoreBoss.getMultiplier()), + true); + if (JdaUtil.requiresBuild(embedBuilder, hiscoreBossList.size(), i)) { + event.getChannel().sendMessage(embedBuilder.build()).queue(); + embedBuilder.clearFields(); + } + } + i++; + } + if (embedBuilder.getFields().size() > 0) + event.getChannel().sendMessage(embedBuilder.build()).queue(); + embedBuilder.clearFields(); + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/KillCountListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/KillCountListener.java @@ -0,0 +1,52 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.client.HiScoreClient; +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.model.OsrsBossKc; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.awt.Color; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class KillCountListener implements Listener { + @NonNull + private final HiScoreClient hiScoreClient; + + @Override + public void proces(MessageReceivedEvent event) { + String msg = event.getMessage().getContentRaw(); + try { + String player = msg.substring(msg.indexOf(" ")).trim(); + List<OsrsBossKc> bossKcList = hiScoreClient.getHiScoreBossKc(player, event.getChannel()).orElseThrow(() + -> new EntityNotFoundException(String.format("No HiScores found for %s.", player))); + + event.getChannel().sendTyping().queue(q -> { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setTitle(String.format("Killcount for %s", player)); + embedBuilder.setColor(Color.RED); + int i = 1; + bossKcList.stream().filter(f -> !"-1".equals(f.getKc())).forEach(f -> { + embedBuilder.addField(f.getName(), String.format("Kc: %s%sRank: %s", f.getKc(), System.lineSeparator(), f.getRank()), true); + if (JdaUtil.requiresBuild(embedBuilder, bossKcList.size(), i)) { + event.getChannel().sendMessage(embedBuilder.build()).queue(); + embedBuilder.clearFields(); + } + }); + event.getChannel().sendMessage(embedBuilder.build()).queue(); + }); + + } catch (StringIndexOutOfBoundsException e) { + event.getChannel().sendMessage("Please enter a player name after the command, separated by space.").queue(); + } catch (EntityNotFoundException e) { + event.getChannel().sendMessage(e.getMessage()).queue(); + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/PingListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/PingListener.java @@ -0,0 +1,19 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.listeners.Listener; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +@Component +public class PingListener implements Listener { + + @Override + public void proces(MessageReceivedEvent event) { + MessageChannel channel; + channel = event.getChannel(); + long time = System.currentTimeMillis(); + channel.sendMessage("Pong") + .queue(response -> response.editMessageFormat("Pong: %d ms", System.currentTimeMillis() - time).queue()); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/PollListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/PollListener.java @@ -0,0 +1,66 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.repository.guild.dao.Poll; +import com.sxcy.sxcybot.services.guild.PollService; +import com.sxcy.sxcybot.util.Constants.Reaction; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.awt.Color; + +@Component +@RequiredArgsConstructor +public class PollListener implements Listener { + + @NonNull + private final PollService pollService; + + @Override + public void proces(MessageReceivedEvent event) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + String msg = event.getMessage().getContentRaw(); + try { + String title = msg.substring(msg.indexOf(" ")); + + embedBuilder.setColor(Color.red); + embedBuilder.setTitle(title); + embedBuilder.addField("✅ Accept (0)", "", true); + embedBuilder.addField("❎ Deny (0)", "", true); + embedBuilder.addField("❓ Unsure (0)", "", true); + embedBuilder.setFooter("Let the polling begin!", event.getGuild().getIconUrl()); + + event.getChannel().sendTyping().queue(typing -> + event.getChannel().sendMessage(embedBuilder.build()).queue(message -> { + message.addReaction(Reaction.CHECK_MARK_BUTTON) + .and(message.addReaction(Reaction.CROSS_MARK_BUTTON)) + .and(message.addReaction(Reaction.QUESTION_MARK)) + .queue(); + pollService.save(Poll.builder().messageId(message.getId()).build()); + })); + } catch (StringIndexOutOfBoundsException e) { + event.getChannel().sendMessage("Please enter a descriptive title for the poll after the command, separated by space.").queue(); + } + } + +// private Poll createPoll(String messageId) { +// List<PollReaction> pollReactionList = newArrayList(); +// Poll poll = Poll.builder() +// .pollReactions(newArrayList(pollReactionList)) +// .messageId(messageId) +// .build(); +// PollReaction pollReaction = PollReaction.builder() +// .reactionId("reactionId") +// .poll(poll) +// .build(); +// pollReactionList.add(pollReaction); +// poll.setPollReactions(pollReactionList); +// +// return poll; +// +// } +} + diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/PriceListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/PriceListener.java @@ -0,0 +1,43 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.client.GrandExchangeClient; +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.Listener; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.awt.Color; + +@Component +@RequiredArgsConstructor +public class PriceListener implements Listener { + + @NonNull + private final GrandExchangeClient grandExchangeClient; + + @Override + public void proces(MessageReceivedEvent event) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + String msg = event.getMessage().getContentRaw(); + try { + String itemName = msg.substring(msg.indexOf(" ")).trim(); + event.getChannel().sendTyping().queue(typing -> { + try { + Object result = grandExchangeClient.getPrice(itemName, event.getChannel()); + embedBuilder.setTitle("Price of item"); + embedBuilder.setColor(Color.RED); + embedBuilder.addField(itemName, result.toString(), false); + event.getChannel().sendMessage(embedBuilder.build()).queue(); + } catch (EntityNotFoundException e) { + event.getChannel().sendMessage(e.getMessage()).queue(); + } + }); + } catch (StringIndexOutOfBoundsException e) { + event.getChannel().sendMessage("Please enter an item name after the command, separated by space.").queue(); + } + + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/PvmListListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/PvmListListener.java @@ -0,0 +1,43 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleUserService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.awt.Color; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class PvmListListener implements Listener { + + @NonNull + private final PvmRoleUserService pvmRoleUserService; + + @Override + public void proces(MessageReceivedEvent event) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.red); + embedBuilder.setTitle("List of PvM Role competitors:"); + List<PvmRoleUser> pvmRoleUsers = pvmRoleUserService.findAll(); + int i = 1; + for (PvmRoleUser pvmRoleUser : pvmRoleUsers) { + embedBuilder.addField(pvmRoleUser.getDiscordName(), + String.format("RSN: %s", pvmRoleUser.getRsn()) + System.lineSeparator() + + String.format("||_Created by: %s - %s | Last edit: %s - %s_||", + pvmRoleUser.getCreatedBy(), pvmRoleUser.getCreatedDate(), pvmRoleUser.getLastModifiedBy(), pvmRoleUser.getLastModifiedDate()), + false); + if (JdaUtil.requiresBuild(embedBuilder, pvmRoleUsers.size(), i)) { + event.getChannel().sendMessage(embedBuilder.build()).queue(); + embedBuilder.clear(); + } + i++; + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/RuleListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/RuleListener.java @@ -0,0 +1,45 @@ +package com.sxcy.sxcybot.listeners.member; + + +import com.sxcy.sxcybot.enums.Command; +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.services.guild.RuleService; +import com.sxcy.sxcybot.util.Constants.Commands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.awt.Color; + + +@Component +@RequiredArgsConstructor +public class RuleListener implements Listener { + + @NonNull + private final RuleService ruleService; + + @Override + public void proces(MessageReceivedEvent event) { + MessageChannel channel = event.getChannel(); + int ruleNumber; + String description; + try { + ruleNumber = Integer.parseInt(event.getMessage().getContentRaw().substring(Commands.COMMAND_PREFIX.length() + Command.RULE.name().length() + 1)); + description = ruleService.findByNumber(ruleNumber).getDescription(); + } catch (NumberFormatException | EntityNotFoundException e) { + channel.sendMessage(e.getMessage()).queue(); + return; + } + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.RED); + embedBuilder.setTitle("Show rule result"); + embedBuilder.addField(String.format("Rule #%s", ruleNumber), description, false); + channel.sendMessage(embedBuilder.build()).queue(); + } + +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/RulesListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/RulesListener.java @@ -0,0 +1,41 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.repository.guild.dao.Rule; +import com.sxcy.sxcybot.services.guild.RuleService; +import com.sxcy.sxcybot.util.JdaUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.awt.Color; +import java.util.Comparator; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class RulesListener implements Listener { + + @NonNull + private final RuleService ruleService; + + @Override + public void proces(MessageReceivedEvent event) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.red); + embedBuilder.setTitle(String.format("List of %s rules:", event.getGuild().getName())); + List<Rule> ruleList = ruleService.findAll(); + ruleList.sort(Comparator.comparing(Rule::getNumber)); + int i = 1; + for (Rule rule : ruleList) { + embedBuilder.addField(String.format("Rule #%s", rule.getNumber()), rule.getDescription(), false); + if (JdaUtil.requiresBuild(embedBuilder, ruleList.size(), i)) { + event.getChannel().sendMessage(embedBuilder.build()).queue(); + embedBuilder.clear(); + } + i++; + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/listeners/member/StatsListener.java b/src/main/java/com/sxcy/sxcybot/listeners/member/StatsListener.java @@ -0,0 +1,31 @@ +package com.sxcy.sxcybot.listeners.member; + +import com.sxcy.sxcybot.listeners.Listener; +import com.sxcy.sxcybot.services.osrs.StatMessageSender; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.Objects; + +@Component +@RequiredArgsConstructor +public class StatsListener implements Listener { + + @Nonnull + private final StatMessageSender statMessageSender; + + @Override + public void proces(MessageReceivedEvent event) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + event.getChannel().sendTyping().queue(e -> + statMessageSender.sendStatMessage(event, embedBuilder, Objects::nonNull, + f -> embedBuilder.addField(f.getName(), + "Level " + f.getLevel() + System.lineSeparator() + + "Rank " + f.getRank() + System.lineSeparator() + + "Exp " + f.getExperience(), true), null + )); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/model/CombatDto.java b/src/main/java/com/sxcy/sxcybot/model/CombatDto.java @@ -0,0 +1,56 @@ +package com.sxcy.sxcybot.model; + +import lombok.Builder; +import lombok.Value; + +import java.util.List; + +import static com.sxcy.sxcybot.enums.OsrsCombatStat.ATTACK; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.DEFENCE; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.HITPOINTS; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.MAGIC; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.PRAYER; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.RANGED; +import static com.sxcy.sxcybot.enums.OsrsCombatStat.STRENGTH; + +@Value +@Builder(toBuilder = true) +public class CombatDto { + + + int attackLevel; + int strengthLevel; + int defenceLevel; + int hitpointsLevel; + int magicLevel; + int rangeLevel; + int prayerLevel; + + public static CombatDto build(List<OsrsStat> osrsStatList) { + CombatDto.CombatDtoBuilder builder = CombatDto.builder(); + for (OsrsStat osrsStat : osrsStatList) { + if (ATTACK.value.equalsIgnoreCase(osrsStat.getName())) { + builder.attackLevel(Integer.parseInt(osrsStat.getLevel())); + } + if (STRENGTH.value.equalsIgnoreCase(osrsStat.getName())) { + builder.strengthLevel(Integer.parseInt(osrsStat.getLevel())); + } + if (DEFENCE.value.equalsIgnoreCase(osrsStat.getName())) { + builder.defenceLevel(Integer.parseInt(osrsStat.getLevel())); + } + if (HITPOINTS.value.equalsIgnoreCase(osrsStat.getName())) { + builder.hitpointsLevel(Integer.parseInt(osrsStat.getLevel())); + } + if (MAGIC.value.equalsIgnoreCase(osrsStat.getName())) { + builder.magicLevel(Integer.parseInt(osrsStat.getLevel())); + } + if (RANGED.value.equalsIgnoreCase(osrsStat.getName())) { + builder.rangeLevel(Integer.parseInt(osrsStat.getLevel())); + } + if (PRAYER.value.equalsIgnoreCase(osrsStat.getName())) { + builder.prayerLevel(Integer.parseInt(osrsStat.getLevel())); + } + } + return builder.build(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/model/EditListenerDto.java b/src/main/java/com/sxcy/sxcybot/model/EditListenerDto.java @@ -0,0 +1,25 @@ +package com.sxcy.sxcybot.model; + +import com.sxcy.sxcybot.listeners.PrivateListener; +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; + +@Builder(toBuilder = true) +@Value +public class EditListenerDto { + + @NonNull + PrivateListener addListener; + PrivateListener updateListener; + @NonNull + PrivateListener deleteListener; + @NonNull + MessageReceivedEvent event; + @NonNull + PrivateChannel privateChannel; + @NonNull + String entityName; +} diff --git a/src/main/java/com/sxcy/sxcybot/model/HiScoreBuilder.java b/src/main/java/com/sxcy/sxcybot/model/HiScoreBuilder.java @@ -0,0 +1,11 @@ +package com.sxcy.sxcybot.model; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; + +import java.util.List; + +@FunctionalInterface +public interface HiScoreBuilder<T> { + + T accept(String string, List<String> stringList, int i) throws EntityNotFoundException; +} diff --git a/src/main/java/com/sxcy/sxcybot/model/OsrsBossKc.java b/src/main/java/com/sxcy/sxcybot/model/OsrsBossKc.java @@ -0,0 +1,14 @@ +package com.sxcy.sxcybot.model; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder(toBuilder = true) +public class OsrsBossKc { + + String name; + String rank; + String kc; + +} diff --git a/src/main/java/com/sxcy/sxcybot/model/OsrsItem.java b/src/main/java/com/sxcy/sxcybot/model/OsrsItem.java @@ -0,0 +1,20 @@ +package com.sxcy.sxcybot.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@JsonDeserialize +@Builder(toBuilder = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class OsrsItem { + + private String id; + private String timestamp; + private Integer price; + private String volume; +} diff --git a/src/main/java/com/sxcy/sxcybot/model/OsrsStat.java b/src/main/java/com/sxcy/sxcybot/model/OsrsStat.java @@ -0,0 +1,14 @@ +package com.sxcy.sxcybot.model; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder(toBuilder = true) +public class OsrsStat { + + String name; + String experience; + String rank; + String level; +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/ChannelDetailRepository.java b/src/main/java/com/sxcy/sxcybot/repository/guild/ChannelDetailRepository.java @@ -0,0 +1,9 @@ +package com.sxcy.sxcybot.repository.guild; + +import com.sxcy.sxcybot.repository.guild.dao.ChannelDetail; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ChannelDetailRepository extends JpaRepository<ChannelDetail, String> { +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/GuildEventDmerRepository.java b/src/main/java/com/sxcy/sxcybot/repository/guild/GuildEventDmerRepository.java @@ -0,0 +1,9 @@ +package com.sxcy.sxcybot.repository.guild; + +import com.sxcy.sxcybot.repository.guild.dao.GuildEventDmer; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface GuildEventDmerRepository extends JpaRepository<GuildEventDmer, String> { +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/GuildRoleRepository.java b/src/main/java/com/sxcy/sxcybot/repository/guild/GuildRoleRepository.java @@ -0,0 +1,18 @@ +package com.sxcy.sxcybot.repository.guild; + +import com.sxcy.sxcybot.repository.guild.dao.GuildRole; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface GuildRoleRepository extends JpaRepository<GuildRole, String> { + + List<GuildRole> findByElevationLessThanEqual(Integer elevation); + + List<GuildRole> findByElevationGreaterThanEqual(Integer elevation); + + Optional<GuildRole> findByName(String name); +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/PollRepository.java b/src/main/java/com/sxcy/sxcybot/repository/guild/PollRepository.java @@ -0,0 +1,13 @@ +package com.sxcy.sxcybot.repository.guild; + +import com.sxcy.sxcybot.repository.guild.dao.Poll; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface PollRepository extends JpaRepository<Poll, String> { + + Optional<Poll> findByMessageId(String messageId); +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/RuleRepository.java b/src/main/java/com/sxcy/sxcybot/repository/guild/RuleRepository.java @@ -0,0 +1,14 @@ +package com.sxcy.sxcybot.repository.guild; + +import com.sxcy.sxcybot.repository.guild.dao.Rule; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface RuleRepository extends JpaRepository<Rule, String> { + + Optional<Rule> findByNumber(int number); + +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/UserRepository.java b/src/main/java/com/sxcy/sxcybot/repository/guild/UserRepository.java @@ -0,0 +1,16 @@ +package com.sxcy.sxcybot.repository.guild; + +import com.sxcy.sxcybot.repository.guild.dao.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface UserRepository extends JpaRepository<User, String> { + + Optional<User> findByName(String name); + + List<User> findAllByBannedTrue(); +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/dao/ChannelDetail.java b/src/main/java/com/sxcy/sxcybot/repository/guild/dao/ChannelDetail.java @@ -0,0 +1,29 @@ +package com.sxcy.sxcybot.repository.guild.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ChannelDetail { + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + private String id; + private String forumUrl; + private String botUpdateChannel; + private String pvmRoleChannel; + private String pvmRoleGeneral; + private String pvmRoleRaids; + private String pvmRoleWilderness; +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/dao/Event.java b/src/main/java/com/sxcy/sxcybot/repository/guild/dao/Event.java @@ -0,0 +1,20 @@ +package com.sxcy.sxcybot.repository.guild.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; + +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Event { + + private String name; + private String description; + private LocalDate time; + +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/dao/GuildEventDmer.java b/src/main/java/com/sxcy/sxcybot/repository/guild/dao/GuildEventDmer.java @@ -0,0 +1,27 @@ +package com.sxcy.sxcybot.repository.guild.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString.Exclude; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +public class GuildEventDmer { + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + @Exclude + private String id; + + private String name; +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/dao/GuildRole.java b/src/main/java/com/sxcy/sxcybot/repository/guild/dao/GuildRole.java @@ -0,0 +1,27 @@ +package com.sxcy.sxcybot.repository.guild.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GuildRole { + + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + private String id; + private String name; + private Integer orderValue; + private int elevation; +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/dao/Poll.java b/src/main/java/com/sxcy/sxcybot/repository/guild/dao/Poll.java @@ -0,0 +1,37 @@ +package com.sxcy.sxcybot.repository.guild.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.GenericGenerator; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import java.time.LocalDateTime; + +@Entity +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class Poll { + + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + private String id; + + private String messageId; + @CreatedDate + private LocalDateTime createdDate; + @LastModifiedDate + private LocalDateTime lastModifiedDate; + +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/dao/Rule.java b/src/main/java/com/sxcy/sxcybot/repository/guild/dao/Rule.java @@ -0,0 +1,30 @@ +package com.sxcy.sxcybot.repository.guild.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString.Exclude; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Rule { + + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + @Exclude + private String id; + + private int number; + + private String description; +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/dao/User.java b/src/main/java/com/sxcy/sxcybot/repository/guild/dao/User.java @@ -0,0 +1,41 @@ +package com.sxcy.sxcybot.repository.guild.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString.Exclude; +import org.hibernate.annotations.GenericGenerator; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import java.time.LocalDate; + +@Entity +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class User { + + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + @Exclude + private String id; + private String name; + private String description; + private boolean banned; + @CreatedDate + private LocalDate createdDate; + private String createdBy; + @LastModifiedDate + private LocalDate lastModifiedDate; + private String lastModifiedBy; +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/PvmKcSnapshotRepository.java b/src/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/PvmKcSnapshotRepository.java @@ -0,0 +1,14 @@ +package com.sxcy.sxcybot.repository.guild.pvmrole; + +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmKcSnapshot; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface PvmKcSnapshotRepository extends JpaRepository<PvmKcSnapshot, String> { + + List<PvmKcSnapshot> findAllByPvmRoleUserId(String PvmRoleUserId); + +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/PvmRoleUserRepository.java b/src/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/PvmRoleUserRepository.java @@ -0,0 +1,13 @@ +package com.sxcy.sxcybot.repository.guild.pvmrole; + +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface PvmRoleUserRepository extends JpaRepository<PvmRoleUser, String> { + + Optional<PvmRoleUser> findByDiscordName(String discordName); +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/dao/PvmKcSnapshot.java b/src/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/dao/PvmKcSnapshot.java @@ -0,0 +1,50 @@ +package com.sxcy.sxcybot.repository.guild.pvmrole.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.hibernate.annotations.GenericGenerator; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class PvmKcSnapshot { + + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + private String id; + + @OneToOne + private PvmRoleUser pvmRoleUser; + + @OneToMany(mappedBy = "pvmKcSnapshot", cascade = CascadeType.ALL, orphanRemoval = true) + @ToString.Exclude + @EqualsAndHashCode.Exclude + private List<PvmUserKc> pvmUserKcList = new ArrayList<>(); + + @CreatedDate + private LocalDateTime createdDate; + @LastModifiedDate + private LocalDateTime lastModifiedDate; +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/dao/PvmRoleUser.java b/src/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/dao/PvmRoleUser.java @@ -0,0 +1,40 @@ +package com.sxcy.sxcybot.repository.guild.pvmrole.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.hibernate.annotations.GenericGenerator; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import java.time.LocalDateTime; + +@Entity +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class PvmRoleUser { + + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + @ToString.Exclude + private String id; + private String discordName; + private String rsn; + @CreatedDate + private LocalDateTime createdDate; + private String createdBy; + @LastModifiedDate + private LocalDateTime lastModifiedDate; + private String lastModifiedBy; +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/dao/PvmUserKc.java b/src/main/java/com/sxcy/sxcybot/repository/guild/pvmrole/dao/PvmUserKc.java @@ -0,0 +1,53 @@ +package com.sxcy.sxcybot.repository.guild.pvmrole.dao; + +import com.sxcy.sxcybot.repository.osrs.dao.OsrsHiscoreBoss; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.GenericGenerator; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import java.time.LocalDateTime; + +@Entity +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class PvmUserKc { + + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + private String id; + + @OneToOne + @JoinColumn(name = "pvm_role_user_id") + private PvmRoleUser pvmRoleUser; + + @OneToOne + @JoinColumn(name = "osrs_hiscore_boss_id") + private OsrsHiscoreBoss osrsHiscoreBoss; + + private Integer kc; + + @ManyToOne + @JoinColumn(name = "pvm_kc_snapshot_id") + private PvmKcSnapshot pvmKcSnapshot; + + @CreatedDate + private LocalDateTime createdDate; + @LastModifiedDate + private LocalDateTime lastModifiedDate; +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/osrs/OsrsHiscoreBossRepository.java b/src/main/java/com/sxcy/sxcybot/repository/osrs/OsrsHiscoreBossRepository.java @@ -0,0 +1,13 @@ +package com.sxcy.sxcybot.repository.osrs; + +import com.sxcy.sxcybot.repository.osrs.dao.OsrsHiscoreBoss; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface OsrsHiscoreBossRepository extends JpaRepository<OsrsHiscoreBoss, String> { + + Optional<OsrsHiscoreBoss> findByName(String name); +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/osrs/OsrsHiscoreStatRepository.java b/src/main/java/com/sxcy/sxcybot/repository/osrs/OsrsHiscoreStatRepository.java @@ -0,0 +1,9 @@ +package com.sxcy.sxcybot.repository.osrs; + +import com.sxcy.sxcybot.repository.osrs.dao.OsrsHiscoreStat; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface OsrsHiscoreStatRepository extends JpaRepository<OsrsHiscoreStat, String> { +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/osrs/dao/OsrsHiscoreBoss.java b/src/main/java/com/sxcy/sxcybot/repository/osrs/dao/OsrsHiscoreBoss.java @@ -0,0 +1,27 @@ +package com.sxcy.sxcybot.repository.osrs.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OsrsHiscoreBoss { + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + private String id; + private String name; + private int orderValue; + private double multiplier; + private int pvmRole; +} diff --git a/src/main/java/com/sxcy/sxcybot/repository/osrs/dao/OsrsHiscoreStat.java b/src/main/java/com/sxcy/sxcybot/repository/osrs/dao/OsrsHiscoreStat.java @@ -0,0 +1,25 @@ +package com.sxcy.sxcybot.repository.osrs.dao; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +@Builder(toBuilder = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OsrsHiscoreStat { + @Id + @GeneratedValue(generator = "uuid") + @GenericGenerator(name = "uuid", strategy = "uuid") + private String id; + private String name; + private int orderValue; +} diff --git a/src/main/java/com/sxcy/sxcybot/services/CleanuperScheduler.java b/src/main/java/com/sxcy/sxcybot/services/CleanuperScheduler.java @@ -0,0 +1,63 @@ +package com.sxcy.sxcybot.services; + +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmKcSnapshot; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.sxcy.sxcybot.services.guild.PollService; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmKcSnapshotService; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleUserService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +@Slf4j +public class CleanuperScheduler { + + private static final int POLL_DAYS_VALID = 60; + + @NonNull + private final PvmKcSnapshotService pvmKcSnapshotService; + + @NonNull + private final PvmRoleUserService pvmRoleUserService; + + @NonNull + private final PollService pollService; + + @Scheduled(cron = "${db.cleanup.schedule}") + @SuppressWarnings("unused") + public void cleanup() { + cleanupPvmKcSnapshots(); + cleanupPolls(); + } + + private void cleanupPvmKcSnapshots() { + List<PvmKcSnapshot> pvmKcSnapshotList; + for (PvmRoleUser pvmRoleUser : pvmRoleUserService.findAll()) { + pvmKcSnapshotList = pvmKcSnapshotService.findAllByPvmRoleUser(pvmRoleUser); + if (pvmKcSnapshotList.size() > 3) { + pvmKcSnapshotList = pvmKcSnapshotList.stream() + .sorted(Comparator.comparing(PvmKcSnapshot::getCreatedDate).reversed()) + .skip(2) + .collect(Collectors.toList()); + log.info("deleted {} from {}", pvmKcSnapshotList.size(), pvmRoleUser.getDiscordName()); + pvmKcSnapshotService.deleteAll(pvmKcSnapshotList); + } + } + } + + private void cleanupPolls() { + pollService.findAll().stream().filter(f -> ChronoUnit.DAYS.between(f.getCreatedDate(), LocalDateTime.now()) > POLL_DAYS_VALID) + .peek(f -> log.info("removed poll {} from {}", f.getMessageId(), f.getCreatedDate())) + .forEach(pollService::delete); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/PvMRoleScheduler.java b/src/main/java/com/sxcy/sxcybot/services/PvMRoleScheduler.java @@ -0,0 +1,61 @@ +package com.sxcy.sxcybot.services; + +import com.sxcy.sxcybot.enums.PvmRole; +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.sxcy.sxcybot.services.guild.ChannelDetailService; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleAssignerService; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleSnapshotComparerService; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleUserService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import net.dv8tion.jda.api.JDA; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class PvMRoleScheduler { + + @NonNull + private final PvmRoleUserService pvmRoleUserService; + @NonNull + private final ChannelDetailService channelDetailService; + @NonNull + private final PvmRoleSnapshotComparerService pvmRoleSnapshotComparerService; + @NonNull + private final PvmRoleAssignerService pvmRoleAssignerService; + @Setter + private JDA jda; + + @Scheduled(cron = "${pvm.role.schedule}") + @SuppressWarnings("unused") + public void resolvePvMRoles() { + Map<PvmRole, LinkedHashMap<PvmRoleUser, BigDecimal>> scoreBoard = new HashMap<>(); + for (PvmRole pvmRole : PvmRole.values()) { + scoreBoard.put(pvmRole, new LinkedHashMap<>()); + } + jda.getGuilds().forEach(guild -> + channelDetailService.findAll().stream().findAny().ifPresent(channelDetail -> + guild.getTextChannelsByName(channelDetail.getPvmRoleChannel(), true) + .forEach(textChannel -> { + for (PvmRoleUser pvmRoleUser : pvmRoleUserService.findAll()) { + try { + pvmRoleSnapshotComparerService.saveSnapshot(textChannel, pvmRoleUser, false); + } catch (EntityNotFoundException e) { + textChannel.sendMessage(e.getMessage()).queue(); + } + pvmRoleSnapshotComparerService.updateScoreboard(pvmRoleUser, scoreBoard); + } + pvmRoleAssignerService.postScoreboardAndAssignRoles(guild, textChannel, scoreBoard, channelDetail); + }) + ) + ); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/ChannelDetailService.java b/src/main/java/com/sxcy/sxcybot/services/guild/ChannelDetailService.java @@ -0,0 +1,10 @@ +package com.sxcy.sxcybot.services.guild; + +import com.sxcy.sxcybot.repository.guild.dao.ChannelDetail; + +import java.util.List; + +public interface ChannelDetailService { + + List<ChannelDetail> findAll(); +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/GuildEventDmerService.java b/src/main/java/com/sxcy/sxcybot/services/guild/GuildEventDmerService.java @@ -0,0 +1,11 @@ +package com.sxcy.sxcybot.services.guild; + +import com.sxcy.sxcybot.repository.guild.dao.GuildEventDmer; + +import java.util.List; + +public interface GuildEventDmerService { + + List<GuildEventDmer> findAll(); + +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/GuildRoleService.java b/src/main/java/com/sxcy/sxcybot/services/guild/GuildRoleService.java @@ -0,0 +1,22 @@ +package com.sxcy.sxcybot.services.guild; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.guild.dao.GuildRole; + +import java.util.List; + +public interface GuildRoleService { + + List<GuildRole> findAllByElevationLessThanEqual(int elevation); + + List<GuildRole> findAllByElevationGreaterThanEqual(int elevation); + + GuildRole findByName(String name) throws EntityNotFoundException; + + GuildRole save(GuildRole guildRole); + + void delete(GuildRole guildRole); + + List<GuildRole> findAll(); + +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/PollService.java b/src/main/java/com/sxcy/sxcybot/services/guild/PollService.java @@ -0,0 +1,17 @@ +package com.sxcy.sxcybot.services.guild; + +import com.sxcy.sxcybot.repository.guild.dao.Poll; + +import java.util.List; +import java.util.Optional; + +public interface PollService { + + List<Poll> findAll(); + + Optional<Poll> findByMessageId(String messageId); + + Poll save(Poll poll); + + void delete(Poll poll); +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/RuleService.java b/src/main/java/com/sxcy/sxcybot/services/guild/RuleService.java @@ -0,0 +1,17 @@ +package com.sxcy.sxcybot.services.guild; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.guild.dao.Rule; + +import java.util.List; + +public interface RuleService { + + List<Rule> findAll(); + + Rule findByNumber(int number) throws EntityNotFoundException; + + Rule save(Rule rule); + + void delete(Rule rule); +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/UserService.java b/src/main/java/com/sxcy/sxcybot/services/guild/UserService.java @@ -0,0 +1,17 @@ +package com.sxcy.sxcybot.services.guild; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.guild.dao.User; + +import java.util.List; + +public interface UserService { + + List<User> findAllBanned(); + + User save(User user); + + void delete(User user) throws EntityNotFoundException; + + User findByName(String name) throws EntityNotFoundException; +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/impl/ChannelDetailServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/guild/impl/ChannelDetailServiceImpl.java @@ -0,0 +1,25 @@ +package com.sxcy.sxcybot.services.guild.impl; + +import com.sxcy.sxcybot.repository.guild.ChannelDetailRepository; +import com.sxcy.sxcybot.repository.guild.dao.ChannelDetail; +import com.sxcy.sxcybot.services.guild.ChannelDetailService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class ChannelDetailServiceImpl implements ChannelDetailService { + + @NonNull + private final ChannelDetailRepository channelDetailRepository; + + @Override + public List<ChannelDetail> findAll() { + return channelDetailRepository.findAll(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/impl/GuildEventDmerServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/guild/impl/GuildEventDmerServiceImpl.java @@ -0,0 +1,25 @@ +package com.sxcy.sxcybot.services.guild.impl; + +import com.sxcy.sxcybot.repository.guild.GuildEventDmerRepository; +import com.sxcy.sxcybot.repository.guild.dao.GuildEventDmer; +import com.sxcy.sxcybot.services.guild.GuildEventDmerService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class GuildEventDmerServiceImpl implements GuildEventDmerService { + + @NonNull + private final GuildEventDmerRepository guildEventDmerRepository; + + @Override + public List<GuildEventDmer> findAll() { + return guildEventDmerRepository.findAll(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/impl/GuildGuildRoleServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/guild/impl/GuildGuildRoleServiceImpl.java @@ -0,0 +1,52 @@ +package com.sxcy.sxcybot.services.guild.impl; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.guild.GuildRoleRepository; +import com.sxcy.sxcybot.repository.guild.dao.GuildRole; +import com.sxcy.sxcybot.services.guild.GuildRoleService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class GuildGuildRoleServiceImpl implements GuildRoleService { + + @NonNull + private final GuildRoleRepository guildRoleRepository; + + @Override + public List<GuildRole> findAllByElevationLessThanEqual(int elevation) { + return guildRoleRepository.findByElevationLessThanEqual(elevation); + } + + @Override + public List<GuildRole> findAllByElevationGreaterThanEqual(int elevation) { + return guildRoleRepository.findByElevationGreaterThanEqual(elevation); + } + + @Override + public GuildRole findByName(String name) throws EntityNotFoundException { + return guildRoleRepository.findByName(name).orElseThrow( + () -> new EntityNotFoundException(String.format("No role found with name %s.", name))); + } + + @Override + public GuildRole save(GuildRole guildRole) { + return guildRoleRepository.save(guildRole); + } + + @Override + public void delete(GuildRole guildRole) { + guildRoleRepository.delete(guildRole); + } + + @Override + public List<GuildRole> findAll() { + return guildRoleRepository.findAll(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/impl/PollServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/guild/impl/PollServiceImpl.java @@ -0,0 +1,41 @@ +package com.sxcy.sxcybot.services.guild.impl; + +import com.sxcy.sxcybot.repository.guild.PollRepository; +import com.sxcy.sxcybot.repository.guild.dao.Poll; +import com.sxcy.sxcybot.services.guild.PollService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +@Transactional +public class PollServiceImpl implements PollService { + + @NonNull + private final PollRepository pollRepository; + + @Override + public List<Poll> findAll() { + return pollRepository.findAll(); + } + + @Override + public Optional<Poll> findByMessageId(String messageId) { + return pollRepository.findByMessageId(messageId); + } + + @Override + public Poll save(Poll poll) { + return pollRepository.save(poll); + } + + @Override + public void delete(Poll poll) { + pollRepository.delete(poll); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/impl/RuleServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/guild/impl/RuleServiceImpl.java @@ -0,0 +1,42 @@ +package com.sxcy.sxcybot.services.guild.impl; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.guild.RuleRepository; +import com.sxcy.sxcybot.repository.guild.dao.Rule; +import com.sxcy.sxcybot.services.guild.RuleService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@RequiredArgsConstructor +@Transactional +public class RuleServiceImpl implements RuleService { + + @NonNull + private final RuleRepository ruleRepository; + + @Override + public List<Rule> findAll() { + return ruleRepository.findAll(); + } + + @Override + public Rule findByNumber(int number) throws EntityNotFoundException { + return ruleRepository.findByNumber(number).orElseThrow( + () -> new EntityNotFoundException(String.format("Rule with number %s not found.", number))); + } + + @Override + public Rule save(Rule rule) { + return ruleRepository.save(rule); + } + + @Override + public void delete(Rule rule) { + ruleRepository.delete(rule); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/impl/UserServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/guild/impl/UserServiceImpl.java @@ -0,0 +1,43 @@ +package com.sxcy.sxcybot.services.guild.impl; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.guild.UserRepository; +import com.sxcy.sxcybot.repository.guild.dao.User; +import com.sxcy.sxcybot.services.guild.UserService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@RequiredArgsConstructor +@Transactional +public class UserServiceImpl implements UserService { + + @NonNull + private final UserRepository userRepository; + + @Override + public List<User> findAllBanned() { + return userRepository.findAllByBannedTrue(); + } + + @Override + public User save(User user) { + return userRepository.save(user); + } + + @Override + public void delete(User user) throws EntityNotFoundException { + findByName(user.getName()); + userRepository.delete(user); + } + + @Override + public User findByName(String name) throws EntityNotFoundException { + return userRepository.findByName(name).orElseThrow( + () -> new EntityNotFoundException(String.format("No user found with name %s.", name))); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmKcSnapshotService.java b/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmKcSnapshotService.java @@ -0,0 +1,17 @@ +package com.sxcy.sxcybot.services.guild.pvmrole; + +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmKcSnapshot; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; + +import java.util.List; + +public interface PvmKcSnapshotService { + + List<PvmKcSnapshot> findAll(); + + List<PvmKcSnapshot> findAllByPvmRoleUser(PvmRoleUser pvmRoleUser); + + PvmKcSnapshot save(PvmKcSnapshot pvmKcSnapshot); + + void deleteAll(List<PvmKcSnapshot> pvmKcSnapshots); +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmRoleAssignerService.java b/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmRoleAssignerService.java @@ -0,0 +1,17 @@ +package com.sxcy.sxcybot.services.guild.pvmrole; + +import com.sxcy.sxcybot.enums.PvmRole; +import com.sxcy.sxcybot.repository.guild.dao.ChannelDetail; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.MessageChannel; + +import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; + +public interface PvmRoleAssignerService { + + void postScoreboardAndAssignRoles(Guild guild, MessageChannel textChannel, Map<PvmRole, LinkedHashMap<PvmRoleUser, BigDecimal>> scoreBoard, ChannelDetail channelDetail); + +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmRoleSnapshotComparerService.java b/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmRoleSnapshotComparerService.java @@ -0,0 +1,17 @@ +package com.sxcy.sxcybot.services.guild.pvmrole; + +import com.sxcy.sxcybot.enums.PvmRole; +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import net.dv8tion.jda.api.entities.MessageChannel; + +import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; + +public interface PvmRoleSnapshotComparerService { + + void updateScoreboard(PvmRoleUser pvmRoleUser, Map<PvmRole, LinkedHashMap<PvmRoleUser, BigDecimal>> scoreBoard); + + void saveSnapshot(MessageChannel textChannel, PvmRoleUser pvmRoleUser, boolean notify) throws EntityNotFoundException; +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmRoleUserService.java b/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/PvmRoleUserService.java @@ -0,0 +1,18 @@ +package com.sxcy.sxcybot.services.guild.pvmrole; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; + +import java.util.List; + +public interface PvmRoleUserService { + + List<PvmRoleUser> findAll(); + + PvmRoleUser save(PvmRoleUser pvmRoleUser); + + PvmRoleUser findByDiscordName(String discordName) throws EntityNotFoundException; + + void delete(PvmRoleUser pvmRoleUser); + +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmKcSnapshotServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmKcSnapshotServiceImpl.java @@ -0,0 +1,39 @@ +package com.sxcy.sxcybot.services.guild.pvmrole.impl; + +import com.sxcy.sxcybot.repository.guild.pvmrole.PvmKcSnapshotRepository; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmKcSnapshot; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmKcSnapshotService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class PvmKcSnapshotServiceImpl implements PvmKcSnapshotService { + + private final PvmKcSnapshotRepository pvmKcSnapshotRepository; + + @Override + public List<PvmKcSnapshot> findAll() { + return pvmKcSnapshotRepository.findAll(); + } + + @Override + public List<PvmKcSnapshot> findAllByPvmRoleUser(PvmRoleUser pvmRoleUser) { + return pvmKcSnapshotRepository.findAllByPvmRoleUserId(pvmRoleUser.getId()); + } + + @Override + public PvmKcSnapshot save(PvmKcSnapshot pvmKcSnapshot) { + return pvmKcSnapshotRepository.save(pvmKcSnapshot); + } + + @Override + public void deleteAll(List<PvmKcSnapshot> pvmKcSnapshots) { + pvmKcSnapshotRepository.deleteAll(pvmKcSnapshots); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmRoleAssignerServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmRoleAssignerServiceImpl.java @@ -0,0 +1,97 @@ +package com.sxcy.sxcybot.services.guild.pvmrole.impl; + +import com.sxcy.sxcybot.enums.PvmRole; +import com.sxcy.sxcybot.repository.guild.dao.ChannelDetail; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleAssignerService; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.Role; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.awt.Color; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Service +@Transactional +@RequiredArgsConstructor +public class PvmRoleAssignerServiceImpl implements PvmRoleAssignerService { + + @Override + public void postScoreboardAndAssignRoles(Guild guild, MessageChannel textChannel, Map<PvmRole, LinkedHashMap<PvmRoleUser, BigDecimal>> scoreBoard, ChannelDetail channelDetail) { + for (PvmRole pvmRole : scoreBoard.keySet()) { + String rolename = getRolename(pvmRole, channelDetail); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.red); + embedBuilder.setTitle(String.format("**%s** Scoreboard results:", rolename)); + if (scoreBoard.get(pvmRole).isEmpty()) { + embedBuilder.addField(String.format("No KC gains detected for %s", pvmRole.name().toLowerCase()), "No increase in KC found for participants, role will remain unchanged.", false); + textChannel.sendMessage(embedBuilder.build()).queue(); + continue; + } + List<Map.Entry<PvmRoleUser, BigDecimal>> entries = new ArrayList<>(scoreBoard.get(pvmRole).entrySet()); + entries.sort(Map.Entry.comparingByValue(Comparator.reverseOrder())); + scoreBoard.get(pvmRole).clear(); + entries.forEach(f -> scoreBoard.get(pvmRole).put(f.getKey(), f.getValue())); + guild.loadMembers().onSuccess(memberlist -> { + long limit = 5; + int i = 1; + for (Map.Entry<PvmRoleUser, BigDecimal> entry : scoreBoard.get(pvmRole).entrySet()) { + if (limit-- == 0) break; + Optional<Member> member = memberlist.stream().filter(f -> entry.getKey().getDiscordName().equalsIgnoreCase(f.getUser().getName()) || entry.getKey().getDiscordName().equalsIgnoreCase(f.getNickname())).findFirst(); + if (member.isPresent()) { + embedBuilder.addField(String.format("#%s %s", i, entry.getKey().getRsn()), String.format("%s with a score of %s!", member.get(), entry.getValue()), false); + if (i == 1) { + Optional<Role> role = guild.getRoles().stream().filter(f -> rolename.equalsIgnoreCase(f.getName())).findFirst(); + if (role.isPresent()) { + guild.findMembersWithRoles(role.get()) + .onSuccess(oldWinners -> { + if (oldWinners.isEmpty()) { + addRoleToWinner(guild, member.get(), role.get(), textChannel, entry.getKey().getRsn()); + } else { + oldWinners.forEach(f -> guild.removeRoleFromMember(f, role.get()).queue(complete -> + addRoleToWinner(guild, member.get(), role.get(), textChannel, entry.getKey().getRsn()))); + } + }); + } else { + textChannel.sendMessage(String.format("No role %s found in the channel, role could not get assigned.", rolename)).queue(); + } + } + } else { + textChannel.sendMessage(String.format("No guildmember found for discordname %s. User did not receive any awards.", entry.getKey().getDiscordName())).queue(); + } + i++; + } + textChannel.sendMessage(embedBuilder.build()).queue(); + }); + } + } + + private String getRolename(PvmRole pvmRole, ChannelDetail channelDetail) { + switch (pvmRole) { + case GENERAL: + return channelDetail.getPvmRoleGeneral(); + case RAIDS: + return channelDetail.getPvmRoleRaids(); + case WILDERNESS: + return channelDetail.getPvmRoleWilderness(); + default: + return "Something went wrong."; + } + } + + private void addRoleToWinner(Guild guild, Member member, Role role, MessageChannel textChannel, String rsn) { + guild.addRoleToMember(member, role).queue(ok -> + textChannel.sendMessage(String.format("%s is our new %s!", rsn, role)).queue()); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmRoleSnapshotComparerServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmRoleSnapshotComparerServiceImpl.java @@ -0,0 +1,93 @@ +package com.sxcy.sxcybot.services.guild.pvmrole.impl; + +import com.sxcy.sxcybot.client.HiScoreClient; +import com.sxcy.sxcybot.enums.PvmRole; +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.model.OsrsBossKc; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmKcSnapshot; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmUserKc; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmKcSnapshotService; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleSnapshotComparerService; +import com.sxcy.sxcybot.services.osrs.OsrsHiscoreBossService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.MessageChannel; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@Transactional +@RequiredArgsConstructor +public class PvmRoleSnapshotComparerServiceImpl implements PvmRoleSnapshotComparerService { + + @NonNull + private final OsrsHiscoreBossService osrsHiscoreBossService; + @NonNull + private final PvmKcSnapshotService pvmKcSnapshotService; + @NonNull + private final HiScoreClient hiScoreClient; + + @Override + public void updateScoreboard(PvmRoleUser pvmRoleUser, Map<PvmRole, LinkedHashMap<PvmRoleUser, BigDecimal>> scoreBoard) { + List<PvmKcSnapshot> pvmKcSnapshots = pvmKcSnapshotService.findAllByPvmRoleUser(pvmRoleUser); + if (pvmKcSnapshots != null && pvmKcSnapshots.size() > 1) { + pvmKcSnapshots = pvmKcSnapshots.stream() + .sorted(Comparator.comparing(PvmKcSnapshot::getCreatedDate) + .reversed()) + .limit(2) + .collect(Collectors.toList()); + for (PvmRole pvmRole : PvmRole.values()) { + BigDecimal points1 = calculatePoints(pvmRole, pvmKcSnapshots.get(0)); + BigDecimal points2 = calculatePoints(pvmRole, pvmKcSnapshots.get(1)); + BigDecimal result = points1.subtract(points2); + if (BigDecimal.ZERO.compareTo(result) < 0) + scoreBoard.get(pvmRole).put(pvmRoleUser, result); + } + } + } + + private BigDecimal calculatePoints(PvmRole pvmRole, PvmKcSnapshot pvmKcSnapshot) { + BigDecimal points = BigDecimal.ZERO; + for (PvmUserKc pvmUserKc : pvmKcSnapshot.getPvmUserKcList().stream().filter(f -> pvmRole.value == f.getOsrsHiscoreBoss().getPvmRole()).collect(Collectors.toList())) { + points = points.add(BigDecimal.valueOf(pvmUserKc.getOsrsHiscoreBoss().getMultiplier()).multiply(BigDecimal.valueOf(pvmUserKc.getKc()))); + } + return points; + } + + @Override + public void saveSnapshot(MessageChannel textChannel, PvmRoleUser pvmRoleUser, boolean notify) throws EntityNotFoundException { + PvmKcSnapshot pvmKcSnapshot = PvmKcSnapshot.builder() + .pvmRoleUser(pvmRoleUser) + .build(); + List<OsrsBossKc> osrsBossKcList = hiScoreClient.getHiScoreBossKc(pvmRoleUser.getRsn(), textChannel).orElseThrow( + () -> new EntityNotFoundException(String.format("No hiScores found for %s", pvmRoleUser.getRsn())) + ); + List<PvmUserKc> pvmUserKcList = new ArrayList<>(); + for (OsrsBossKc osrsBossKc : osrsBossKcList.stream().filter(r -> Integer.parseInt(r.getKc()) > 0).collect(Collectors.toList())) { + try { + PvmUserKc pvmUserKc = PvmUserKc.builder() + .pvmRoleUser(pvmRoleUser) + .osrsHiscoreBoss(osrsHiscoreBossService.findByName(osrsBossKc.getName())) + .pvmKcSnapshot(pvmKcSnapshot) + .kc(Integer.valueOf(osrsBossKc.getKc())) + .build(); + pvmUserKcList.add(pvmUserKc); + } catch (EntityNotFoundException e) { + e.printStackTrace(); + } + } + pvmKcSnapshot.setPvmUserKcList(pvmUserKcList); + pvmKcSnapshotService.save(pvmKcSnapshot); + if (notify) + textChannel.sendMessage(String.format("KC snapshot saved for %s.%n", pvmRoleUser.getRsn())).queue(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmRoleUserServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/guild/pvmrole/impl/PvmRoleUserServiceImpl.java @@ -0,0 +1,44 @@ +package com.sxcy.sxcybot.services.guild.pvmrole.impl; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.guild.pvmrole.PvmRoleUserRepository; +import com.sxcy.sxcybot.repository.guild.pvmrole.dao.PvmRoleUser; +import com.sxcy.sxcybot.services.guild.pvmrole.PvmRoleUserService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static com.sxcy.sxcybot.enums.Command.PVMLIST; +import static com.sxcy.sxcybot.util.Constants.Commands.COMMAND_PREFIX; + +@Service +@RequiredArgsConstructor +public class PvmRoleUserServiceImpl implements PvmRoleUserService { + + @NonNull + private final PvmRoleUserRepository pvmRoleUserRepository; + + @Override + public List<PvmRoleUser> findAll() { + return pvmRoleUserRepository.findAll(); + } + + @Override + public PvmRoleUser save(PvmRoleUser pvmRoleUser) { + return pvmRoleUserRepository.save(pvmRoleUser); + } + + @Override + public PvmRoleUser findByDiscordName(String discordName) throws EntityNotFoundException { + return pvmRoleUserRepository.findByDiscordName(discordName).orElseThrow(() + -> new EntityNotFoundException(String.format("No discord user found with name %s in the PvM competition.%sYou can check all competitors with the \"%s\" command." + , discordName, System.lineSeparator(), COMMAND_PREFIX + PVMLIST.name().toLowerCase()))); + } + + @Override + public void delete(PvmRoleUser pvmRoleUser) { + pvmRoleUserRepository.delete(pvmRoleUser); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/osrs/CombatCalculatorService.java b/src/main/java/com/sxcy/sxcybot/services/osrs/CombatCalculatorService.java @@ -0,0 +1,8 @@ +package com.sxcy.sxcybot.services.osrs; + +import com.sxcy.sxcybot.model.CombatDto; + +public interface CombatCalculatorService { + + double getCombatLevel(CombatDto combatDto); +} diff --git a/src/main/java/com/sxcy/sxcybot/services/osrs/OsrsHiscoreBossService.java b/src/main/java/com/sxcy/sxcybot/services/osrs/OsrsHiscoreBossService.java @@ -0,0 +1,13 @@ +package com.sxcy.sxcybot.services.osrs; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.osrs.dao.OsrsHiscoreBoss; + +import java.util.List; + +public interface OsrsHiscoreBossService { + + List<OsrsHiscoreBoss> findAll(); + + OsrsHiscoreBoss findByName(String name) throws EntityNotFoundException; +} diff --git a/src/main/java/com/sxcy/sxcybot/services/osrs/OsrsHiscoreStatService.java b/src/main/java/com/sxcy/sxcybot/services/osrs/OsrsHiscoreStatService.java @@ -0,0 +1,10 @@ +package com.sxcy.sxcybot.services.osrs; + +import com.sxcy.sxcybot.repository.osrs.dao.OsrsHiscoreStat; + +import java.util.List; + +public interface OsrsHiscoreStatService { + + List<OsrsHiscoreStat> findAll(); +} diff --git a/src/main/java/com/sxcy/sxcybot/services/osrs/StatMessageSender.java b/src/main/java/com/sxcy/sxcybot/services/osrs/StatMessageSender.java @@ -0,0 +1,15 @@ +package com.sxcy.sxcybot.services.osrs; + +import com.sxcy.sxcybot.model.OsrsStat; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public interface StatMessageSender { + + void sendStatMessage(MessageReceivedEvent event, EmbedBuilder embedBuilder, Predicate<OsrsStat> predicate, Consumer<OsrsStat> consumer, Consumer<List<OsrsStat>> calcCombatLevel); + +} diff --git a/src/main/java/com/sxcy/sxcybot/services/osrs/impl/CombatCalculatorServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/osrs/impl/CombatCalculatorServiceImpl.java @@ -0,0 +1,31 @@ +package com.sxcy.sxcybot.services.osrs.impl; + +import com.sxcy.sxcybot.model.CombatDto; +import com.sxcy.sxcybot.services.osrs.CombatCalculatorService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +@Service +@Transactional +public class CombatCalculatorServiceImpl implements CombatCalculatorService { + + @Override + public double getCombatLevel(CombatDto combatDto) { + double base = 0.25 * (combatDto.getDefenceLevel() + combatDto.getHitpointsLevel() + (combatDto.getPrayerLevel() / 2)); + + double typeContribution = getMeleeRangeOrMagicCombatLevelContribution(combatDto.getAttackLevel(), combatDto.getStrengthLevel(), combatDto.getMagicLevel(), combatDto.getRangeLevel()); + + return BigDecimal.valueOf(base + typeContribution).setScale(3, RoundingMode.HALF_UP).doubleValue(); + } + + private double getMeleeRangeOrMagicCombatLevelContribution(int attackLevel, int strengthLevel, int magicLevel, int rangeLevel) { + double melee = 0.325 * (attackLevel + strengthLevel); + double range = 0.325 * (rangeLevel / 2 + rangeLevel); + double magic = 0.325 * (magicLevel / 2 + magicLevel); + + return Math.max(melee, Math.max(range, magic)); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/osrs/impl/OsrsHiscoreBossServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/osrs/impl/OsrsHiscoreBossServiceImpl.java @@ -0,0 +1,32 @@ +package com.sxcy.sxcybot.services.osrs.impl; + +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.repository.osrs.OsrsHiscoreBossRepository; +import com.sxcy.sxcybot.repository.osrs.dao.OsrsHiscoreBoss; +import com.sxcy.sxcybot.services.osrs.OsrsHiscoreBossService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class OsrsHiscoreBossServiceImpl implements OsrsHiscoreBossService { + + @NonNull + private final OsrsHiscoreBossRepository osrsHiscoreBossRepository; + + @Override + public List<OsrsHiscoreBoss> findAll() { + return osrsHiscoreBossRepository.findAll(); + } + + @Override + public OsrsHiscoreBoss findByName(String name) throws EntityNotFoundException { + return osrsHiscoreBossRepository.findByName(name).orElseThrow( + () -> new EntityNotFoundException(String.format("No hiscoreBoss found with name %s.", name))); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/osrs/impl/OsrsHiscoreStatServiceImpl.java b/src/main/java/com/sxcy/sxcybot/services/osrs/impl/OsrsHiscoreStatServiceImpl.java @@ -0,0 +1,25 @@ +package com.sxcy.sxcybot.services.osrs.impl; + +import com.sxcy.sxcybot.repository.osrs.OsrsHiscoreStatRepository; +import com.sxcy.sxcybot.repository.osrs.dao.OsrsHiscoreStat; +import com.sxcy.sxcybot.services.osrs.OsrsHiscoreStatService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class OsrsHiscoreStatServiceImpl implements OsrsHiscoreStatService { + + @NonNull + private final OsrsHiscoreStatRepository osrsHiscoreStatRepository; + + @Override + public List<OsrsHiscoreStat> findAll() { + return osrsHiscoreStatRepository.findAll(); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/services/osrs/impl/StatMessageSenderImpl.java b/src/main/java/com/sxcy/sxcybot/services/osrs/impl/StatMessageSenderImpl.java @@ -0,0 +1,50 @@ +package com.sxcy.sxcybot.services.osrs.impl; + +import com.sxcy.sxcybot.client.HiScoreClient; +import com.sxcy.sxcybot.exceptions.EntityNotFoundException; +import com.sxcy.sxcybot.model.OsrsStat; +import com.sxcy.sxcybot.services.osrs.StatMessageSender; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.awt.Color; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; + +@Service +@RequiredArgsConstructor +@Transactional +public class StatMessageSenderImpl implements StatMessageSender { + + @NonNull + private final HiScoreClient hiScoreClient; + + public void sendStatMessage(MessageReceivedEvent event, EmbedBuilder embedBuilder, + Predicate<OsrsStat> predicate, Consumer<OsrsStat> consumer + , Consumer<List<OsrsStat>> calcCombatLevel) { + String msg = event.getMessage().getContentRaw(); + try { + String player = msg.substring(msg.indexOf(" ")).trim(); + try { + embedBuilder.setColor(Color.RED); + embedBuilder.setTitle(String.format("Stats of %s", player)); + List<OsrsStat> osrsStatList = hiScoreClient.getHiScoreStats(player, event.getChannel()).orElseThrow(() + -> new EntityNotFoundException(String.format("No HiScores found for %s.", player))); + osrsStatList.stream().filter(predicate).forEach(consumer); + if (calcCombatLevel != null) { + calcCombatLevel.accept(osrsStatList); + } + event.getChannel().sendMessage(embedBuilder.build()).queue(); + } catch (EntityNotFoundException entityNotFoundException) { + event.getChannel().sendMessage(entityNotFoundException.getMessage()).queue(); + } + } catch (StringIndexOutOfBoundsException e) { + event.getChannel().sendMessage("Please enter a player name after the command, separated by space.").queue(); + } + } +} diff --git a/src/main/java/com/sxcy/sxcybot/util/Constants.java b/src/main/java/com/sxcy/sxcybot/util/Constants.java @@ -0,0 +1,34 @@ +package com.sxcy.sxcybot.util; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class Constants { + + public static final int ADDED_ROLE_ELEVATION = 100; + + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public static class Commands { + + public static final String COMMAND_PREFIX = "sb-"; + public static final String BB8 = COMMAND_PREFIX + "8"; + } + + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public static class Emoji { + + public static final String THUMBS_UP = ":+1:"; + public static final String FLAMES = ":flame:"; + } + + @NoArgsConstructor(access = AccessLevel.PRIVATE) + public static class Reaction { + + public static final String CHECK_MARK = "U+2714"; + public static final String CROSS_MARK = "U+274C"; + public static final String QUESTION_MARK = "U+2753"; + public static final String CHECK_MARK_BUTTON = "U+2705"; + public static final String CROSS_MARK_BUTTON = "U+274E"; + } +} diff --git a/src/main/java/com/sxcy/sxcybot/util/CustomPollFiller.java b/src/main/java/com/sxcy/sxcybot/util/CustomPollFiller.java @@ -0,0 +1,79 @@ +package com.sxcy.sxcybot.util; + +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.repository.guild.dao.Poll; +import com.sxcy.sxcybot.services.guild.PollService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.awt.Color; +import java.util.Set; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +@RequiredArgsConstructor +public class CustomPollFiller { + + @NonNull + private final EventWaiterUtil eventWaiterUtil; + @NonNull + private final PollService pollService; + private static final String STOP_WORD = "stop"; + +// private static final String EMOJI_REGEX = "([\\u20a0-\\u32ff\\ud83c\\udc00-\\ud83d\\udeff\\udbb9\\udce5-\\udbb9\\udcee])"; + + public void fillPoll(PrivateChannel privateChannel, MessageReceivedEvent event, EmbedBuilder embedBuilder, Set<String> emojiList) { + EmbedBuilder embeddedOption = new EmbedBuilder(); + embeddedOption.setColor(Color.RED); + embeddedOption.addField("Please enter an option for the poll", "`stop` to finish and create the poll.", false); + privateChannel.sendMessage(embeddedOption.build()).queue(); + embeddedOption.clear(); + eventWaiterUtil.waitForPrivateChannelEvent(optionReceiver -> { + if (isReadyToStop(optionReceiver)) { + event.getChannel().sendTyping().queue(typing -> + event.getChannel().sendMessage(embedBuilder.build()).queue(message -> { + emojiList.forEach(emoji -> message.addReaction(emoji).queue()); + pollService.save(Poll.builder().messageId(message.getId()).build()); + })); + return; + } + embeddedOption.setColor(Color.RED); + embeddedOption.addField(String.format("Please type in a reaction emoji for _%s_.", optionReceiver.getMessage().getContentRaw()), "", false); + privateChannel.sendMessage(embeddedOption.build()).queue(); + embeddedOption.clear(); + eventWaiterUtil.waitForPrivateChannelEvent(emojiReceiver -> { + if (!emojiList.contains(emojiReceiver.getMessage().getContentRaw())) { + if (!isValidEmoji(emojiReceiver.getMessage().getContentRaw())) { + privateChannel.sendMessage(String.format("%s is not a valid emoji, please retry this option.", emojiReceiver.getMessage().getContentRaw())).queue(); + this.fillPoll(privateChannel, event, embedBuilder, emojiList); + return; + } + embedBuilder.addField(String.format("%s %s %s", emojiReceiver.getMessage().getContentRaw(), optionReceiver.getMessage().getContentRaw(), "(0)"), "", true); + emojiList.add(emojiReceiver.getMessage().getContentRaw()); + } else { + privateChannel.sendMessage(String.format("Emoji %s was already picked for another options, please retry this option.", emojiReceiver.getMessage().getContentRaw())).queue(); + } + this.fillPoll(privateChannel, event, embedBuilder, emojiList); + }, event, privateChannel); + }, event, privateChannel); + } + + private boolean isReadyToStop(PrivateMessageReceivedEvent privateMessageReceivedEvent) { + return privateMessageReceivedEvent.getMessage().getContentRaw().equalsIgnoreCase(STOP_WORD); + } + + private boolean isValidEmoji(String emoji) { + /* + TODO fix: + return Pattern.compile(EMOJI_REGEX).matcher(emoji).find(); + */ + return true; + } +} diff --git a/src/main/java/com/sxcy/sxcybot/util/DiscordMemberFinderUtil.java b/src/main/java/com/sxcy/sxcybot/util/DiscordMemberFinderUtil.java @@ -0,0 +1,50 @@ +package com.sxcy.sxcybot.util; + +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.springframework.stereotype.Component; + +import java.util.Optional; +import java.util.function.Consumer; + +@Component +@RequiredArgsConstructor +public class DiscordMemberFinderUtil { + + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + public void onMemberFoundVerification(MessageReceivedEvent event, EmbedBuilder embedBuilder, PrivateChannel privateChannel, Consumer<Member> memberConsumer) { + embedBuilder.addField("Type the name of the user.", "Discord username will be looked up first, if no match is found it will search on nickname.", false); + privateChannel.sendMessage(embedBuilder.build()).queue(); + eventWaiterUtil.waitForPrivateChannelEvent(memberReceiver -> { + String name = memberReceiver.getMessage().getContentRaw(); + event.getGuild().loadMembers().onSuccess(memberList -> { + if (memberList.isEmpty()) { + privateChannel.sendMessage(String.format("User with name %s not found, please try again later.", name)).queue(); + } else { + Optional<Member> member = memberList.stream().filter(f -> name.equalsIgnoreCase(f.getUser().getName()) || name.equalsIgnoreCase(f.getNickname())).findFirst(); + if (member.isPresent()) { + embedBuilder.clearFields(); + embedBuilder.addField("Confirm by typing ``yes or y``.", String.format("Is %s the correct member?", member.get()), false); + privateChannel.sendMessage(embedBuilder.build()).queue(); + eventWaiterUtil.waitForPrivateChannelEvent(memberVerifyReceiver -> { + String verifyMessage = memberVerifyReceiver.getMessage().getContentRaw(); + if ("y".equalsIgnoreCase(verifyMessage) || "yes".equalsIgnoreCase(verifyMessage)) { + memberConsumer.accept(member.get()); + } + embedBuilder.clearFields(); + }, event, privateChannel); + } else { + privateChannel.sendMessage(String.format("User with name %s not found, please try again later.", name)).queue(); + } + } + }); + }, event, privateChannel); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/util/EditListenerUtil.java b/src/main/java/com/sxcy/sxcybot/util/EditListenerUtil.java @@ -0,0 +1,47 @@ +package com.sxcy.sxcybot.util; + +import com.sxcy.sxcybot.listeners.EventWaiterUtil; +import com.sxcy.sxcybot.model.EditListenerDto; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import org.springframework.stereotype.Component; + +import java.awt.Color; + +@Component +@RequiredArgsConstructor +public class EditListenerUtil { + + @NonNull + private final EventWaiterUtil eventWaiterUtil; + + public void procesEditEvent(EditListenerDto editListenerDto) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.red); + embedBuilder.setTitle("What do you want to do?"); + embedBuilder.addField("1", String.format("Add a new %s.", editListenerDto.getEntityName()), false); + embedBuilder.addField("2", String.format("Delete an existing %s.", editListenerDto.getEntityName()), false); + if (editListenerDto.getUpdateListener() != null) + embedBuilder.addField("3", String.format("Update an existing %s.", editListenerDto.getEntityName()), false); + editListenerDto.getPrivateChannel().sendMessage(embedBuilder.build()).queue(); + eventWaiterUtil.waitForPrivateChannelEvent(commandReceiver -> { + switch (commandReceiver.getMessage().getContentRaw()) { + case "1": + editListenerDto.getAddListener().proces(commandReceiver, editListenerDto.getEvent()); + break; + case "2": + editListenerDto.getDeleteListener().proces(commandReceiver, editListenerDto.getEvent()); + break; + case "3": + if (editListenerDto.getUpdateListener() != null) + editListenerDto.getUpdateListener().proces(commandReceiver, editListenerDto.getEvent()); + break; + default: + editListenerDto.getPrivateChannel().sendMessage("Unknown command, please try again.").queue(); + break; + } + }, editListenerDto.getEvent(), editListenerDto.getPrivateChannel()); + } + +} diff --git a/src/main/java/com/sxcy/sxcybot/util/JdaUtil.java b/src/main/java/com/sxcy/sxcybot/util/JdaUtil.java @@ -0,0 +1,37 @@ +package com.sxcy.sxcybot.util; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.react.GenericMessageReactionEvent; +import org.springframework.stereotype.Component; + +@Component +public class JdaUtil { + + public static String getName(GenericMessageReactionEvent event) { + if (event.getMember() != null && event.getMember().getNickname() != null) { + return event.getMember().getNickname(); + } else if (event.getUser() != null) { + return event.getUser().getName(); + } + return null; + } + + public static String getName(MessageReceivedEvent event) { + if (event.getMember() != null && event.getMember().getNickname() != null) { + return event.getMember().getNickname(); + } else if (event.getMember() != null) { + return event.getMember().getUser().getName(); + } + return null; + } + + public static User getUser(MessageReceivedEvent event) { + return event.getMember() != null ? event.getMember().getUser() : null; + } + + public static boolean requiresBuild(EmbedBuilder embedBuilder, int size, int count) { + return (embedBuilder.length() > 5000 || embedBuilder.getFields().size() == 25 || size == count); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/util/NumberFormatter.java b/src/main/java/com/sxcy/sxcybot/util/NumberFormatter.java @@ -0,0 +1,15 @@ +package com.sxcy.sxcybot.util; + +import java.text.NumberFormat; +import java.util.Locale; + +public class NumberFormatter { + + public static String format(String numberToFormat) { + return format(Integer.valueOf(numberToFormat)); + } + + public static String format(Integer numberToFormat) { + return NumberFormat.getNumberInstance(Locale.UK).format(numberToFormat); + } +} diff --git a/src/main/java/com/sxcy/sxcybot/util/ReleaseNotesUtil.java b/src/main/java/com/sxcy/sxcybot/util/ReleaseNotesUtil.java @@ -0,0 +1,48 @@ +package com.sxcy.sxcybot.util; + + +import com.sxcy.sxcybot.services.guild.ChannelDetailService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.JDA; +import org.springframework.stereotype.Component; + +import java.awt.*; +import java.time.LocalDate; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +@Component +@RequiredArgsConstructor +public class ReleaseNotesUtil { + + @NonNull + private final ChannelDetailService channelDetailService; + + private static final String GITLAB_URL = "https://gitlab.com/WimDupont/sxcybot"; + + public void showReleaseNotes(JDA jda) { + Map<String, String> releaseNotes = ReleaseNotesUtil.getReleaseNotes(); + if (!releaseNotes.isEmpty()) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.RED); + embedBuilder.setTitle(String.format("Latest updates %s", LocalDate.now()), GITLAB_URL); + for (Entry<String, String> entry : releaseNotes.entrySet()) { + embedBuilder.addField(entry.getKey(), entry.getValue(), false); + } + + channelDetailService.findAll().stream().findAny() + .ifPresent(detail -> jda.getTextChannelsByName(detail.getBotUpdateChannel(), false).forEach(f -> + f.sendMessage(embedBuilder.build()).queue() + )); + } + } + + private static Map<String, String> getReleaseNotes() { + Map<String, String> releaseNotes = new LinkedHashMap<>(); + releaseNotes.put("Update Bosses HiScores", "Bosses HiScores has been updated to also include ToB: Hard Mode. This will fix the current faulty kc's."); + return releaseNotes; + } +} diff --git a/src/main/java/com/sxcy/sxcybot/util/SpringSecurityAuditorAware.java b/src/main/java/com/sxcy/sxcybot/util/SpringSecurityAuditorAware.java @@ -0,0 +1,20 @@ +package com.sxcy.sxcybot.util; + + +import org.springframework.data.domain.AuditorAware; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class SpringSecurityAuditorAware implements AuditorAware<String> { + /** + * Returns the current auditor of the application. + * + * @return the current auditor + */ + @Override + public Optional<String> getCurrentAuditor() { + return Optional.empty(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties @@ -0,0 +1,19 @@ +spring.datasource.url=jdbc:mariadb://localhost:3306/sxcybot +spring.datasource.driver-class-name=org.mariadb.jdbc.Driver +spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect +spring.jpa.generate-ddl=true +spring.jpa.hibernate.ddl-auto=update +spring.flyway.url=jdbc:mariadb://localhost:3306/sxcybot +#Every Month at 1 AM (server time) +#0 0 1 1 * * +#Every 20 sec +#*/20 * * * * * +pvm.role.schedule=0 0 1 1 * * + +##### add to profile properties: ##### +#spring.datasource.username= +#spring.datasource.password= +#spring.flyway.user= +#spring.flyway.password= +#discord.bot.token= +#server.port=8080 diff --git a/src/main/resources/db/migration/V1_0__db-init.sql b/src/main/resources/db/migration/V1_0__db-init.sql @@ -0,0 +1,87 @@ +CREATE TABLE rule ( + id VARCHAR(36) primary key NOT NULL, + `number` SMALLINT(6) NOT NULL UNIQUE, + description VARCHAR(500) DEFAULT NULL +); + +CREATE TABLE user ( + id VARCHAR(36) primary key NOT NULL, + name VARCHAR(100) NOT NULL UNIQUE, + description VARCHAR(1000) DEFAULT NULL, + banned TINYINT(1) DEFAULT 0, + created_date DATE, + created_by VARCHAR(50), + last_modified_date DATE, + last_modified_by VARCHAR(50) +); + +CREATE TABLE poll ( + id VARCHAR(36) primary key NOT NULL, + message_id VARCHAR(100) NOT NULL UNIQUE, + created_date DATE, + last_modified_date DATE +); + +CREATE TABLE guild_role ( + id VARCHAR(36) primary key NOT NULL, + name VARCHAR(100) NOT NULL UNIQUE, + order_value INT, + elevation INT NOT NULL +); + +CREATE TABLE channel_detail ( + id VARCHAR(36) primary key NOT NULL, + forum_url VARCHAR(500), + bot_update_channel VARCHAR(100), + pvm_role_channel VARCHAR(100), + pvm_role_general VARCHAR(100), + pvm_role_raids VARCHAR(100), + pvm_role_wilderness VARCHAR(100) +); + +CREATE TABLE osrs_hiscore_stat ( + id VARCHAR(36) primary key NOT NULL, + name VARCHAR(100) NOT NULL, + order_value INT NOT NULL +); + +CREATE TABLE osrs_hiscore_boss ( + id VARCHAR(36) primary key NOT NULL, + name VARCHAR(100) NOT NULL, + multiplier DECIMAL DEFAULT 0, + order_value INT NOT NULL, + pvm_role INT DEFAULT 0 +); + +CREATE TABLE pvm_kc_snapshot ( + id VARCHAR(36) primary key NOT NULL, + created_date DATETIME, + last_modified_date DATETIME +); + +CREATE TABLE pvm_role_user ( + id VARCHAR(36) primary key NOT NULL, + discord_name VARCHAR(100) NOT NULL UNIQUE, + rsn VARCHAR(100) NOT NULL UNIQUE, + created_date DATETIME, + created_by VARCHAR(50), + last_modified_date DATETIME, + last_modified_by VARCHAR(50) +); + +CREATE TABLE pvm_user_kc ( + id VARCHAR(36) primary key NOT NULL, + pvm_role_user_id VARCHAR(36), + CONSTRAINT fk_pvmroleuser FOREIGN KEY (pvm_role_user_id) REFERENCES pvm_role_user (id), + osrs_hiscore_boss_id VARCHAR(36), + CONSTRAINT fk_osrshiscoreboss FOREIGN KEY (osrs_hiscore_boss_id) REFERENCES osrs_hiscore_boss (id), + pvm_kc_snapshot_id VARCHAR(36), + CONSTRAINT fk_pvmkcsnapshot FOREIGN KEY (pvm_kc_snapshot_id) REFERENCES pvm_kc_snapshot (id), + created_date DATETIME, + last_modified_date DATETIME +); + +CREATE TABLE guild_event_dmer ( + id VARCHAR(36) primary key NOT NULL, + name VARCHAR(100) NOT NULL UNIQUE +); diff --git a/src/main/resources/db/migration/V1_1__insert_osrs_values.sql b/src/main/resources/db/migration/V1_1__insert_osrs_values.sql @@ -0,0 +1,75 @@ +INSERT INTO osrs_hiscore_stat +VALUES + (UUID(),"Overall", 0), + (UUID(),"Attack", 1), + (UUID(),"Defence", 2), + (UUID(),"Strength", 3), + (UUID(),"Hitpoints", 4), + (UUID(),"Ranged", 5), + (UUID(),"Prayer", 6), + (UUID(),"Magic", 7), + (UUID(),"Cooking", 8), + (UUID(),"Woodcutting", 9), + (UUID(),"Fletching", 10), + (UUID(),"Fishing", 11), + (UUID(),"Firemaking", 12), + (UUID(),"Crafting", 13), + (UUID(),"Smithing", 14), + (UUID(),"Mining", 15), + (UUID(),"Herblore", 16), + (UUID(),"Agility", 17), + (UUID(),"Thieving", 18), + (UUID(),"Slayer", 19), + (UUID(),"Farming", 20), + (UUID(),"Runecrafting", 21), + (UUID(),"Hunter", 22), + (UUID(),"Construction", 23) +; +INSERT INTO osrs_hiscore_boss +VALUES + (UUID(),"Abyssal Sire", 1, 36, 1), + (UUID(),"Alchemical Hydra", 1, 37, 1), + (UUID(),"Barrows Chests", 1, 38, 1), + (UUID(),"Bryophyta", 1, 39, 1), + (UUID(),"Callisto", 1, 40, 3), + (UUID(),"Cerberus", 1, 41, 1), + (UUID(),"Chambers of Xeric", 1, 42, 2), + (UUID(),"Chambers of Xeric: Challenge Mode", 1, 43, 2), + (UUID(),"Chaos Elemental", 1, 44, 3), + (UUID(),"Chaos Fanatic", 1, 45, 3), + (UUID(),"Commander Zilyana", 1, 46, 1), + (UUID(),"Corporeal Beast", 1, 47, 1), + (UUID(),"Crazy Archaeologist", 1, 48, 3), + (UUID(),"Dagannoth Prime", 1, 49, 1), + (UUID(),"Dagannoth Rex", 1, 50, 1), + (UUID(),"Dagannoth Supreme", 1, 51, 1), + (UUID(),"Deranged Archaeologist", 1, 52, 1), + (UUID(),"General Graardor", 1, 53, 1), + (UUID(),"Giant Mole", 1, 54, 1), + (UUID(),"Grotesque Guardians", 1, 55, 1), + (UUID(),"Hespori", 1, 56, 1), + (UUID(),"Kalphite Queen", 1, 57, 1), + (UUID(),"King Black Dragon", 1, 58, 1), + (UUID(),"Kraken", 1, 59, 1), + (UUID(),"Kree' Arra", 1, 60, 1), + (UUID(),"K'ril Tsutsaroth", 1, 61, 1), + (UUID(),"Mimic", 1, 62, 1), + (UUID(),"Nightmare", 1, 63, 1), + (UUID(),"Obor", 1, 64, 1), + (UUID(),"Sarachnis", 1, 65, 1), + (UUID(),"Scorpia", 1, 66, 3), + (UUID(),"Skotizo", 1, 67, 1), + (UUID(),"Tempoross", 1, 68, 0), + (UUID(),"The Gauntlet", 1, 69, 1), + (UUID(),"The Corrupted Gauntlet", 1, 70, 1), + (UUID(),"Theatre of Blood", 1, 71, 2), + (UUID(),"Thermonuclear Smoke Devil", 1, 72, 1), + (UUID(),"TzKal-Zuk", 1, 73, 1), + (UUID(),"TzTok-Jad", 1, 74, 1), + (UUID(),"Venenatis", 1, 75, 3), + (UUID(),"Vet'ion", 1, 76, 3), + (UUID(),"Vorkath", 1, 77, 1), + (UUID(),"Wintertodt", 1, 78, 0), + (UUID(),"Zalcano", 1, 79, 0), + (UUID(),"Zulrah", 1, 80, 1) +; +\ No newline at end of file diff --git a/src/main/resources/db/migration/V1_2__db-update.sql b/src/main/resources/db/migration/V1_2__db-update.sql @@ -0,0 +1 @@ +ALTER TABLE osrs_hiscore_boss MODIFY multiplier DOUBLE DEFAULT 0; +\ No newline at end of file diff --git a/src/main/resources/db/migration/V1_3__update_boss_tob_hard.sql b/src/main/resources/db/migration/V1_3__update_boss_tob_hard.sql @@ -0,0 +1,5 @@ +UPDATE osrs_hiscore_boss SET order_value = order_value+1 WHERE order_value > 71; + +INSERT INTO osrs_hiscore_boss +VALUES +(UUID(),"Theatre of Blood: Hard Mode", 1, 72, 2); +\ No newline at end of file diff --git a/src/main/resources/images/bb8.jpg b/src/main/resources/images/bb8.jpg Binary files differ. diff --git a/src/main/resources/todo.adoc b/src/main/resources/todo.adoc @@ -0,0 +1,19 @@ += TODO + +.Features +* Finish Event listener +* Logging of commands in seperate channel _requested by Mudkip_ +** Username, commandname, command parameters + +.Technical +* Logging +* Make boss changes updateable without breaking code (hiscoreClient indexes are hardcoded) +* Make new channel startups easier (especially channel_detail and guild_role inserts) + +== Nice to have + +== Future plans + +* Single instance can run multiple channels + +== Additional notes +\ No newline at end of file diff --git a/src/test/java/com/sxcy/sxcybot/SxcyBotApplicationTests.java b/src/test/java/com/sxcy/sxcybot/SxcyBotApplicationTests.java @@ -0,0 +1,15 @@ +package com.sxcy.sxcybot; + +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest +@ActiveProfiles("dev") +public class SxcyBotApplicationTests { + + @Test + public void contextLoads() { + } + +}