From 3a1c7059911ae515c58e2565991bd9bfa48c7fd1 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 18:09:31 +0100
Subject: [PATCH 01/66] bootstrap rewrite
---
.gitignore | 34 +-
LICENSE | 875 ++++--------------
README.md | 69 +-
commandEmbeds.json | 522 -----------
docs.md | 549 -----------
jdacEmbeds.json | 118 ---
pom.xml | 88 +-
.../kaktushose/nplaybot/Bootstrapper.java | 14 +
.../de/kaktushose/levelbot/Bootstrapper.java | 78 --
.../de/kaktushose/levelbot/bot/Levelbot.java | 432 ---------
.../levelbot/bot/ShutdownHttpServer.java | 50 -
.../levelbot/bot/TaskScheduler.java | 22 -
.../levelbot/commands/PermissionsService.java | 50 -
.../commands/member/BotInfoCommand.java | 30 -
.../member/ChangeDiamondsCommand.java | 67 --
.../levelbot/commands/member/GiftCommand.java | 54 --
.../commands/member/LeaderboardCommand.java | 141 ---
.../levelbot/commands/member/PingCommand.java | 28 -
.../commands/member/RankInfoCommand.java | 27 -
.../commands/member/SwitchDailyCommand.java | 44 -
.../commands/moderation/BlacklistCommand.java | 80 --
.../moderation/BulkDeleteCommand.java | 46 -
.../moderation/ChangeCurrencyCommand.java | 81 --
.../moderation/IgnoreChannelCommand.java | 63 --
.../moderation/SetCurrencyCommand.java | 77 --
.../commands/moderation/SetPermsCommand.java | 55 --
.../moderation/WelcomeEmbedsCommand.java | 37 -
.../events/BalanceEventCommand.java | 70 --
.../events/CollectEventCommand.java | 81 --
.../events/ContestEventCommand.java | 68 --
.../levelbot/commands/owner/EvalCommand.java | 66 --
.../levelbot/commands/owner/StopCommand.java | 56 --
.../levelbot/database/model/BotUser.java | 221 -----
.../levelbot/database/model/CollectEvent.java | 107 ---
.../levelbot/database/model/ContestEntry.java | 55 --
.../database/model/CurrencyChance.java | 68 --
.../database/model/GuildSettings.java | 145 ---
.../levelbot/database/model/NitroBooster.java | 49 -
.../levelbot/database/model/Rank.java | 86 --
.../levelbot/database/model/Reward.java | 80 --
.../repositories/ChancesRepository.java | 26 -
.../repositories/CollectEventRepository.java | 7 -
.../repositories/ContestRepository.java | 16 -
.../repositories/NitroBoosterRepository.java | 14 -
.../database/repositories/RankRepository.java | 13 -
.../repositories/RewardRepository.java | 20 -
.../repositories/SettingsRepository.java | 39 -
.../database/repositories/UserRepository.java | 33 -
.../database/services/BoosterService.java | 155 ----
.../database/services/EventService.java | 181 ----
.../database/services/LevelService.java | 215 -----
.../database/services/SettingsService.java | 133 ---
.../database/services/UserService.java | 198 ----
.../listener/ContestEventListener.java | 108 ---
.../listener/DailyRewardListener.java | 65 --
.../levelbot/listener/JoinLeaveListener.java | 31 -
.../levelbot/listener/LevelListener.java | 113 ---
.../levelbot/shop/ShopListener.java | 206 -----
.../shop/commands/AddItemCommand.java | 245 -----
.../shop/commands/InitShopCommand.java | 66 --
.../shop/commands/RemoveItemCommand.java | 85 --
.../shop/commands/SetPriceCommand.java | 34 -
.../shop/commands/ShopDeprecatedCommand.java | 25 -
.../levelbot/shop/data/ShopService.java | 163 ----
.../levelbot/shop/data/items/FrozenItem.java | 68 --
.../shop/data/items/FrozenItemRepository.java | 6 -
.../levelbot/shop/data/items/Item.java | 106 ---
.../shop/data/items/ItemCategory.java | 28 -
.../shop/data/items/ItemRepository.java | 16 -
.../levelbot/shop/data/items/ItemVariant.java | 18 -
.../shop/data/transactions/Transaction.java | 61 --
.../transactions/TransactionRepository.java | 29 -
.../spring/ApplicationContextHolder.java | 22 -
.../levelbot/util/NumberEmojis.java | 20 -
.../de/kaktushose/levelbot/util/Pageable.java | 9 -
.../kaktushose/levelbot/util/Pagination.java | 85 --
.../kaktushose/levelbot/util/Statistics.java | 123 ---
src/main/resources/META-INF/MANIFEST.MF | 2 +-
src/test/java/BoosterServiceTest.java | 114 ---
src/test/java/LevelbotMock.java | 32 -
src/test/java/SettingsServiceMock.java | 16 -
src/test/resources/application.properties | 2 -
src/test/resources/truncate_all.sql | 2 -
welcomeEmbeds.json | 131 ---
84 files changed, 260 insertions(+), 7704 deletions(-)
delete mode 100644 commandEmbeds.json
delete mode 100644 docs.md
delete mode 100644 jdacEmbeds.json
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/Bootstrapper.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/bot/Levelbot.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/bot/ShutdownHttpServer.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/bot/TaskScheduler.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/PermissionsService.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/member/BotInfoCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/member/ChangeDiamondsCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/member/GiftCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/member/LeaderboardCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/member/PingCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/member/RankInfoCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/member/SwitchDailyCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/moderation/BlacklistCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/moderation/BulkDeleteCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/moderation/ChangeCurrencyCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/moderation/IgnoreChannelCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/moderation/SetCurrencyCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/moderation/SetPermsCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/moderation/WelcomeEmbedsCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/moderation/events/BalanceEventCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/moderation/events/CollectEventCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/moderation/events/ContestEventCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/owner/EvalCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/commands/owner/StopCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/model/BotUser.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/model/CollectEvent.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/model/ContestEntry.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/model/CurrencyChance.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/model/GuildSettings.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/model/NitroBooster.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/model/Rank.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/model/Reward.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/repositories/ChancesRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/repositories/CollectEventRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/repositories/ContestRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/repositories/NitroBoosterRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/repositories/RankRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/repositories/RewardRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/repositories/SettingsRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/repositories/UserRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/services/BoosterService.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/services/EventService.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/services/LevelService.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/services/SettingsService.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/database/services/UserService.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/listener/ContestEventListener.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/listener/DailyRewardListener.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/listener/JoinLeaveListener.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/listener/LevelListener.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/ShopListener.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/commands/AddItemCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/commands/InitShopCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/commands/RemoveItemCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/commands/SetPriceCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/commands/ShopDeprecatedCommand.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/data/ShopService.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/data/items/FrozenItem.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/data/items/FrozenItemRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/data/items/Item.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/data/items/ItemCategory.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/data/items/ItemRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/data/items/ItemVariant.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/data/transactions/Transaction.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/shop/data/transactions/TransactionRepository.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/spring/ApplicationContextHolder.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/util/NumberEmojis.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/util/Pageable.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/util/Pagination.java
delete mode 100644 src/main/java/de/kaktushose/levelbot/util/Statistics.java
delete mode 100644 src/test/java/BoosterServiceTest.java
delete mode 100644 src/test/java/LevelbotMock.java
delete mode 100644 src/test/java/SettingsServiceMock.java
delete mode 100644 src/test/resources/application.properties
delete mode 100644 src/test/resources/truncate_all.sql
delete mode 100644 welcomeEmbeds.json
diff --git a/.gitignore b/.gitignore
index 109df20..8e84f37 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,34 @@
+### IntelliJ ###
+out/
.idea/
+*.iml
+modules.xml
+*.ipr
+
+### Java ###
+# Compiled class file
+*.class
+# Log file
+*.log
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+### Maven ###
target/
-logs/
-src/main/resources/application.properties
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
dependency-reduced-pom.xml
-*.iml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+
+### Project ###
diff --git a/LICENSE b/LICENSE
index e72bfdd..261eeb9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,674 +1,201 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. 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
-them 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 prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. 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.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey 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;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If 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 convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU 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 that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- 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.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-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.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- 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
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- 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 3 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, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- Copyright (C)
- This program 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, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-.
-
- The GNU 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. But first, please read
-.
\ No newline at end of file
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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
+
+ http://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.
diff --git a/README.md b/README.md
index 4a466cc..a09f7d3 100644
--- a/README.md
+++ b/README.md
@@ -2,82 +2,17 @@
[![Deploy](https://github.com/Kaktushose/Levelbot/actions/workflows/deploy.yml/badge.svg)](https://github.com/Kaktushose/Levelbot/actions/workflows/deploy.yml)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/6eaa0127de99428795b4f5f759da188a)](https://www.codacy.com/gh/Kaktushose/Levelbot/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Kaktushose/Levelbot&utm_campaign=Badge_Grade)
![Generic badge](https://img.shields.io/badge/Version-2.3.0-86c240".svg)
-[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
+[![license-shield](https://img.shields.io/badge/License-Apache%202.0-lightgrey.svg)]()
-# Levelbot (NEW Level-System)
+# NPLAY-Bot
This bot was created specifically for the Discord [server](https://discord.gg/qcpeZQhJf5) of the german YouTuber and Twitch Streamer [nordrheintvplay](https://www.youtube.com/user/nordrheintvplay). The core feature of this bot is a leveling system, similar to Mee6, but with a high level of customization. Besides 3 currencies that can be collected, there are 13 items that all bring different functions and advantages. In addition, there are various temporary events, daily rewards and many other useful features.
## Test Server
The bot is in constant development. Join the test [server](https://discord.gg/JYWezvQ) to receive regular updates, make suggestions and test preview versions. This is also the place to get support if you want to host the bot by yourself.
-
-## Installation
-
-Due to the high level of customization, I do not provide a public instance that anyone can invite. However, you can still host your own version of the bot. Therefore, you should have a basic understanding of Maven, MySQL, Discord bots in general and intermediate knowledge of Java and Spring Boot.
-
-### 0. Prerequisites
-
-Make sure to have the following things up and running:
-
-- Java 11
-- MySQL Server
-- Maven
-- git
-
-### 1. Cloning the repo
-
-```
-git clone https://github.com/Kaktushose/Levelbot.git
-```
-
-### 2. Configuration
-
-Go to the resources folder and add the following `application.properties` file:
-
-```
-spring.jpa.hibernate.ddl-auto=update
-spring.datasource.url=jdbcurl
-spring.datasource.username=username
-spring.datasource.password=password
-```
-
-Make sure to set `ddl-auto` to `none` once you are in production environment.
-
-There are also some hardcoded values (e.g. channel ids) inside the codebase, make sure to change them.
-
-Go to [this](https://github.com/Kaktushose/Levelbot/blob/master/src/main/java/de/kaktushose/levelbot/bot/Levelbot.java#L91) line and provide your own bot token.
-
-### 3. Setting up the database
-
-As soon as you start the bot for the first time, Spring Boot will create all the database tables automatically. Afterwards you can start to fill in values, the column names should be self-explanatory. Feel free to hit me up, if you need help with this step. _Kaktushose#4036 is my discord tag_.
-
-### 4. Building the jar
-
-Once you are done with all configuration steps, you can build the jar and run it:
-
-```
-mvn clean package
-```
-
-```
-java -jar Levelbot.jar
-```
-
-## Contributing
-
-If you believe that something is missing, and you want to add it yourself, feel free to open a pull request. I recommend opening an issue first to prevent misunderstandings or waste of time because I'm already making your feature. Please try to keep your code quality at least as good as mine and stick to the design concepts of this project.
-
-## Used Technologies
-
-- [Java 11](https://openjdk.java.net/projects/jdk/11/)
-- [Maven](https://maven.apache.org/) - Project Management Software
-- [JDA](https://github.com/DV8FromTheWorld/JDA) - Discord API Wrapper
-- [jda-commands](https://github.com/Kaktushose/jda-commands) - Command Framework
-- [MariaDB](https://mariadb.com/) - Database
-- [Spring Boot Data JPA](https://spring.io/projects/spring-data-jpa) - Database Access
diff --git a/commandEmbeds.json b/commandEmbeds.json
deleted file mode 100644
index 3460c37..0000000
--- a/commandEmbeds.json
+++ /dev/null
@@ -1,522 +0,0 @@
-{
- "pingEmbed": {
- "title": ":satellite_orbital: Ping zur Discord-API",
- "color": "#666666",
- "fields": [
- {
- "name": "Gateway",
- "value": "{gatewayPing}"
- },
- {
- "name": "Rest",
- "value": "{restPing}"
- }
- ]
- },
- "currencyChange": {
- "title": "Erfolg!",
- "description": "Die {currency} von {user} wurden um {value} {operation}.",
- "color": "#86c240"
- },
- "currencySet": {
- "title": "Erfolg!",
- "description": "Die {currency} von {user} wurden auf {value} gesetzt.",
- "color": "#86c240"
- },
- "memberNotFound": {
- "title": "Fehler!",
- "description": "Der angegebene Nutzer ist nicht in der Datenbank vorhanden.\n\nBitte kontaktiere <@393843637437464588> .",
- "color": "#aa0c14"
- },
- "confirmAction": {
- "title": "Achtung!",
- "description": "Bist du sicher, dass {action}",
- "color": "#f4cd53"
- },
- "memberBlacklistAdd": {
- "title": "Erfolg!",
- "description": "{user} wurde zur Blacklist hinzugefügt und kann nicht mehr mit dem Bot interagieren.",
- "color": "#86c240"
- },
- "memberBlacklistShow": {
- "title": "Folgende Nutzer stehen auf der Blacklist:",
- "description": "{blacklist}",
- "color": "#86c240"
- },
- "memberBlacklistRemove": {
- "title": "Erfolg!",
- "description": "{user} wurde von der Blacklist entfernt und kann wieder mit dem Bot interagieren.\nHinweis: Sein Berechtigungslevel wurde auf `1` zurückgesetzt!",
- "color": "#86c240"
- },
- "memberBlacklistInvalidTarget": {
- "title": "Unzureichende Berechtigungen!",
- "description": "Dein Berechtigungslevel reicht nicht aus, um {user} zur Blacklist hinzuzufügen.",
- "color": "#aa0c14"
- },
- "permissionSet": {
- "title": "Erfolg!",
- "description": "Das Berechtigungslevel von {user} wurde auf {value} gesetzt.",
- "color": "#86c240"
- },
- "permissionSetInvalidTarget": {
- "title": "Unzureichende Berechtigungen!",
- "description": "Dein Berechtigungslevel reicht nicht aus, um das Berechtigungslevel von {user} zu bearbeiten.",
- "color": "#aa0c14"
- },
- "invalidValue": {
- "title": "Fehler!",
- "description": "Es sind nur Werte von {min} bis einschließlich {max} erlaubt.",
- "color": "#aa0c14"
- },
- "bulkDeleteSuccess": {
- "title": "Erfolg!",
- "description": "{amount} Nachrichten wurden gelöscht.",
- "color": "#86c240"
- },
- "removeItem": {
- "title": "Item entfernen",
- "description": "{user} besitzt folgende Items:",
- "color": "#f4cd53",
- "footer": {
- "text": "Reagiere mit dem entsprechenden Emote, um ein Item zu entfernen"
- }
- },
- "removeItemSuccess": {
- "title": "Erfolg!",
- "description": "{user} wurde das Item entfernt.",
- "color": "#86c240"
- },
- "evalCommand": {
- "title": "Eval Result",
- "description": "```{result}```",
- "color": "{color}"
- },
- "botInfo": {
- "title": "Informationen zum Bot",
- "color": "#86c240",
- "fields": [
- {
- "name": "Prefix",
- "value": "{prefix}"
- },
- {
- "name": "Version",
- "value": "{version}"
- },
- {
- "name": "Lizenz",
- "value": "[GNU General Public License 3](https://www.gnu.org/licenses/gpl-3.0)"
- },
- {
- "name": "Website",
- "value": "[GitHub](https://github.com/Kaktushose/Levelbot)"
- },
- {
- "name": "Credits",
- "value": "Konzept und Idee: <@307973135746072578> \nProgrammierung: <@393843637437464588> \nLogo und Testing: <@487320784759685130>"
- }
- ]
- },
- "missingCurrency": {
- "title": "Fehler!",
- "description": "Du hast nicht genügend {currency}.",
- "color": "#aa0c14"
- },
- "diamondChangeSuccess": {
- "title": "Erfolg!",
- "description": "Du hast {diamonds} Diamanten gegen {coins} Münzen getauscht.",
- "color": "#86c240"
- },
- "switchDailySuccess": {
- "title": "Erfolg!",
- "description": "Die tägliche Kontoinformation wurde {action}.",
- "color": "#86c240"
- },
- "switchDailyError": {
- "title": "Fehler!",
- "description": "Der Bot kann dir keine Direktnachrichten senden!\nBitte überprüfe deine Einstellungen und versuche es dann erneut!",
- "color": "#aa0c14"
- },
- "rankInfo": {
- "title": ":information_source: Kontoinformation für",
- "description": "{user}",
- "color": "{color}",
- "thumbnail": {
- "url": "{avatarUrl}"
- },
- "fields": [
- {
- "name": "Stufe",
- "value": ":level_slider: {currentRank}"
- },
- {
- "name": "Nächste Stufe",
- "value": ":dart: {nextRank}"
- },
- {
- "name": "",
- "value": "__Währungen__:"
- },
- {
- "name": "XP:",
- "value": ":star2: {xp}",
- "inline": true
- },
- {
- "name": "Münzen:",
- "value": ":moneybag: {coins}",
- "inline": true
- },
- {
- "name": "Diamanten:",
- "value": ":gem: {diamonds}",
- "inline": true
- },
- {
- "name": "",
- "value": "__Statistiken__:"
- },
- {
- "name": "Ressourcen-Zuwachs:",
- "value": ":star2: {xpGain} | :moneybag: {coinsGain} | :gem: {diamondsGain}"
- },
- {
- "name": "Gezählte Nachrichten:",
- "value": ":chart_with_upwards_trend: {messageCount}"
- },
- {
- "name": "",
- "value": "__Items__:"
- }
- ],
- "footer": {
- "text": "Hole dir Items direkt im Kanal #levelsystem"
- }
- },
- "eventRankInfo": {
- "title": ":information_source: Kontoinformation für",
- "description": "{user}",
- "color": "{color}",
- "thumbnail": {
- "url": "{avatarUrl}"
- },
- "fields": [
- {
- "name": "Stufe",
- "value": ":level_slider: {currentRank}"
- },
- {
- "name": "Nächste Stufe",
- "value": ":dart: {nextRank}"
- },
- {
- "name": "",
- "value": "__Währungen__:"
- },
- {
- "name": "XP:",
- "value": ":star2: {xp}",
- "inline": true
- },
- {
- "name": "Münzen:",
- "value": ":moneybag: {coins}",
- "inline": true
- },
- {
- "name": "Diamanten:",
- "value": ":gem: {diamonds}",
- "inline": true
- },
- {
- "name": "",
- "value": "__Statistiken__:"
- },
- {
- "name": "Ressourcen-Zuwachs:",
- "value": ":star2: {xpGain} | :moneybag: {coinsGain} | :gem: {diamondsGain}"
- },
- {
- "name": "Gezählte Nachrichten:",
- "value": ":chart_with_upwards_trend: {messageCount}"
- },
- {
- "name": "",
- "value": "__{eventName}__:"
- },
- {
- "name": "{currencyName}:",
- "value": "{currencyEmote} {currencyPoints}"
- },
- {
- "name": "Belohnungen:",
- "value": "{eventRewards}"
- },
- {
- "name": "",
- "value": "__Items__:"
- }
- ],
- "footer": {
- "text": "Hole dir Items direkt im Kanal #levelsystem"
- }
- },
- "leaderboard": {
- "title": "Rangliste {guild}: {currency}",
- "color": "#86c240"
- },
- "shopOverview": {
- "title": ":shopping_cart: Shop",
- "description": "Item hinzufügen für {user}",
- "color": "#86c240",
- "fields": [
- {
- "name": ":star: PREMIUM",
- "value": "Erhalte mit dieser besonderen Rolle satte 12 exklusive Vorteile auf unserem Server!"
- },
- {
- "name": ":musical_note: Rythm DJ Perk",
- "value": "Mit der DJ Rolle für den \"Rythm\" bist Du der Star!"
- },
- {
- "name": ":man_tone3: Nickname Perk",
- "value": "Mit dem Nickname Perk erhältst du das Recht, Deinen Nicknamen auf dem Server selbstständig jederzeit zu ändern!"
- },
- {
- "name": ":moneybag: Münzenbooster",
- "value": "Mit dem Münzenbooster erhältst Du +2 Münzen je gezählter Nachricht zusätzlich - optimal für viele Münzen!"
- },
- {
- "name": ":star2: XP-Booster",
- "value": "Mit dem XP-Booster erhältst Du +2 XP je gezählter Nachricht zusätzlich - steige so leichter in neue Stufen auf!"
- }
- ],
- "footer": {
- "text": "Um ein Item zu kaufen, reagiere mit dem jeweiligen Emote!"
- }
- },
- "specificShop": {
- "title": ":shopping_cart: Shop",
- "description": "Für dieses Item stehen folgende Variationen zur Verfügung:",
- "color": "#86c240",
- "footer": {
- "text": "Um ein Item zu kaufen, reagiere mit dem jeweiligen Emote!"
- }
- },
- "shopSuccess": {
- "title": ":shopping_bags: Erfolgreicher Kauf!",
- "description": "Du besitzt jetzt das Item \"{item}\"",
- "color": "#86c240",
- "fields": [
- {
- "name": "Dauer:",
- "value": ":timer_clock: {days} Tage"
- }
- ]
- },
- "addItemSuccess": {
- "title": "Erfolg!",
- "description": "{user} besitzt jetzt das Item \"{item}\"",
- "color": "#86c240",
- "fields": [
- {
- "name": "Dauer:",
- "value": ":timer_clock: {days} Tage"
- }
- ]
- },
- "shopConfirm": {
- "title": "Bestätige Deinen Kauf! :gift:",
- "description": "Bist du sicher, dass Du das Item \"{item}\" für {price} Münzen :moneybag: erwerben möchtest? Klicke auf den :white_check_mark:, um den Kauf zu bestätigen.",
- "color": "#f4cd53"
- },
- "shopError": {
- "title": "Fehler!",
- "description": "{message}",
- "color": "#aa0c14"
- },
- "levelUp": {
- "title": ":arrow_up: Stufenaufstieg!",
- "description": "{user}",
- "color": "{color}",
- "fields": [
- {
- "name": "Neue Stufe:",
- "value": ":level_slider: {currentRank}"
- },
- {
- "name": "Einmalige Belohnung:",
- "value": "{reward}"
- },
- {
- "name": "Nächste Stufe:",
- "value": ":dart: {nextRank} (ab {xp} XP)"
- }
- ]
- },
- "itemExpired": {
- "title": "Item abgelaufen!",
- "description": "Dein {item} ist abgelaufen!",
- "color": "#f4cd53",
- "fields": [
- {
- "name": "Gekauft am:",
- "value": "{date}"
- }
- ]
- },
- "botStop": {
- "title": "Bot wurde heruntergefahren!",
- "description": ":wrench: Wir sind in Kürze wieder zurück!",
- "color": "#aa0c14"
- },
- "botStart": {
- "title": "Bot wurde gestartet!",
- "description": ":gear: Version: {version}",
- "color": "#86c240"
- },
- "itemNotFound": {
- "title": "Fehler!",
- "description": "Es wurde kein Item mit der ID {id} gefunden!",
- "color": "#aa0c14"
- },
- "itemPriceChanged": {
- "title": "Erfolg!",
- "description": "Der Preis wurde erfolgreich geändert!",
- "color": "#86c240"
- },
- "nitroBoostStart": {
- "title": "Vielen Dank für Deine Unterstützung {user}!",
- "description": "Danke, dass Du den nordrheintvplay Discord mit Deinem Nitro-Boost unterstützt.\nAls kleine Aufmerksamkeit hast Du einige coole einmalige Belohnung erhalten:\n> **EINMALIG:**\n\n> <:icon_confirmation2:693837343580356618> 250 XP :star2: geschenkt\n> <:icon_confirmation2:693837343580356618> 250 Münzen :moneybag: geschenkt\n> <:icon_confirmation2:693837343580356618> 25 Diamanten :gem: geschenkt\n> + PREMIUM unlimited, gilt dauerhaft bis zur Beendigung des Boosts!\n\nAußerdem schenken wir Dir alle 30 Tage zusätzlich:\n\n**FORTLAUFEND:**\n> <:icon_confirmation2:693837343580356618> 50 XP :star2: jeden Monat zusätzlich!\n> <:icon_confirmation2:693837343580356618> 50 Münzen :moneybag:\n> <:icon_confirmation2:693837343580356618> 5 Diamanten :gem:\n> <:icon_confirmation2:693837343580356618> Nitro Booster Rolle :icon_boost: als cooles Abzeichen!\n\nWir wünschen Dir weiterhin viel Spaß auf dem Server.",
- "color": "#f47fff"
- },
- "nitroBoostResume": {
- "title": "Vielen Dank für Deine Unterstützung {user}!",
- "description": "Danke, dass Du den nordrheintvplay Discord erneut mit Deinem Nitro-Boost unterstützt. \nAls kleine Aufmerksamkeit hast Du PREMIUM unlimited :star: erhalten. Die Rolle gilt dauerhaft bis zur Beendigung des Boosts!\n\nAußerdem schenken wir Dir alle 30 Tage zusätzlich:\n> <:icon_confirmation2:693837343580356618> 50 XP :star2: jeden Monat zusätzlich!\n> <:icon_confirmation2:693837343580356618> 50 Münzen :moneybag:\n> <:icon_confirmation2:693837343580356618> 5 Diamanten :gem:\n> <:icon_confirmation2:693837343580356618> Nitro Booster Rolle :icon_boost: als cooles Abzeichen!\n\nWir wünschen Dir weiterhin viel Spaß auf dem Server.",
- "color": "#f47fff"
- },
- "nitroBoostStop": {
- "title": "Information zu Deinem Server-Boost bei nordrheintvplay",
- "description": "Lieber {user},\nschade, dass du unseren Server nicht mehr mit einem Server-Boost unterstützt.\nWir möchten dich darüber informieren, dass mit der Beendigung des Boosts auch die dazugehörigen fortlaufenden Belohnungen entfallen. \nWir bedanken uns für Deine Treue und wünschen Dir weiterhin viel Spaß auf dem Server.\nDein Serverteam\n",
- "color": "#f4cd53"
- },
- "shopInitSuccess": {
- "title": "Erfolg!",
- "description": "Der Reaction Shop wurde erfolgreich eingerichtet!",
- "color": "#86c240"
- },
- "statistics": {
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/850466263216947252/970283398063079464/nplay_logo_standard.jpg"
- },
- "title": "Aktuelle Statistiken",
- "description": "__**NPLAY Discord:**__\n\n**Mitglieder auf dem Server:**\n{totalMemberCount}\n\n**Mitglieder online:**\n{onlineMemberCount}\n\n**Mitglieder in Spielen:**\n:tractor: LS 22: {lsMemberCount}\n:truck: ETS 2: {etsMemberCount}\n:fire: Notruf 112: {notrufMemberCount}\n:bus: OMSI 2: {omsiMemberCount}\n:mountain_cableway: Winter Resort Simulator: {wrsMemberCount}\n:gun: GTA V: {gtaMemberCount}\n\n**Nitro-Booster:**\nDerzeit insgesamt {boosterMemberCount} <@&596780997727617045>, die uns mit {boosterCount} Boosts unterstützen.\n\n{boosterMemberList}\n\n**PREMIUM:**\nDerzeit insgesamt {premiumMemberCount} <@&386302591883018242>- Mitglieder.\n\n{premiumMemberList}\n\n__**NPLAY auf Youtube:**__\n\n**Abonnenten auf YouTube:** \n{ytFollowerCount}\n\n**Videos auf YouTube:**\n{ytVideoCount}\n\n**Views auf YouTube:**\n{ytViewCount}",
- "color": "#aeff00"
- },
- "dailyReward": {
- "title": "Herzlichen Glückwunsch, {user}!",
- "description": "Du hast Deine tägliche Belohnung in Höhe von {reward} erfolgreich abgeholt.\nSchau gerne morgen wieder vorbei.",
- "color": "#86c240"
- },
- "balanceEventList": {
- "title": "Folgende Balance Events sind verfügbar",
- "description": "0: XP-Booster x2\n1: Münzen-Rush x2\n2: Diamanten-Regen x2\n3: Cooldown -67%",
- "color": "#86c240"
- },
- "unknownEventId": {
- "title": "Fehler!",
- "description": "Unbekannte Event ID. Siehe `event list` für Details!",
- "color": "#aa0c14"
- },
- "balanceEventStart": {
- "title": "Erfolg!",
- "description": "Das Event \"{name}\" wurde erfolgreich aktiviert.",
- "color": "#86c240"
- },
- "balanceEventStop": {
- "title": "Erfolg!",
- "description": "Das Event \"{name}\" wurde erfolgreich deaktiviert.",
- "color": "#86c240"
- },
- "contestEventStart": {
- "title": "Erfolg!",
- "description": "Das Bilder Contest Event wurde erfolgreich aktiviert.",
- "color": "#86c240"
- },
- "contestEventStop": {
- "title": "Erfolg!",
- "description": "Das Bilder Contest Event wurde erfolgreich deaktiviert.",
- "color": "#86c240"
- },
- "collectEventStart": {
- "title": "Erfolg!",
- "description": "Das Sammel Event \"{name}\" wurde erfolgreich aktiviert.",
- "color": "#86c240"
- },
- "collectEventStop": {
- "title": "Erfolg!",
- "description": "Das Sammel Event wurde erfolgreich deaktiviert.",
- "color": "#86c240"
- },
- "collectEventList": {
- "title": "Folgende Collect Events sind verfügbar",
- "description": "{list}",
- "color": "#86c240"
- },
- "noActiveCollectEvent": {
- "title": "Fehler!",
- "description": "Es ist kein Sammel Event aktiviert.",
- "color": "#aa0c14"
- },
-
- "collectEventRoleReward": {
- "title": "Frohe Weihnachtszeit :santa: , {user}!",
- "description": "Du hast Dein **erstes Rentier** :deer: auf dem Server gefunden!\nAls Belohnung verleihen wir Dir unsere exklusive **Eventrolle XMAS 2022** :red_circle:, mit der Du über die Weihnachtage ganz oben auf dem Server gelistet bist! Genieße die freie Zeit und finde insgesamt **12 Rentiere** :deer: für eine weitere Belohnung.\n\n:point_right: Nimm an unserem Screenshot-Contest teil! Alle Infos in <#1053712477650686063>.\n\n:point_right: Und vom 24.12 - 26.12 ist unser **CHRISTMAS-BOOSTER** :christmas_tree: aktiv, der alle bisherigen Booster kombiniert.\n\n:point_right: In diesem Zeitraum kannst Du dir außerdem mit dem Befehl !geschenk im Kanal bot-befehle ein **besonderes Geschenk** :gift: abholen.",
- "color": "#EC5C0F"
- },
- "collectEventItemReward": {
- "title": "Ein Geschenk für Dich :man_surfing:, {user}!",
- "description": "Du hast nun großartige **30 Wassermelonen** :watermelon: geerntet.\nWie versprochen darfst Du jetzt **15 Tage** :clock:️ **GRATIS PREMIUM** :star: auf dem Server genießen!\nWir wünschen Dir weiterhin viel Spaß mit der NPLAY-Sommerzeit :man_surfing:.\n\nÜbrigens: Wenn du insgesamt **30 Melonen** :watermelon: gesammelt hast, darfst Du dich über **15 Tage** :clock:️ **GRATIS PREMIUM** :star: auf dem Server freuen!\nUnd während der gesamten NPLAY-Sommerzeit ist unser **XXL-SOMMERBOOSTER** :timer::star2: mit **2-fachen XP** und **2-fachten Münzen** aktiviert.",
- "color": "#EC5C0F"
- },
- "collectEventXpReward": {
- "title": "Frohe Weihnachtszeit :santa: , {user}!",
- "description": "Du hast nun satte **12 Rentiere** :deer: auf dem Server gefunden!\nAls Dankeschön haben wir Dir zusätzlich **50 XP** :star2: auf Deinem Konto gutgeschrieben. Und die Suche geht weiter, denn ab insgesamt **24 Rentieren** :deer: erhältst Du eine weitere Belohnung!\n\n:point_right: Nimm an unserem Screenshot-Contest teil! Alle Infos in <#1053712477650686063>.\n\n:point_right: Und vom 24.12 - 26.12 ist unser **CHRISTMAS-BOOSTER** :christmas_tree: aktiv, der alle bisherigen Booster kombiniert.\n\n:point_right: In diesem Zeitraum kannst Du dir außerdem mit dem Befehl !geschenk im Kanal bot-befehle ein **besonderes Geschenk** :gift: abholen.",
- "color": "#EC5C0F"
- },
- "collectEventCoinsReward": {
- "title": "Frohe Weihnachtszeit :santa: , {user}!",
- "description": "Du hast nun fabelhafte **24 Rentiere** :deer: auf dem Server gefunden!\nDafür schenken wir Dir weitere **100 Münzen** :moneybag:. Viel Spaß damit und weiterhin eine gute Zeit!\n\n:point_right: Nimm an unserem Screenshot-Contest teil! Alle Infos in <#1053712477650686063>.\n\n:point_right: Und vom 24.12 - 26.12 ist unser **CHRISTMAS-BOOSTER** :christmas_tree: aktiv, der alle bisherigen Booster kombiniert.\n\n:point_right: In diesem Zeitraum kannst Du dir außerdem mit dem Befehl !geschenk im Kanal bot-befehle ein **besonderes Geschenk** :gift: abholen.",
- "color": "#EC5C0F"
- },
- "rewardAlreadyClaimed": {
- "title": "Fehler!",
- "description": "Du hast deine tägliche Belohnung bereits abgeholt.\nSchau gerne in {hours} Stunden wieder vorbei!",
- "color": "#f4cd53"
- },
- "shopCommandDeprecated": {
- "title": ":information_source: Hinweis",
- "description": "Der Shop-Command wurde entfernt.\nItems kannst du ab sofort direkt in <#851388807239827466> kaufen.",
- "color": "#f4cd53"
- },
- "mutedChannelsAdd": {
- "title": "Erfolg!",
- "description": "{channel} wird ab sofort vom Levelsystem ignoriert.",
- "color": "#86c240"
- },
- "mutedChannelsRemove": {
- "title": "Erfolg!",
- "description": "{channel} wird nicht mehr vom Levelsystem ignoriert.",
- "color": "#86c240"
- },
- "mutedChannelsList": {
- "title": "Folgende Kanäle werden vom Levelsystem ignoriert:",
- "description": "{list}",
- "color": "#86c240"
- },
- "buyLog": {
- "title": "Transaktion",
- "description": "{user} hat das Item \"{item}\" gekauft.",
- "color": "#86c240"
- }
-}
diff --git a/docs.md b/docs.md
deleted file mode 100644
index 35bb178..0000000
--- a/docs.md
+++ /dev/null
@@ -1,549 +0,0 @@
-> Auto generated command manual | 2021/06/08 11:59:24
-
-Owner
-=====
-### Bot herunterfahren
-
-**Description:**
-
-Fährt den Bot herunter.
-
-**Usage:**
-
-`!stop`
-
-**Aliases:**
-
-- shutdown
-
-**Permissions:**
-
-- owner
-
-### Code ausführen
-
-**Description:**
-
-Führt Code in der aktuellen Runtime des Bots aus
-
-**Usage:**
-
-`!eval `
-
-**Permissions:**
-
-- owner
-
-Moderation
-==========
-### Item entfernen
-
-**Description:**
-
-Entfernt ein Item aus dem Besitz eines Benutzers
-
-**Usage:**
-
-`!remove `
-
-**Aliases:**
-
-- rm
-
-**Permissions:**
-
-- moderator
-
-### Preis ändern
-
-**Description:**
-
-Setzt den Preis eines Items auf den angegebenen Wert
-
-**Usage:**
-
-`!setprice `
-
-**Permissions:**
-
-- moderator
-
-### Willkommen Embeds senden
-
-**Description:**
-
-Sendet die Embeds in <#551483788337872927>
-
-**Usage:**
-
-`!embeds resend `
-
-**Permissions:**
-
-- moderator
-
-### Willkommen Embeds senden
-
-**Description:**
-
-Sendet die Embeds in <#551483788337872927>
-
-**Usage:**
-
-`!embeds send`
-
-**Permissions:**
-
-- moderator
-
-### Contest Event deaktivieren
-
-**Description:**
-
-Stoppt ein Bilder Contest Event
-
-**Usage:**
-
-`!event contest stop`
-
-**Permissions:**
-
-- moderator
-
-### Collect Event Arten
-
-**Description:**
-
-Zeigt eine Liste aller verfügbaren Collect Events an
-
-**Usage:**
-
-`!event collect list`
-
-**Permissions:**
-
-- moderator
-
-### XP setzen
-
-**Description:**
-
-Setzt die Anzahl der XP eines Benutzers auf den angegbenen Wert.
-
-**Usage:**
-
-`!set xp `
-
-**Permissions:**
-
-- moderator
-
-### Balance Event Arten
-
-**Description:**
-
-Zeigt eine Liste aller verfügbaren Balance Events an
-
-**Usage:**
-
-`!event balance list`
-
-**Permissions:**
-
-- moderator
-
-### Balance Event deaktivieren
-
-**Description:**
-
-Stoppt das Balance Event mit der angegeben ID
-
-**Usage:**
-
-`!event balance stop `
-
-**Permissions:**
-
-- moderator
-
-### Münzen ändern
-
-**Description:**
-
-Ändert die Anzahl der Münzen eines Benutzers um den angegbenen Wert.
-
-**Usage:**
-
-`!add coins `
-
-**Permissions:**
-
-- moderator
-
-### Balance Event aktivieren
-
-**Description:**
-
-Startet das Balance Event mit der angegeben ID
-
-**Usage:**
-
-`!event balance start `
-
-**Permissions:**
-
-- moderator
-
-### Benutzer sperren
-
-**Description:**
-
-Fügt einen Benutzer zur Blacklist hinzu
-
-**Usage:**
-
-`!blacklist add `
-
-**Aliases:**
-
-- banlist add
-- bl add
-
-**Permissions:**
-
-- moderator
-
-### Sammel Event aktivieren
-
-**Description:**
-
-Startet das Sammel Event mit der angegeben ID
-
-**Usage:**
-
-`!event collect start `
-
-**Permissions:**
-
-- moderator
-
-### Berechtigung ändern
-
-**Description:**
-
-Setzt das Berechtigungslevel eines Benutzers auf den angegebenen Wert
-
-**Usage:**
-
-`!setperms `
-
-**Permissions:**
-
-- moderator
-
-### Diamanten ändern
-
-**Description:**
-
-Ändert die Anzahl der Diamanten eines Benutzers um den angegbenen Wert.
-
-**Usage:**
-
-`!add diamonds `
-
-**Permissions:**
-
-- moderator
-
-### Reaction Shop einrichten
-
-**Description:**
-
-Fügt die benötigten Reactions für den Shop hinzu
-
-**Usage:**
-
-`!initshop `
-
-**Permissions:**
-
-- moderator
-
-### XP ändern
-
-**Description:**
-
-Ändert die Anzahl der XP eines Benutzers um den angegbenen Wert.
-
-**Usage:**
-
-`!add xp `
-
-**Permissions:**
-
-- moderator
-
-### Münzen setzen
-
-**Description:**
-
-Setzt die Anzahl der Münzen eines Benutzers auf den angegbenen Wert.
-
-**Usage:**
-
-`!set coins `
-
-**Permissions:**
-
-- moderator
-
-### Benutzer entsperren
-
-**Description:**
-
-Entfernt einen Benutzer von der Blacklist
-
-**Usage:**
-
-`!blacklist remove `
-
-**Aliases:**
-
-- blacklist rm
-- banlist remove
-- banlist rm
-- bl remove
-- bl rm
-
-**Permissions:**
-
-- moderator
-
-### Nachrichten löschen
-
-**Description:**
-
-Löscht die angegebene Zahl von Nachrichten aus einem Channel
-
-**Usage:**
-
-`!delete `
-
-**Aliases:**
-
-- purge
-- clear
-
-**Permissions:**
-
-- moderator
-
-### Gesperrte Benutzer
-
-**Description:**
-
-Zeigt alle Nutzer, die auf der Blacklist stehen
-
-**Usage:**
-
-`!blacklist show`
-
-**Aliases:**
-
-- blacklist list
-- blacklist view
-- banlist show
-- banlist list
-- banlist view
-- bl show
-- bl list
-- bl view
-
-**Permissions:**
-
-- moderator
-
-### Contest Event aktivieren
-
-**Description:**
-
-Startet ein Bilder Contest Event
-
-**Usage:**
-
-`!event contest start `
-
-**Permissions:**
-
-- moderator
-
-### Diamanten setzen
-
-**Description:**
-
-Setzt die Anzahl der Diamanten eines Benutzers auf den angegbenen Wert.
-
-**Usage:**
-
-`!set diamonds `
-
-**Permissions:**
-
-- moderator
-
-### Collect Event deaktivieren
-
-**Description:**
-
-Stoppt das aktuelle Collect Event
-
-**Usage:**
-
-`!event collect stop`
-
-**Permissions:**
-
-- moderator
-
-Levelsystem
-===========
-### Täglich Command
-
-**Description:**
-
-Aktiviert bzw. deaktiviert die täglichen Kontoinformationen
-
-**Usage:**
-
-`!täglich`
-
-**Permissions:**
-
-
-
-### Diamanten tauschen
-
-**Description:**
-
-Tauscht Diamanten gegen Münzen ein. Ein Diamant ist 20 Münzen wert
-
-**Usage:**
-
-`!tauschen `
-
-**Aliases:**
-
-- wechseln
-
-**Permissions:**
-
-
-
-### Level-Shop
-
-**Description:**
-
-Mit diesem Command kannst du Items aus dem Levelshop kaufen
-
-**Usage:**
-
-`!kaufen`
-
-**Aliases:**
-
-- shop
-
-**Permissions:**
-
-
-
-### Level-Shop
-
-**Description:**
-
-Fügt ein Item einem anderen Nutzer hinzu
-
-**Usage:**
-
-`!kaufen `
-
-**Aliases:**
-
-- shop for
-
-**Permissions:**
-
-- moderator
-
-### Kontoinformation abrufen
-
-**Description:**
-
-Zeigt die Kontoinformationen zu einem User an
-
-**Usage:**
-
-`!info `
-
-**Aliases:**
-
-- rank
-- konto
-
-**Permissions:**
-
-
-
-### Rangliste
-
-**Description:**
-
-Zeigt eine Rangliste der Benutzer mit den meisten XP, Münzen oder Diamanten
-
-**Usage:**
-
-`!rangliste`
-
-**Aliases:**
-
-- leaderboard
-- lb
-
-**Permissions:**
-
-
-
-Sonstiges
-=========
-### Ping Command
-
-**Description:**
-
-Zeigt den Ping zur Discord-API an
-
-**Usage:**
-
-`!ping`
-
-**Permissions:**
-
-
-
-### Bot Information
-
-**Description:**
-
-Zeigt allgemeine Inforamtionen über den Bot an
-
-**Usage:**
-
-`!botinfo`
-
-**Aliases:**
-
-- credits
-
-**Permissions:**
-
-
-
diff --git a/jdacEmbeds.json b/jdacEmbeds.json
deleted file mode 100644
index dce38ec..0000000
--- a/jdacEmbeds.json
+++ /dev/null
@@ -1,118 +0,0 @@
-{
- "defaultHelp": {
- "title": "Generelle Hilfe",
- "description": "Die folgenden Commands sind verfügbar. Siehe `{prefix}{helpLabel} ` um spezifische Hilfe zu erhalten.",
- "color": "#86c240"
- },
- "specificHelp": {
- "title": "Ausführliche Hilfe",
- "description": "Command Details für `{prefix}{label}`",
- "color": "#86c240",
- "fields": [
- {
- "name": "Name",
- "value": "`{name}`"
- },
- {
- "name": "Benutzung",
- "value": "`{usage}`"
- },
- {
- "name": "Aliase",
- "value": "`{aliases}`"
- },
- {
- "name": "Beschreibung",
- "value": "`{description}`"
- },
- {
- "name": "Berechtigungen",
- "value": "`{permissions}`"
- },
- {
- "name": "Kategorie",
- "value": "`{category}`"
- }
- ]
- },
- "genericHelp": {
- "title": "Generelle Hilfe",
- "description": "Die folgenden Commands sind verfügbar. Siehe `{prefix}{helpLabel} ` für eine ausführliche Hilfe",
- "color": "#86c240"
- },
- "commandNotFound": {
- "title": "Command nicht gefunden!",
- "description": "```Siehe {prefix}{helpLabel} um eine Liste aller verfügbaren Commands zu erhalten```",
- "fields": [
- {
- "name": "Ähnliche Commands",
- "value": "{commands}"
- }
- ],
- "color": "#f4cd53"
- },
- "insufficientPermissions": {
- "title": "Unzureichende Berechtigungen",
- "description": "`{prefix}{label}` benötigt bestimmte Berechtigungen um ausgeführt zu werden",
- "color": "#ff0000",
- "fields": [
- {
- "name": "Berechtigungen:",
- "value": "`{permissions}`"
- }
- ]
- },
- "guildMuted": {
- "title": "Unzureichende Berechtigungen",
- "description": "Dieser Server wurde gemuted!",
- "color": "#ff0000"
- },
- "channelMuted": {
- "title": "Unzureichende Berechtigungen",
- "description": "Dieser Kanal wurde gemuted!",
- "color": "#ff0000"
- },
- "userMuted": {
- "title": "Unzureichende Berechtigungen",
- "description": "Du wurdest gemuted!",
- "color": "#ff0000"
- },
- "syntaxError": {
- "title": "Syntax Fehler",
- "description": "`{usage}`",
- "color": "#ffc800",
- "fields": [
- {
- "name": "Erwartete Argumente",
- "value": "`{expected}`"
- },
- {
- "name": "Übergebene Parameter",
- "value": "`{actual}`"
- }
- ]
- },
- "cooldown": {
- "title": "Cooldown",
- "description": "Du kannst diesen Command wieder nutzen in: {cooldown}",
- "color": "#ff0000"
- },
- "wrongChannel": {
- "title": "Falscher Kanal",
- "description": "Dieser Command kann in Direktnachrichten nicht ausgeführt werden!",
- "color": "#ff0000"
- },
- "constraintFailed": {
- "title": "Parameter Fehler",
- "description": "```{message}```",
- "color": "#ffc800"
- },
- "executionFailed": {
- "title": "Command Ausführung fehlgeschlagen",
- "description": "```exception```",
- "color": "#ff0000",
- "footer": {
- "text": "Bitte kontaktiere Kaktushose"
- }
- }
-}
diff --git a/pom.xml b/pom.xml
index 892fd7e..5912a45 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,14 +4,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- de.kaktushose.levelbot
- Levelbot
- 2.3.0
+ com.github.kaktushose
+ NPLAY-Bot
+ 3.0.0
UTF-8
- 11
- 11
+ 21
+ 21
@@ -40,28 +40,11 @@
- de.kaktushose.levelbot.Bootstrapper
+ com.github.kaktushose.nplaybot.Bootstrapper
-
- org.springframework.boot
- spring-boot-maven-plugin
- 2.6.4
-
-
-
- repackage
-
-
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 3.0.0-M5
-
@@ -81,76 +64,27 @@
net.dv8tion
JDA
- 4.4.0_352
+ 5.0.0-beta.18
com.github.Kaktushose
jda-commands
- v.2.2.0
-
-
- com.github.Kaktushose
- reactionwaiter
- 71c2dd9ba2
-
-
- com.google.apis
- google-api-services-youtube
- v3-rev125-1.19.1
-
-
- org.springframework.boot
- spring-boot-starter-data-jpa
- 2.6.4
-
-
- mysql
- mysql-connector-java
- 8.0.28
-
-
- javax.xml.bind
- jaxb-api
- 2.3.1
+ 4.0.0-beta.1
org.slf4j
slf4j-api
- 1.7.36
+ 2.0.9
ch.qos.logback
logback-classic
- 1.2.11
+ 1.4.11
ch.qos.logback
logback-core
- 1.2.11
-
-
- org.junit.jupiter
- junit-jupiter-api
- 5.8.2
- test
-
-
- org.junit.jupiter
- junit-jupiter-engine
- 5.8.2
- test
-
-
- org.springframework.boot
- spring-boot-starter-test
- 2.6.4
- test
-
-
- com.h2database
- h2
- 2.1.210
- test
+ 1.4.11
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java b/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
new file mode 100644
index 0000000..7879bd1
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
@@ -0,0 +1,14 @@
+package com.github.kaktushose.nplaybot;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class Bootstrapper {
+
+ private final static Logger log = LoggerFactory.getLogger(Bootstrapper.class);
+
+ public static void main(String[] args) {
+ log.info("Hello World!");
+ }
+}
diff --git a/src/main/java/de/kaktushose/levelbot/Bootstrapper.java b/src/main/java/de/kaktushose/levelbot/Bootstrapper.java
deleted file mode 100644
index d3530c7..0000000
--- a/src/main/java/de/kaktushose/levelbot/Bootstrapper.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package de.kaktushose.levelbot;
-
-import com.github.kaktushose.jda.commands.annotations.Produces;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.services.*;
-import de.kaktushose.levelbot.shop.data.ShopService;
-import net.dv8tion.jda.api.JDA;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-import javax.security.auth.login.LoginException;
-import java.util.concurrent.TimeUnit;
-
-@SpringBootApplication
-public class Bootstrapper {
-
- private final static Logger log = LoggerFactory.getLogger(Bootstrapper.class);
- private static Levelbot levelbot;
-
- public static void main(String[] args) throws LoginException, InterruptedException {
- long startTime = System.currentTimeMillis();
- log.info("Starting bot...");
- Thread.setDefaultUncaughtExceptionHandler((t, e) -> log.error("An unexpected error has occurred!", e));
- SpringApplication.run(Bootstrapper.class, args);
- levelbot = new Levelbot(Levelbot.GuildType.PRODUCTION);
- levelbot.start().indexMembers();
- startTime = System.currentTimeMillis() - startTime;
- log.info("Successfully started bot! Took {} seconds", TimeUnit.MILLISECONDS.toSeconds(startTime));
- }
-
- @Produces
- public UserService getUserService() {
- return levelbot.getUserService();
- }
-
- @Produces
- public ShopService getShopService() {
- return levelbot.getShopService();
- }
-
- @Produces
- public LevelService getLevelService() {
- return levelbot.getLevelService();
- }
-
- @Produces
- public SettingsService getSettingsService() {
- return levelbot.getSettingsService();
- }
-
- @Produces
- public BoosterService getBoosterService() {
- return levelbot.getBoosterService();
- }
-
- @Produces
- public EventService getEventService() {
- return levelbot.getEventService();
- }
-
- @Produces
- public JDA getJda() {
- return levelbot.getJda();
- }
-
- @Produces
- public EmbedCache getEmbedCache() {
- return levelbot.getEmbedCache();
- }
-
- @Produces
- public Levelbot getLevelbot() {
- return levelbot;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/bot/Levelbot.java b/src/main/java/de/kaktushose/levelbot/bot/Levelbot.java
deleted file mode 100644
index a8fd57f..0000000
--- a/src/main/java/de/kaktushose/levelbot/bot/Levelbot.java
+++ /dev/null
@@ -1,432 +0,0 @@
-package de.kaktushose.levelbot.bot;
-
-import com.github.kaktushose.jda.commands.JDACommands;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import com.github.kaktushose.jda.commands.embeds.EmbedDTO;
-import com.github.kaktushose.jda.commands.embeds.error.JsonErrorMessageFactory;
-import com.github.kaktushose.jda.commands.embeds.help.JsonHelpMessageFactory;
-import de.kaktushose.discord.reactionwaiter.ReactionListener;
-import de.kaktushose.levelbot.Bootstrapper;
-import de.kaktushose.levelbot.commands.moderation.WelcomeEmbedsCommand;
-import de.kaktushose.levelbot.database.model.BotUser;
-import de.kaktushose.levelbot.database.model.CollectEvent;
-import de.kaktushose.levelbot.database.model.Rank;
-import de.kaktushose.levelbot.database.services.*;
-import de.kaktushose.levelbot.listener.*;
-import de.kaktushose.levelbot.shop.ShopListener;
-import de.kaktushose.levelbot.shop.data.ShopService;
-import de.kaktushose.levelbot.shop.data.items.Item;
-import de.kaktushose.levelbot.util.Statistics;
-import net.dv8tion.jda.api.EmbedBuilder;
-import net.dv8tion.jda.api.JDA;
-import net.dv8tion.jda.api.JDABuilder;
-import net.dv8tion.jda.api.OnlineStatus;
-import net.dv8tion.jda.api.entities.*;
-import net.dv8tion.jda.api.exceptions.ErrorHandler;
-import net.dv8tion.jda.api.requests.ErrorResponse;
-import net.dv8tion.jda.api.requests.GatewayIntent;
-import net.dv8tion.jda.api.utils.ChunkingFilter;
-import net.dv8tion.jda.api.utils.MemberCachePolicy;
-import net.dv8tion.jda.api.utils.cache.CacheFlag;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.security.auth.login.LoginException;
-import java.io.File;
-import java.text.SimpleDateFormat;
-import java.time.Instant;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-@SuppressWarnings("ConstantConditions")
-public class Levelbot {
-
- private static final Logger log = LoggerFactory.getLogger(Levelbot.class);
- private final UserService userService;
- private final ShopService shopService;
- private final SettingsService settingsService;
- private final LevelService levelService;
- private final EventService eventService;
- private final BoosterService boosterService;
- private final EmbedCache embedCache;
- private final TaskScheduler taskScheduler;
- private final Statistics statistics;
- private final ShutdownHttpServer httpServer;
- private final long guildId;
- private JDACommands jdaCommands;
- private JDA jda;
- private Guild guild;
- private TextChannel botChannel;
- private TextChannel logChannel;
-
- public Levelbot() {
- userService = null;
- shopService = null;
- settingsService = null;
- levelService = null;
- eventService = null;
- boosterService = null;
- embedCache = null;
- taskScheduler = null;
- statistics = null;
- httpServer = null;
- guildId = 0;
- }
-
- public Levelbot(GuildType guildType) {
- userService = new UserService();
- shopService = new ShopService(this);
- settingsService = new SettingsService();
- eventService = new EventService(settingsService, userService);
- boosterService = new BoosterService(this);
- levelService = new LevelService(this);
- guildId = guildType.id;
- embedCache = new EmbedCache(new File("commandEmbeds.json"));
- taskScheduler = new TaskScheduler();
- statistics = new Statistics(this, guildId);
- httpServer = new ShutdownHttpServer(this, 8080);
- }
-
- public Levelbot start() throws LoginException, InterruptedException {
- log.info("Bot is running at version {}", settingsService.getVersion(guildId));
-
- embedCache.loadEmbedsToCache();
-
- log.debug("Starting jda...");
- String token = settingsService.getBotToken(guildId);
- jda = JDABuilder.create(
- token,
- GatewayIntent.GUILD_MEMBERS,
- GatewayIntent.GUILD_VOICE_STATES,
- GatewayIntent.GUILD_MESSAGES,
- GatewayIntent.GUILD_MESSAGE_REACTIONS,
- GatewayIntent.GUILD_PRESENCES
- ).disableCache(
- CacheFlag.EMOTE,
- CacheFlag.CLIENT_STATUS
- ).enableCache(
- CacheFlag.ACTIVITY
- ).setChunkingFilter(
- ChunkingFilter.ALL
- ).setMemberCachePolicy(
- MemberCachePolicy.NONE
- ).setActivity(
- Activity.playing("starting...")
- ).setStatus(
- OnlineStatus.DO_NOT_DISTURB
- ).build().awaitReady();
-
- log.debug("Registering event listeners...");
- jda.addEventListener(
- new JoinLeaveListener(this),
- new LevelListener(this),
- new ShopListener(this),
- new DailyRewardListener(this),
- new ContestEventListener(settingsService, eventService)
- );
-
- log.debug("Starting ReactionListener...");
- ReactionListener.setAutoRemove(true);
- ReactionListener.setAutoRemoveDelay(60, TimeUnit.SECONDS);
- ReactionListener.startListening(jda);
-
- log.debug("Starting jda-commands...");
- jdaCommands = JDACommands.start(jda, Bootstrapper.class, "de.kaktushose.levelbot");
- EmbedCache embeds = new EmbedCache("jdacEmbeds.json");
- embeds.loadEmbedsToCache();
- jdaCommands.getImplementationRegistry().setHelpMessageFactory(
- new JsonHelpMessageFactory(embeds)
- );
- jdaCommands.getImplementationRegistry().setErrorMessageFactory(
- new JsonErrorMessageFactory(embeds)
- );
- guild = jda.getGuildById(guildId);
- botChannel = guild.getTextChannelById(settingsService.getBotChannelId(guildId));
- logChannel = guild.getTextChannelById(settingsService.getLogChannelId(guildId));
-
- // first start of bot, check for expired items immediately
- shopService.checkForExpiredItems();
-
- // get offset time until it's 0 am, also ensures that this task only runs once every 24 hours
- long current = TimeUnit.HOURS.toMinutes(Calendar.getInstance().get(Calendar.HOUR_OF_DAY)) + Calendar.getInstance().get(Calendar.MINUTE);
- long delay = TimeUnit.HOURS.toMinutes(24) - current;
- taskScheduler.addRepetitiveTask(() -> {
- log.info("Starting daily tasks!");
- try {
- log.info("Sending dm rank infos...");
- dmRankInfo();
- log.info("Checking for expired items...");
- shopService.checkForExpiredItems();
- log.info("Checking for new nitro boosters...");
- boosterService.updateBoosterStatus(guild, botChannel, embedCache);
- log.info("Checking for booster rewards...");
- checkForNitroBoostersRewards();
- log.info("Update user statistics...");
- updateUserStatistics();
- log.info("Done!");
- } catch (Throwable t) {
- log.error("An exception has occurred while executing daily tasks!", t);
- }
- }, delay, TimeUnit.HOURS.toMinutes(24), TimeUnit.MINUTES);
-
- taskScheduler.addRepetitiveTask(() -> {
- try {
- updateStatistics();
- } catch (Throwable t) {
- log.error("An exception has occurred while updating statistics!", t);
- }
- }, 0, 4, TimeUnit.HOURS);
-
- String version = settingsService.getVersion(guildId);
- jda.getPresence().setStatus(OnlineStatus.ONLINE);
- jda.getPresence().setActivity(Activity.playing(version));
-
- getBotChannel().sendMessageEmbeds(embedCache.getEmbed("botStart")
- .injectValue("version", version)
- .toMessageEmbed()
- ).queue();
-
- httpServer.start();
-
- return this;
- }
-
- public Levelbot stop() {
- getBotChannel().sendMessageEmbeds(embedCache.getEmbed("botStop").toMessageEmbed()).complete();
- jdaCommands.shutdown();
- jda.shutdown();
- return this;
- }
-
- public void terminate(int status) {
- System.exit(status);
- }
-
- public Levelbot indexMembers() {
- log.info("Indexing members...");
- guild.loadMembers().onSuccess(guildMembers -> {
- guildMembers.forEach(member -> userService.createUserIfAbsent(member.getIdLong()));
-
- List guildMemberIds = guildMembers.stream().map(ISnowflake::getIdLong).collect(Collectors.toList());
- userService.getAllUsers().forEach(botUser -> {
- if (!guildMemberIds.contains(botUser.getUserId())) {
- log.info("Removing " + botUser.getUserId());
- userService.deleteUser(botUser.getUserId());
- }
- });
- });
- return this;
- }
-
- public void addRankRole(long userId, int rankId) {
- Rank rank = levelService.getRank(rankId);
- guild.addRoleToMember(userId, guild.getRoleById(rank.getRoleId())).queue();
- }
-
- public void removeRankRole(long userId, int rankId) {
- Rank rank = levelService.getRank(rankId);
- guild.removeRoleFromMember(userId, guild.getRoleById(rank.getRoleId())).queue();
- }
-
- public void addItemRole(long userId, int itemId) {
- Item item = levelService.getItem(itemId);
- if (item.getRoleId() == -1) {
- return;
- }
- guild.addRoleToMember(userId, guild.getRoleById(item.getRoleId())).queue();
- }
-
- public void removeItemRole(long userId, int itemId) {
- Item item = levelService.getItem(itemId);
- if (item.getRoleId() == -1) {
- return;
- }
- guild.removeRoleFromMember(userId, guild.getRoleById(item.getRoleId())).queue();
- }
-
- public void addCollectEventRole(long userId) {
- CollectEvent event = eventService.getActiveCollectEvent(guildId);
- guild.addRoleToMember(userId, guild.getRoleById(event.getRoleId())).queue();
- }
-
- public void updateUserStatistics() {
- userService.getAllUserIds().forEach(userService::updateUserStatistics);
- }
-
- public void dmRankInfo() {
- userService.getUsersByDailyEnabled().forEach(botUser -> {
- User user = jda.getUserById(botUser.getUserId());
- user.openPrivateChannel().flatMap(privateChannel ->
- privateChannel.sendMessageEmbeds(generateRankInfo(user, true).build())
- ).queue(null, new ErrorHandler().ignore(ErrorResponse.CANNOT_SEND_TO_USER));
- });
- }
-
- public void checkForNitroBoostersRewards() {
- boosterService.getActiveNitroBoosters().forEach(nitroBooster -> {
- if (TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - nitroBooster.getBoostStart()) % 30 == 0) {
- boosterService.addMonthlyReward(nitroBooster.getUserId());
- }
- });
- }
-
- public void sendItemExpiredInformation(long userId, int itemId, long buyTime) {
- User user = jda.getUserById(userId);
- Item item = levelService.getItem(itemId);
- EmbedBuilder embed = embedCache.getEmbed("itemExpired")
- .injectValue("item", item.getName())
- .injectValue("date", new SimpleDateFormat("dd.MM.yyyy HH:mm").format(new Date(buyTime)))
- .toEmbedBuilder();
- user.openPrivateChannel().flatMap(privateChannel -> privateChannel.sendMessageEmbeds(embed.build()))
- .queue(null, new ErrorHandler().handle(ErrorResponse.CANNOT_SEND_TO_USER, exception -> {
- TextChannel channel = getBotChannel();
- channel.sendMessage(user.getAsMention()).and(channel.sendMessageEmbeds(embed.build())).queue();
- }));
- }
-
- public EmbedBuilder generateRankInfo(User target, boolean dm) {
- BotUser botUser = userService.getUserById(target.getIdLong());
-
- Rank currentRank = levelService.getCurrentRank(botUser.getUserId());
- Rank nextRank = levelService.getNextRank(botUser.getUserId());
- long nextRankXp = nextRank.getBound() - botUser.getXp();
- long xpGain = botUser.getXp() - botUser.getStartXp();
- long coinsGain = botUser.getCoins() - botUser.getStartCoins();
- long diamondsGain = botUser.getDiamonds() - botUser.getStartDiamonds();
-
- // if event is active, load another template
- String embed = eventService.isCollectEventActive(guildId) ? "eventRankInfo" : "rankInfo";
-
- String currentRankInfo = dm ? currentRank.getName() : String.format("<@&%d>", currentRank.getRoleId());
- String nextRankInfo = dm ? String.format("%s (noch %d XP)", nextRank.getName(), nextRankXp) : String.format("<@&%d> (noch %d XP)", nextRank.getRoleId(), nextRankXp);
- nextRankInfo = currentRank.equals(nextRank) ? "N/A" : nextRankInfo;
- String url = target.getAvatarUrl() == null ? "https://cdn.discordapp.com/embed/avatars/0.png" : target.getAvatarUrl();
-
- EmbedDTO embedDTO = embedCache.getEmbed(embed)
- .injectValue("user", target.getAsMention())
- .injectValue("color", currentRank.getColor())
- .injectValue("currentRank", currentRankInfo)
- .injectValue("nextRank", nextRankInfo)
- .injectValue("avatarUrl", url)
- .injectValue("xpGain", xpGain)
- .injectValue("coinsGain", coinsGain)
- .injectValue("diamondsGain", diamondsGain)
- .injectFields(botUser);
-
-
- if (eventService.isCollectEventActive(guildId)) {
- CollectEvent collectEvent = eventService.getActiveCollectEvent(guildId);
- Role collectEventRole = guild.getRoleById(collectEvent.getRoleId());
- long eventPoints = botUser.getEventPoints();
- embedDTO.injectValue("eventName", collectEvent.getName())
- .injectValue("currencyName", collectEvent.getCurrencyName())
- .injectValue("currencyEmote", collectEvent.getCurrencyEmote())
- .injectValue("currencyPoints", eventPoints);
- if (eventPoints >= 24) {
- embedDTO.injectValue("eventRewards", ":red_circle: **Eventrolle XMAS 2022**\n:star2: **50 XP**\n:moneybag: **100 Münzen**");
- } else if (eventPoints >= 12) {
- embedDTO.injectValue("eventRewards", ":red_circle: **Eventrolle XMAS 2022**\n:star2: **50 XP**");
- } else if (eventPoints >= 1) {
- embedDTO.injectValue("eventRewards", ":red_circle: **Eventrolle XMAS 2022**");
- } else {
- embedDTO.injectValue("eventRewards", ":no_entry_sign: noch keine");
- }
- }
- EmbedBuilder embedBuilder = embedDTO.toEmbedBuilder();
-
- if (botUser.getTransactions().isEmpty()) {
- embedBuilder.addField("Keine Items in Besitz", "", false);
- }
-
- botUser.getTransactions().forEach(transaction -> {
- Item item = transaction.getItem();
- embedBuilder.addField(item.getName(), "noch " + item.getRemainingTimeAsDate(transaction.getBuyTime()), false);
- });
-
- return embedBuilder;
- }
-
- public void updateStatistics() {
- statistics.queryStatistics().onSuccess(stats -> {
- TextChannel channel = guild.getTextChannelById(WelcomeEmbedsCommand.WELCOME_CHANNEL_ID);
- channel.retrieveMessageById(settingsService.getStatisticsMessageId(guildId)).flatMap(message ->
- message.editMessageEmbeds(embedCache.getEmbed("statistics")
- .injectFields(statistics)
- .toEmbedBuilder()
- .setTimestamp(Instant.now())
- .build())
- ).queue();
- });
- }
-
- public UserService getUserService() {
- return userService;
- }
-
- public ShopService getShopService() {
- return shopService;
- }
-
- public LevelService getLevelService() {
- return levelService;
- }
-
- public SettingsService getSettingsService() {
- return settingsService;
- }
-
- public BoosterService getBoosterService() {
- return boosterService;
- }
-
- public EventService getEventService() {
- return eventService;
- }
-
- public JDA getJda() {
- return jda;
- }
-
- public EmbedCache getEmbedCache() {
- return embedCache;
- }
-
- public Levelbot getLevelbot() {
- return this;
- }
-
- public Guild getGuild() {
- return guild;
- }
-
- public JDACommands getJdaCommands() {
- return jdaCommands;
- }
-
- public TextChannel getBotChannel() {
- return botChannel;
- }
-
- public TextChannel getLogChannel() {
- return logChannel;
- }
-
- public TaskScheduler getTaskScheduler() {
- return taskScheduler;
- }
-
- public enum GuildType {
-
- TESTING(496614159254028289L),
- PRODUCTION(367353132772098048L);
-
- public final long id;
-
- GuildType(long id) {
- this.id = id;
- }
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/bot/ShutdownHttpServer.java b/src/main/java/de/kaktushose/levelbot/bot/ShutdownHttpServer.java
deleted file mode 100644
index d1eea7b..0000000
--- a/src/main/java/de/kaktushose/levelbot/bot/ShutdownHttpServer.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package de.kaktushose.levelbot.bot;
-
-import com.sun.net.httpserver.HttpExchange;
-import com.sun.net.httpserver.HttpHandler;
-import com.sun.net.httpserver.HttpServer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
-
-public class ShutdownHttpServer {
-
- private static final Logger log = LoggerFactory.getLogger(ShutdownHttpServer.class);
- private final Levelbot levelbot;
- private HttpServer server;
-
- public ShutdownHttpServer(Levelbot levelbot, int port) {
- this.levelbot = levelbot;
- try {
- server = HttpServer.create(new InetSocketAddress(port), 0);
- server.createContext("/api/v1/shutdown", new ShutdownHandler());
- } catch (IOException e) {
- log.error("Unable to create http server!", e);
- }
- }
-
- public void start() {
- server.start();
- }
-
- private class ShutdownHandler implements HttpHandler {
- @Override
- public void handle(HttpExchange exchange) throws IOException {
- log.info("Received shutdown request! Shutting down bot...");
- String response = "OK";
- exchange.sendResponseHeaders(200, response.getBytes(StandardCharsets.UTF_8).length);
- OutputStream outputStream = exchange.getResponseBody();
- outputStream.write(response.getBytes());
- outputStream.close();
- new Thread(() -> {
- levelbot.stop();
- levelbot.terminate(0);
- }).start();
- server.stop(0);
- }
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/bot/TaskScheduler.java b/src/main/java/de/kaktushose/levelbot/bot/TaskScheduler.java
deleted file mode 100644
index 46c23f9..0000000
--- a/src/main/java/de/kaktushose/levelbot/bot/TaskScheduler.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package de.kaktushose.levelbot.bot;
-
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-public class TaskScheduler {
-
- private final ScheduledExecutorService executorService;
-
- public TaskScheduler() {
- executorService = Executors.newScheduledThreadPool(10);
- }
-
- public void addSingleTask(Runnable runnable, long delay, TimeUnit timeUnit) {
- executorService.schedule(runnable, delay, timeUnit);
- }
-
- public void addRepetitiveTask(Runnable runnable, long initialDelay, long period, TimeUnit timeUnit) {
- executorService.scheduleAtFixedRate(runnable, initialDelay, period, timeUnit);
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/PermissionsService.java b/src/main/java/de/kaktushose/levelbot/commands/PermissionsService.java
deleted file mode 100644
index 46830b4..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/PermissionsService.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package de.kaktushose.levelbot.commands;
-
-import com.github.kaktushose.jda.commands.annotations.Component;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.dispatching.CommandContext;
-import com.github.kaktushose.jda.commands.permissions.PermissionsProvider;
-import de.kaktushose.levelbot.database.services.UserService;
-import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.entities.User;
-import org.jetbrains.annotations.NotNull;
-
-@Component
-public class PermissionsService implements PermissionsProvider {
-
- @Inject
- private UserService userService;
-
- @Override
- public boolean isMuted(@NotNull User user, @NotNull CommandContext context) {
- return userService.getMutedUsers().contains(user.getIdLong());
- }
-
- @Override
- public boolean hasPermission(@NotNull User user, @NotNull CommandContext context) {
- for (String permission : context.getCommand().getPermissions()) {
- if (!userService.getUsersByPermission(getLevelByName(permission)).contains(user.getIdLong())) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public boolean hasPermission(@NotNull Member member, @NotNull CommandContext context) {
- return hasPermission(member.getUser(), context);
- }
-
- private int getLevelByName(String name) {
- switch (name) {
- case "moderator":
- return 2;
- case "admin":
- return 3;
- default:
- //for security reasons, commands with an unknown permission string can only be executed by level owner
- return 4;
- }
- }
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/member/BotInfoCommand.java b/src/main/java/de/kaktushose/levelbot/commands/member/BotInfoCommand.java
deleted file mode 100644
index f85ee29..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/member/BotInfoCommand.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package de.kaktushose.levelbot.commands.member;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.services.SettingsService;
-
-@CommandController(value = {"botinfo", "credits"}, category = "Sonstiges")
-public class BotInfoCommand {
-
- @Inject
- private SettingsService settingsService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Bot Information",
- usage = "{prefix}botinfo",
- desc = "Zeigt allgemeine Informationen über den Bot an"
- )
- public void onBotInfo(CommandEvent event) {
- long guildId = event.getGuild().getIdLong();
- event.reply(embedCache.getEmbed("botInfo")
- .injectValue("prefix", settingsService.getBotPrefix(guildId))
- .injectValue("version", settingsService.getVersion(guildId))
- );
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/member/ChangeDiamondsCommand.java b/src/main/java/de/kaktushose/levelbot/commands/member/ChangeDiamondsCommand.java
deleted file mode 100644
index ff9f67f..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/member/ChangeDiamondsCommand.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package de.kaktushose.levelbot.commands.member;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Optional;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.discord.reactionwaiter.EmoteType;
-import de.kaktushose.discord.reactionwaiter.ReactionWaiter;
-import de.kaktushose.levelbot.database.model.BotUser;
-import de.kaktushose.levelbot.database.services.UserService;
-
-@CommandController(value = {"tauschen", "wechseln"}, category = "Levelsystem")
-public class ChangeDiamondsCommand {
-
- @Inject
- private UserService userService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Diamanten tauschen",
- usage = "{prefix}tauschen ",
- desc = "Tauscht Diamanten gegen Münzen ein. Ein Diamant ist 20 Münzen wert"
- )
- public void onChangeDiamonds(CommandEvent event, @Optional("1") long amount) {
- BotUser botUser = userService.getUserById(event.getAuthor().getIdLong());
- long diamonds = botUser.getDiamonds();
- long coins = amount * 20;
- if (diamonds == 0 || amount > diamonds) {
- event.reply(embedCache.getEmbed("missingCurrency").injectValue("currency", "Diamanten"));
- return;
- }
-
- event.reply(
- embedCache.getEmbed("confirmAction").injectValue(
- "action",
- String.format("du %d Diamanten gegen %d Münzen tauschen möchtest?", amount, coins)
- ),
- confirmMessage -> {
- confirmMessage.addReaction(EmoteType.THUMBSUP.unicode)
- .and(confirmMessage.addReaction(EmoteType.THUMBSDOWN.unicode))
- .queue();
-
- ReactionWaiter reactionWaiter = new ReactionWaiter(
- confirmMessage,
- event.getMember(),
- EmoteType.THUMBSUP.unicode,
- EmoteType.THUMBSDOWN.unicode
- );
-
- reactionWaiter.onEvent(reactionEvent -> {
- if (reactionEvent.getEmote().equals(EmoteType.THUMBSUP.unicode)) {
- userService.exchangeDiamonds(botUser.getUserId(), amount);
- confirmMessage.editMessageEmbeds(embedCache.getEmbed("diamondChangeSuccess")
- .injectValue("diamonds", amount)
- .injectValue("coins", coins)
- .toMessageEmbed()
- ).queue();
- }
- reactionWaiter.stopWaiting(true);
- });
- }
- );
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/member/GiftCommand.java b/src/main/java/de/kaktushose/levelbot/commands/member/GiftCommand.java
deleted file mode 100644
index 36ad447..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/member/GiftCommand.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package de.kaktushose.levelbot.commands.member;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.services.SettingsService;
-import de.kaktushose.levelbot.shop.data.ShopService;
-import de.kaktushose.levelbot.shop.data.items.ItemCategory;
-import de.kaktushose.levelbot.shop.data.items.ItemVariant;
-import net.dv8tion.jda.api.EmbedBuilder;
-
-import java.awt.*;
-
-@CommandController(value = "geschenk", category = "Levelsystem", isActive = false)
-public class GiftCommand {
-
- @Inject
- private SettingsService settingsService;
- @Inject
- private ShopService shopService;
- @Inject
- private Levelbot levelbot;
-
- @Command(
- name = "Geschenke",
- usage = "{prefix}geschenk",
- desc = "Fröhliche Weihnachten!"
- )
- public void onGift(CommandEvent event) {
- if (settingsService.getRewardedUsers().contains(event.getAuthor().getIdLong())) {
- event.reply("Du hast dein Geschenk bereits erhalten!");
- return;
- }
- shopService.addItem(event.getAuthor().getIdLong(), ItemCategory.PREMIUM, ItemVariant.LIGHT);
- settingsService.addRewardedUser(event.getAuthor().getIdLong());
- event.reply(new EmbedBuilder()
- .setTitle("Ein Geschenk für Dich, " + event.getMember().getEffectiveName() + ":christmas_tree::santa::snowflake:")
- .setDescription("Das ganze Serverteam wünscht Dir **frohe Festtage** und einen **guten Rutsch.**\n\n" +
- "Wir bedanken uns für Deine Treue und schenken Dir das Item:\n**:gift: PREMIUM light :star:!**\n\n" +
- "Freue dich über **15 Tage kostenfreies PREMIUM** auf dem Server mit **vielen Vorteilen!**\n\n" +
- "Dein Serverteam")
- .setColor(Color.ORANGE)
- );
- }
-
- // needed to hide the command
- @Command("dummy")
- public void onDummyCommand(CommandEvent event) {
- onGift(event);
- }
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/member/LeaderboardCommand.java b/src/main/java/de/kaktushose/levelbot/commands/member/LeaderboardCommand.java
deleted file mode 100644
index cde1041..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/member/LeaderboardCommand.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package de.kaktushose.levelbot.commands.member;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.discord.reactionwaiter.ReactionWaiter;
-import de.kaktushose.levelbot.database.services.LevelService;
-import de.kaktushose.levelbot.util.Pagination;
-import net.dv8tion.jda.api.EmbedBuilder;
-import net.dv8tion.jda.api.entities.Guild;
-import net.dv8tion.jda.api.entities.Message;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-
-import static de.kaktushose.levelbot.util.Pagination.CurrencyType;
-
-@CommandController(value = {"rangliste", "leaderboard", "lb"}, category = "Levelsystem")
-public class LeaderboardCommand {
-
- private static final String BACK = "◀️";
- private static final String FORTH = "▶️";
- private static final String XP = "\uD83C\uDF1F";
- private static final String COINS = "\uD83D\uDCB0";
- private static final String DIAMONDS = "\uD83D\uDC8E";
-
- @Inject
- private LevelService levelService;
- @Inject
- private EmbedCache embedCache;
- private Guild guild;
- private CurrencyType currencyType;
- private Map paginationMap;
-
- @Command(
- name = "Rangliste",
- usage = "{prefix}rangliste",
- desc = "Zeigt eine Rangliste der Benutzer mit den meisten XP, Münzen oder Diamanten"
- )
- public void onLeaderboard(CommandEvent event) {
- this.guild = event.getGuild();
- currencyType = CurrencyType.XP;
- paginationMap = new HashMap<>();
- paginationMap.put(CurrencyType.XP, levelService.getXpLeaderboard(10, event.getJDA()));
- paginationMap.put(CurrencyType.COINS, levelService.getCoinsLeaderboard(10, event.getJDA()));
- paginationMap.put(CurrencyType.DIAMONDS, levelService.getDiamondsLeaderboard(10, event.getJDA()));
- showLeaderboard(event, null);
- }
-
- public void showLeaderboard(CommandEvent event, Message sentMessage) {
- Pagination pagination = paginationMap.get(currencyType);
- Consumer success = message -> {
- addReactions(message, pagination.index(), pagination.pages());
- ReactionWaiter waiter = new ReactionWaiter(message, event.getMember(), BACK, FORTH, XP, COINS, DIAMONDS);
- waiter.onEvent(reactionEvent -> {
- switch (reactionEvent.getEmote()) {
- case BACK:
- if (pagination.index() == 0) {
- return;
- }
- pagination.previousPage();
- break;
- case FORTH:
- if (pagination.index() + 1 == pagination.pages()) {
- return;
- }
- pagination.nextPage();
- break;
- case XP:
- if (currencyType == CurrencyType.XP) {
- return;
- }
- currencyType = CurrencyType.XP;
- break;
- case COINS:
- if (currencyType == CurrencyType.COINS) {
- return;
- }
- currencyType = CurrencyType.COINS;
- break;
- case DIAMONDS:
- if (currencyType == CurrencyType.DIAMONDS) {
- return;
- }
- currencyType = CurrencyType.DIAMONDS;
- break;
- default:
- break;
- }
- showLeaderboard(event, message);
- waiter.stopWaiting(true);
- });
- };
-
- if (sentMessage == null) {
- event.reply(buildEmbed(pagination.getPage(), pagination.index(), pagination.pages()), success);
- } else {
- sentMessage.editMessage(buildEmbed(pagination.getPage(), pagination.index(), pagination.pages()).build()).queue(success);
- }
- }
-
- private EmbedBuilder buildEmbed(List users, int index, int page) {
- EmbedBuilder embedBuilder = embedCache.getEmbed("leaderboard")
- .injectValue("guild", guild.getName())
- .injectValue("currency", currencyType.toString())
- .toEmbedBuilder();
-
- StringBuilder stringBuilder = new StringBuilder();
- for (int i = 0; i < users.size(); i++) {
- stringBuilder.append(String.format("`%d)` ", (i + 1) + index * 10)).append(users.get(i)).append("\n");
- }
-
- return embedBuilder.setDescription(stringBuilder.toString())
- .setFooter(String.format("Seite %d/%d", index + 1, page));
- }
-
- private void addReactions(Message message, int index, int pages) {
- if (index == 0) {
- message.addReaction(FORTH).queue();
- } else if (index + 1 == pages) {
- message.addReaction(BACK).queue();
- } else {
- message.addReaction(BACK).and(message.addReaction(FORTH)).queue();
- }
- switch (currencyType) {
- case XP:
- message.addReaction(COINS).and(message.addReaction(DIAMONDS)).queue();
- break;
- case COINS:
- message.addReaction(XP).and(message.addReaction(DIAMONDS)).queue();
- break;
- case DIAMONDS:
- message.addReaction(XP).and(message.addReaction(COINS)).queue();
- break;
- }
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/member/PingCommand.java b/src/main/java/de/kaktushose/levelbot/commands/member/PingCommand.java
deleted file mode 100644
index ae896a7..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/member/PingCommand.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package de.kaktushose.levelbot.commands.member;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-
-@CommandController(value = "ping", category = "Sonstiges")
-public class PingCommand {
-
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Ping Command",
- usage = "{prefix}ping",
- desc = "Zeigt den Ping zur Discord-API an")
- public void onPing(CommandEvent event) {
- long gatewayPing = event.getJDA().getGatewayPing();
- long restPing = event.getJDA().getRestPing().complete();
- event.reply(embedCache
- .getEmbed("pingEmbed")
- .injectValue("gatewayPing", gatewayPing)
- .injectValue("restPing", restPing)
- );
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/member/RankInfoCommand.java b/src/main/java/de/kaktushose/levelbot/commands/member/RankInfoCommand.java
deleted file mode 100644
index d4befd5..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/member/RankInfoCommand.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package de.kaktushose.levelbot.commands.member;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Optional;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import de.kaktushose.levelbot.bot.Levelbot;
-import net.dv8tion.jda.api.entities.Member;
-
-@CommandController(value = {"info", "rank", "konto"}, category = "Levelsystem")
-public class RankInfoCommand {
-
- @Inject
- Levelbot levelbot;
-
- @Command(
- name = "Kontoinformation abrufen",
- usage = "{prefix}info ",
- desc = "Zeigt die Kontoinformationen zu einem User an"
- )
- public void onRankInfo(CommandEvent event, @Optional Member member) {
- Member target = member == null ? event.getMember() : member;
- event.reply(levelbot.generateRankInfo(target.getUser(), false));
- }
-}
-
diff --git a/src/main/java/de/kaktushose/levelbot/commands/member/SwitchDailyCommand.java b/src/main/java/de/kaktushose/levelbot/commands/member/SwitchDailyCommand.java
deleted file mode 100644
index d9488b3..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/member/SwitchDailyCommand.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package de.kaktushose.levelbot.commands.member;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.services.UserService;
-import net.dv8tion.jda.api.exceptions.ErrorHandler;
-import net.dv8tion.jda.api.requests.ErrorResponse;
-
-@CommandController(value = {"täglich", "daily"}, category = "Levelsystem")
-public class SwitchDailyCommand {
-
- @Inject
- private EmbedCache embedCache;
- @Inject
- private UserService userService;
-
- @Command(
- name = "Täglich Command",
- usage = "{prefix}täglich",
- desc = "Aktiviert bzw. deaktiviert die täglichen Kontoinformationen"
- )
- public void onSwitchDaily(CommandEvent event) {
- if (!userService.switchDaily(event.getAuthor().getIdLong())) {
- event.reply(embedCache.getEmbed("switchDailySuccess").injectValue("action", "deaktiviert"));
- } else {
- event.getAuthor().openPrivateChannel()
- .flatMap(privateChannel ->
- privateChannel.sendMessageEmbeds(embedCache.getEmbed("switchDailySuccess")
- .injectValue("action", "aktiviert")
- .toMessageEmbed()
- )
- )
- .queue(success -> event.getMessage().delete().queue(),
- new ErrorHandler().handle(ErrorResponse.CANNOT_SEND_TO_USER, e -> {
- userService.switchDaily(event.getAuthor().getIdLong());
- event.reply(embedCache.getEmbed("switchDailyError"));
- })
- );
- }
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/moderation/BlacklistCommand.java b/src/main/java/de/kaktushose/levelbot/commands/moderation/BlacklistCommand.java
deleted file mode 100644
index 826b845..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/moderation/BlacklistCommand.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package de.kaktushose.levelbot.commands.moderation;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.model.BotUser;
-import de.kaktushose.levelbot.database.services.UserService;
-import net.dv8tion.jda.api.entities.Member;
-
-import java.util.List;
-
-@CommandController(value = {"blacklist", "banlist", "bl"}, category = "Moderation")
-@Permission("moderator")
-public class BlacklistCommand {
-
- @Inject
- private UserService userService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Blacklist",
- usage = "{prefix}blacklist | {prefix}blacklist list",
- desc = "Benutzer, die auf der Blacklist stehen, können keine Commands ausführen",
- isSuper = true
- )
- public void onBlacklist(CommandEvent event) {
- event.sendSpecificHelpMessage();
- }
-
- @Command(
- value = "add",
- name = "Benutzer sperren",
- usage = "{prefix}blacklist add ",
- desc = "Fügt einen Benutzer zur Blacklist hinzu"
- )
- public void onBlacklistAdd(CommandEvent event, Member member) {
- BotUser executor = userService.getUserById(event.getAuthor().getIdLong());
- BotUser target = userService.getUserById(member.getIdLong());
- // can only blacklist users with lower permissions
- if (executor.getPermissionLevel() < target.getPermissionLevel()) {
- event.reply(embedCache.getEmbed("memberBlacklistInvalidTarget").injectValue("user", member.getAsMention()));
- return;
- }
- userService.setPermission(member.getIdLong(), 0);
- event.reply(embedCache.getEmbed("memberBlacklistAdd").injectValue("user", member.getAsMention()));
- }
-
- @Command(
- value = {"remove", "rm"},
- name = "Benutzer entsperren",
- usage = "{prefix}blacklist remove ",
- desc = "Entfernt einen Benutzer von der Blacklist"
- )
- public void onBlacklistRemove(CommandEvent event, Member member) {
- BotUser target = userService.getUserById(member.getIdLong());
- userService.setPermission(member.getIdLong(), 1);
- event.reply(embedCache.getEmbed("memberBlacklistRemove")
- .injectValue("user", member.getAsMention())
- );
- }
-
- @Command(
- value = {"show", "list", "view"},
- name = "Gesperrte Benutzer",
- usage = "{prefix}blacklist show",
- desc = "Zeigt alle Nutzer, die auf der Blacklist stehen"
- )
- public void onBlacklistShow(CommandEvent event) {
- List blacklist = userService.getUsersByPermission(0);
- StringBuilder members = new StringBuilder();
- blacklist.forEach(id -> members.append(event.getGuild().retrieveMemberById(id).complete().getEffectiveName()).append(", "));
- event.reply(embedCache.getEmbed("memberBlacklistShow")
- .injectValue("blacklist", members.substring(0, members.length() - 2))
- );
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/moderation/BulkDeleteCommand.java b/src/main/java/de/kaktushose/levelbot/commands/moderation/BulkDeleteCommand.java
deleted file mode 100644
index 5fb1387..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/moderation/BulkDeleteCommand.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package de.kaktushose.levelbot.commands.moderation;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.annotations.constraints.Max;
-import com.github.kaktushose.jda.commands.annotations.constraints.Min;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import net.dv8tion.jda.api.entities.Message;
-import net.dv8tion.jda.api.exceptions.ErrorHandler;
-import net.dv8tion.jda.api.requests.ErrorResponse;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-@CommandController(value = {"delete", "purge", "clear"}, category = "Moderation")
-@Permission("moderator")
-public class BulkDeleteCommand {
-
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Nachrichten löschen",
- usage = "{prefix}delete ",
- desc = "Löscht die angegebene Zahl von Nachrichten aus einem Channel"
- )
- public void onBulkDeleteMessages(
- CommandEvent event,
- @Min(value = 1, message = "Muss mindestens eine Nachricht löschen")
- @Max(value = 100, message = "Kann maximal 100 Nachrichten gleichzeitig löschen") int amount
- ) {
- // amount + 1 so we delete the command message as well
- // complete aka blocking to make sure that the success message is sent correctly
- List messageHistory = event.getChannel().getHistory().retrievePast(amount + 1).complete();
- messageHistory.forEach(message -> message.delete().complete());
-
- event.reply(embedCache.getEmbed("bulkDeleteSuccess")
- .injectValue("amount", amount),
- message -> message.delete().queueAfter(10, TimeUnit.SECONDS,
- null, new ErrorHandler().ignore(ErrorResponse.UNKNOWN_MESSAGE)
- )); // delete success message after 10 secs
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/moderation/ChangeCurrencyCommand.java b/src/main/java/de/kaktushose/levelbot/commands/moderation/ChangeCurrencyCommand.java
deleted file mode 100644
index b36ca1c..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/moderation/ChangeCurrencyCommand.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package de.kaktushose.levelbot.commands.moderation;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.services.UserService;
-import net.dv8tion.jda.api.entities.Member;
-
-@CommandController(value = "add", category = "Moderation")
-@Permission("moderator")
-public class ChangeCurrencyCommand {
-
- @Inject
- private UserService userService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Add",
- usage = "{prefix}add ",
- desc = "Ändert die Währungen eines Nutzers um den angegebenen Wert",
- isSuper = true
- )
- public void onChangeCurrency(CommandEvent event) {
- event.sendSpecificHelpMessage();
- }
-
- @Command(
- value = "coins",
- name = "Münzen ändern",
- usage = "{prefix}add coins ",
- desc = "Ändert die Anzahl der Münzen eines Benutzers um den angegebenen Wert.",
- category = "Moderation"
- )
- public void onAddCoins(CommandEvent event, Member member, Integer amount) {
- userService.addCoins(member.getIdLong(), amount);
- event.reply(embedCache.getEmbed("currencyChange")
- .injectValue("currency", "Münzen")
- .injectValue("user", member.getAsMention())
- .injectValue("value", amount)
- .injectValue("operation", amount > 0 ? "erhöht" : "verringert")
- );
- }
-
- @Command(
- value = "xp",
- name = "XP ändern",
- usage = "{prefix}add xp ",
- desc = "Ändert die Anzahl der XP eines Benutzers um den angegebenen Wert.",
- category = "Moderation"
- )
- public void onAddXp(CommandEvent event, Member member, Integer amount) {
- userService.addXp(member.getIdLong(), amount);
- event.reply(embedCache.getEmbed("currencyChange")
- .injectValue("currency", "XP")
- .injectValue("user", member.getAsMention())
- .injectValue("value", amount)
- .injectValue("operation", amount > 0 ? "erhöht" : "verringert")
- );
- }
-
- @Command(
- value = "diamonds",
- name = "Diamanten ändern",
- usage = "{prefix}add diamonds ",
- desc = "Ändert die Anzahl der Diamanten eines Benutzers um den angegebenen Wert.",
- category = "Moderation"
- )
- public void onAddDiamonds(CommandEvent event, Member member, Integer amount) {
- userService.addDiamonds(member.getIdLong(), amount);
- event.reply(embedCache.getEmbed("currencyChange")
- .injectValue("currency", "Diamanten")
- .injectValue("user", member.getAsMention())
- .injectValue("value", amount)
- .injectValue("operation", amount > 0 ? "erhöht" : "verringert")
- );
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/moderation/IgnoreChannelCommand.java b/src/main/java/de/kaktushose/levelbot/commands/moderation/IgnoreChannelCommand.java
deleted file mode 100644
index 4309e8f..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/moderation/IgnoreChannelCommand.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package de.kaktushose.levelbot.commands.moderation;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.services.SettingsService;
-import net.dv8tion.jda.api.entities.TextChannel;
-
-import java.util.List;
-
-@CommandController(value = "ignore", category = "Moderation")
-@Permission("moderator")
-public class IgnoreChannelCommand {
-
- @Inject
- private SettingsService settingsService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Textkanal muten",
- usage = "{prefix}ignore ",
- desc = "Mutet einen Textkanal",
- category = "Moderation",
- isSuper = true
- )
- public void onMutedChannelsAdd(CommandEvent event, TextChannel channel) {
- if (!settingsService.isIgnoredChannel(channel.getIdLong())) {
- settingsService.addIgnoredChannel(channel.getIdLong());
- } else {
- event.reply(embedCache.getEmbed("mutedChannelsAdd").injectValue("channel", channel.getAsMention()));
- }
- }
-
- @Command(
- value = {"remove", "rm"},
- name = "Textkanal unmuten",
- usage = "{prefix}ignore remove ",
- desc = "Unmutet einen Textkanal",
- category = "Moderation"
- )
- public void onMutedChannelsRemove(CommandEvent event, TextChannel channel) {
- settingsService.removeIgnoredChannel(channel.getIdLong());
- event.reply(embedCache.getEmbed("mutedChannelsRemove").injectValue("channel", channel.getAsMention()));
- }
-
- @Command(
- value = "list",
- name = "Gemutete Textkanäle",
- usage = "{prefix}ignore list",
- desc = "Zeigt alle Channel, die vom Levelsystem ignoriert werden",
- category = "Moderation"
- )
- public void onMutedChannelsList(CommandEvent event) {
- List mutedChannels = settingsService.getIgnoredChannels();
- StringBuilder list = new StringBuilder();
- mutedChannels.forEach(channelId -> list.append(String.format("<#%d>", channelId)).append("\n"));
- event.reply(embedCache.getEmbed("mutedChannelsList").injectValue("list", list));
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/moderation/SetCurrencyCommand.java b/src/main/java/de/kaktushose/levelbot/commands/moderation/SetCurrencyCommand.java
deleted file mode 100644
index 979287e..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/moderation/SetCurrencyCommand.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package de.kaktushose.levelbot.commands.moderation;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.services.UserService;
-import net.dv8tion.jda.api.entities.Member;
-
-@CommandController(value = "set", category = "Moderation")
-@Permission("moderator")
-public class SetCurrencyCommand {
-
- @Inject
- private UserService userService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Set",
- usage = "{prefix}set ",
- desc = "Setzt die Währungen eines Nutzers auf den angegebenen Wert",
- isSuper = true)
- public void onSetCurrency(CommandEvent event) {
- event.sendSpecificHelpMessage();
- }
-
- @Command(
- value = "coins",
- name = "Münzen setzen",
- usage = "{prefix}set coins ",
- desc = "Setzt die Anzahl der Münzen eines Benutzers auf den angegebenen Wert.",
- category = "Moderation"
- )
- public void onSetCoins(CommandEvent event, Member member, Integer amount) {
- userService.setCoins(member.getIdLong(), amount);
- event.reply(embedCache.getEmbed("currencySet")
- .injectValue("currency", "Münzen")
- .injectValue("user", member.getAsMention())
- .injectValue("value", amount)
- );
- }
-
- @Command(
- value = "xp",
- name = "XP setzen",
- usage = "{prefix}set xp ",
- desc = "Setzt die Anzahl der XP eines Benutzers auf den angegebenen Wert.",
- category = "Moderation"
- )
- public void onSetXp(CommandEvent event, Member member, Integer amount) {
- userService.setXp(member.getIdLong(), amount);
- event.reply(embedCache.getEmbed("currencySet")
- .injectValue("currency", "XP")
- .injectValue("user", member.getAsMention())
- .injectValue("value", amount)
- );
- }
-
- @Command(
- value = "diamonds",
- name = "Diamanten setzen",
- usage = "{prefix}set diamonds ",
- desc = "Setzt die Anzahl der Diamanten eines Benutzers auf den angegebenen Wert.",
- category = "Moderation"
- )
- public void onSetDiamonds(CommandEvent event, Member member, Integer amount) {
- userService.setDiamonds(member.getIdLong(), amount);
- event.reply(embedCache.getEmbed("currencySet")
- .injectValue("currency", "Diamanten")
- .injectValue("user", member.getAsMention())
- .injectValue("value", amount)
- );
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/moderation/SetPermsCommand.java b/src/main/java/de/kaktushose/levelbot/commands/moderation/SetPermsCommand.java
deleted file mode 100644
index f12eb10..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/moderation/SetPermsCommand.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package de.kaktushose.levelbot.commands.moderation;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.annotations.constraints.NotPerm;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.model.BotUser;
-import de.kaktushose.levelbot.database.services.UserService;
-import net.dv8tion.jda.api.entities.Member;
-
-@CommandController(value = "setperms", category = "Moderation")
-@Permission("moderator")
-public class SetPermsCommand {
-
- @Inject
- private UserService userService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Berechtigung ändern",
- usage = "{prefix}setperms ",
- desc = "Setzt das Berechtigungslevel eines Benutzers auf den angegebenen Wert"
- )
- public void onSetPerms(CommandEvent event, Member member, int level) {
- if (level < 1 || level > 4) {
- event.reply(embedCache.getEmbed("invalidValue")
- .injectValue("min", 1)
- .injectValue("max", 4)
- );
- return;
- }
-
- BotUser executor = userService.getUserById(event.getAuthor().getIdLong());
- BotUser target = userService.getUserById(member.getIdLong());
-
- // can only update users with lower perms
- if (executor.getPermissionLevel() < level + 1 || executor.getPermissionLevel() < target.getPermissionLevel()) {
- event.reply(embedCache.getEmbed("permissionSetInvalidTarget")
- .injectValue("user", member.getAsMention())
- );
- return;
- }
-
- userService.setPermission(target.getUserId(), level);
-
- event.reply(embedCache.getEmbed("permissionSet")
- .injectValue("user", member.getAsMention())
- .injectValue("value", level)
- );
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/moderation/WelcomeEmbedsCommand.java b/src/main/java/de/kaktushose/levelbot/commands/moderation/WelcomeEmbedsCommand.java
deleted file mode 100644
index ffc1f9d..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/moderation/WelcomeEmbedsCommand.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package de.kaktushose.levelbot.commands.moderation;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-
-import java.io.File;
-
-@CommandController(value = "sendembeds", category = "Moderation")
-@Permission("moderator")
-public class WelcomeEmbedsCommand {
-
- public static final long WELCOME_CHANNEL_ID = 851434963316375602L;
- private final EmbedCache welcomeEmbedCache;
- @Inject
- private EmbedCache embedCache;
-
- public WelcomeEmbedsCommand() {
- welcomeEmbedCache = new EmbedCache(new File("welcomeEmbeds.json"));
- }
-
- @Command(
- name = "Willkommen Embeds senden",
- usage = "{prefix}sendembeds",
- desc = "Sendet die Embeds in <#551483788337872927>"
- )
- public void sendEmbeds(CommandEvent event) {
- welcomeEmbedCache.loadEmbedsToCache();
- welcomeEmbedCache.values().forEach(embedDTO -> {
- event.getGuild().getTextChannelById(WELCOME_CHANNEL_ID).sendMessageEmbeds(embedDTO.toMessageEmbed()).queue();
- });
- }
-}
-
diff --git a/src/main/java/de/kaktushose/levelbot/commands/moderation/events/BalanceEventCommand.java b/src/main/java/de/kaktushose/levelbot/commands/moderation/events/BalanceEventCommand.java
deleted file mode 100644
index 5ab4d63..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/moderation/events/BalanceEventCommand.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package de.kaktushose.levelbot.commands.moderation.events;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.services.EventService;
-
-@CommandController(value = "balance", category = "Moderation")
-@Permission("moderator")
-public class BalanceEventCommand {
-
- @Inject
- private EventService eventService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Balance Event",
- usage = "{prefix}balance | {prefix}balance list",
- desc = "Balance Events verändern die Ausschüttung der Währungen",
- isSuper = true
- )
- public void onBalance(CommandEvent event) {
- event.sendSpecificHelpMessage();
- }
-
- @Command(
- value = "start",
- name = "Balance Event aktivieren",
- usage = "{prefix}balance start ",
- desc = "Startet das Balance Event mit der angegeben ID"
- )
- public void onBalanceEventStart(CommandEvent event, int id) {
- if (id < 0 || id > 3) {
- event.reply(embedCache.getEmbed("unknownEventId"));
- return;
- }
- String name = eventService.startBalanceEvent(id, event.getGuild().getIdLong());
- event.reply(embedCache.getEmbed("balanceEventStart").injectValue("name", name));
- }
-
- @Command(
- value = "stop",
- name = "Balance Event deaktivieren",
- usage = "{prefix}balance stop ",
- desc = "Stoppt das Balance Event mit der angegeben ID"
- )
- public void onBalanceEventStop(CommandEvent event, int id) {
- if (id < 0 || id > 3) {
- event.reply(embedCache.getEmbed("unknownEventId"));
- return;
- }
- String name = eventService.stopBalanceEvent(id, event.getGuild().getIdLong());
- event.reply(embedCache.getEmbed("balanceEventStop").injectValue("name", name));
- }
-
- @Command(
- value = "list",
- name = "Balance Event Arten",
- usage = "{prefix}balance list",
- desc = "Zeigt eine Liste aller verfügbaren Balance Events an"
- )
- public void onBalanceEventList(CommandEvent event) {
- event.reply(embedCache.getEmbed("balanceEventList"));
- }
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/moderation/events/CollectEventCommand.java b/src/main/java/de/kaktushose/levelbot/commands/moderation/events/CollectEventCommand.java
deleted file mode 100644
index 0359486..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/moderation/events/CollectEventCommand.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package de.kaktushose.levelbot.commands.moderation.events;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.model.CollectEvent;
-import de.kaktushose.levelbot.database.services.EventService;
-
-import java.util.List;
-
-@CommandController(value = "collect", category = "Moderation")
-@Permission("moderator")
-public class CollectEventCommand {
-
- @Inject
- private EventService eventService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Collect Event",
- usage = "{prefix}collect | {prefix}collect list",
- desc = "Collect Events mit zusätzlichen Währungen",
- isSuper = true
- )
- public void onCollect(CommandEvent event) {
- event.sendSpecificHelpMessage();
- }
-
- @Command(
- value = "start",
- name = "Sammel Event aktivieren",
- usage = "{prefix}collect start ",
- desc = "Startet das Sammel Event mit der angegeben ID",
- category = "Moderation"
- )
- public void onCollectEventStart(CommandEvent event, int id) {
- if (!eventService.collectEventExistsById(id)) {
- event.reply(embedCache.getEmbed("unknownEventId"));
- return;
- }
- String name = eventService.startCollectEvent(id, event.getGuild());
- event.reply(embedCache.getEmbed("collectEventStart").injectValue("name", name));
- }
-
- @Command(
- value = "stop",
- name = "Collect Event deaktivieren",
- usage = "{prefix}collect stop",
- desc = "Stoppt das aktuelle Collect Event",
- category = "Moderation"
- )
- public void onCollectEventStop(CommandEvent event) {
- if (eventService.stopCollectEvent(event.getGuild().getIdLong())) {
- event.reply(embedCache.getEmbed("collectEventStop"));
- } else {
- event.reply(embedCache.getEmbed("noActiveCollectEvent"));
- }
- }
-
- @Command(
- value = "list",
- name = "Collect Event Arten",
- usage = "{prefix}collect list",
- desc = "Zeigt eine Liste aller verfügbaren Collect Events an",
- category = "Moderation"
- )
- public void onCollectEventList(CommandEvent event) {
- List events = eventService.getAllCollectEvents();
- StringBuilder builder = new StringBuilder();
- events.forEach(collectEvent -> {
- builder.append(String.format("%d: %s\n", collectEvent.getEventId(), collectEvent.getName()));
- });
- String list = builder.length() == 0 ? "N/A" : builder.substring(0, builder.length() - 1);
- event.reply(embedCache.getEmbed("collectEventList").injectValue("list", list));
- }
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/moderation/events/ContestEventCommand.java b/src/main/java/de/kaktushose/levelbot/commands/moderation/events/ContestEventCommand.java
deleted file mode 100644
index 965aef9..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/moderation/events/ContestEventCommand.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package de.kaktushose.levelbot.commands.moderation.events;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.services.EventService;
-import net.dv8tion.jda.api.EmbedBuilder;
-import net.dv8tion.jda.api.entities.TextChannel;
-
-import java.util.List;
-
-@CommandController(value = "contest", category = "Moderation")
-@Permission("moderator")
-public class ContestEventCommand {
-
- @Inject
- private EventService eventService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Contest Event",
- usage = "{prefix}contest start | {prefix}contest stop",
- desc = "Bilder Contest Event",
- isSuper = true
- )
- public void onContest(CommandEvent event) {
- event.sendSpecificHelpMessage();
- }
-
- @Command(
- value = "start",
- name = "Contest Event aktivieren",
- usage = "{prefix}contest start ",
- desc = "Startet ein Bilder Contest Event",
- category = "Moderation"
- )
- public void onContestEventStart(CommandEvent event, TextChannel textChannel, String emote) {
- eventService.startContestEvent(event.getGuild().getIdLong(), textChannel.getIdLong(), emote);
- event.reply(embedCache.getEmbed("contestEventStart"));
- }
-
- @Command(
- value = "stop",
- name = "Contest Event deaktivieren",
- usage = "{prefix}contest stop",
- desc = "Stoppt ein Bilder Contest Event",
- category = "Moderation"
- )
- public void onContestEventStop(CommandEvent event) {
- eventService.stopContestEvent(event.getGuild().getIdLong());
- event.reply(embedCache.getEmbed("contestEventStop"));
- List users = eventService.getVoteResult(10, event.getJDA()).getPage();
- EmbedBuilder embedBuilder = embedCache.getEmbed("leaderboard")
- .injectValue("guild", "Contest Event")
- .injectValue("currency", "")
- .toEmbedBuilder();
- StringBuilder result = new StringBuilder();
- for (int i = 0; i < users.size(); i++) {
- result.append(String.format("`%d)` ", i + 1)).append(users.get(i)).append("\n");
- }
- event.reply(embedBuilder.setDescription(result.toString()));
- }
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/owner/EvalCommand.java b/src/main/java/de/kaktushose/levelbot/commands/owner/EvalCommand.java
deleted file mode 100644
index 21bf773..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/owner/EvalCommand.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package de.kaktushose.levelbot.commands.owner;
-
-import com.github.kaktushose.jda.commands.annotations.*;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.bot.Levelbot;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-
-@CommandController("eval")
-@Permission("owner")
-public class EvalCommand {
-
- private static final Logger log = LoggerFactory.getLogger(EvalCommand.class);
- private final ScriptEngine engine;
- @Inject
- private Levelbot levelbot;
- @Inject
- private EmbedCache embedCache;
-
- public EvalCommand() {
- engine = new ScriptEngineManager().getEngineByName("nashorn");
- try {
- engine.eval("var imports = new JavaImporter(" +
- "java.io," +
- "java.lang," +
- "java.util)"
- );
- } catch (ScriptException e) {
- log.error("Unable to initialize script engine!", e);
- }
- }
-
- @Command(
- name = "Code ausführen",
- usage = "{prefix}eval ",
- desc = "Führt Code in der aktuellen Runtime des Bots aus",
- category = "Owner"
- )
- public void onEval(CommandEvent event, @Concat String code) {
- log.warn("Executing eval command with code: {}", code);
- engine.put("levelbot", levelbot);
- engine.put("event", event);
- code = code.replaceAll("`", "");
-
- String script = String.format("(function() { with (imports) {%s} } )();", code);
- Object result;
- String color;
- try {
- result = engine.eval(script);
- color = "#86c240";
- } catch (ScriptException e) {
- result = e;
- color = "#aa0c14";
- }
- log.info("Eval Command returned result: {}", result);
- event.reply(embedCache.getEmbed("evalCommand")
- .injectValue("result", result)
- .injectValue("color", color)
- );
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/commands/owner/StopCommand.java b/src/main/java/de/kaktushose/levelbot/commands/owner/StopCommand.java
deleted file mode 100644
index f0daa99..0000000
--- a/src/main/java/de/kaktushose/levelbot/commands/owner/StopCommand.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package de.kaktushose.levelbot.commands.owner;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.discord.reactionwaiter.EmoteType;
-import de.kaktushose.discord.reactionwaiter.ReactionWaiter;
-import de.kaktushose.levelbot.bot.Levelbot;
-
-@CommandController(value = {"stop", "shutdown"})
-@Permission("owner")
-public class StopCommand {
-
- @Inject
- private Levelbot levelbot;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Bot herunterfahren",
- usage = "{prefix}stop",
- desc = "Fährt den Bot herunter",
- category = "Owner"
- )
- public void onStop(CommandEvent event) {
- event.reply(embedCache.getEmbed("confirmAction").injectValue(
- "action",
- "du den Bot herunterfahren möchtest?\nNur <@393843637437464588> kann den Bot wieder starten!"
- ),
- confirmMessage -> {
- confirmMessage.addReaction(EmoteType.THUMBSUP.unicode)
- .and(confirmMessage.addReaction(EmoteType.THUMBSDOWN.unicode))
- .queue();
-
- ReactionWaiter reactionWaiter = new ReactionWaiter(
- confirmMessage,
- event.getMember(),
- EmoteType.THUMBSUP.unicode,
- EmoteType.THUMBSDOWN.unicode
- );
-
- reactionWaiter.onEvent(reactionEvent -> {
- if (reactionEvent.getEmote().equals(EmoteType.THUMBSUP.unicode)) {
- event.reply("https://tenor.com/view/tekashi-69-fade-out-peace-gif-15141419");
- confirmMessage.delete().queue();
- levelbot.stop().terminate(0);
- }
- reactionWaiter.stopWaiting(true);
- });
- }
- );
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/model/BotUser.java b/src/main/java/de/kaktushose/levelbot/database/model/BotUser.java
deleted file mode 100644
index 94253d6..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/model/BotUser.java
+++ /dev/null
@@ -1,221 +0,0 @@
-package de.kaktushose.levelbot.database.model;
-
-import de.kaktushose.levelbot.shop.data.transactions.Transaction;
-import de.kaktushose.levelbot.util.Pageable;
-import de.kaktushose.levelbot.util.Pagination;
-
-import javax.persistence.*;
-import java.util.List;
-
-@Entity
-@Table(name = "users")
-public class BotUser implements Pageable {
-
- @Id
- private Long userId;
- private int level;
- private long xp;
- private long coins;
- private long diamonds;
- private long lastValidMessage;
- private long messageCount;
- private long startXp;
- private long startCoins;
- private long startDiamonds;
- @Column(name = "daily")
- private boolean dailyUpdate;
- private int permissionLevel;
- private int rewardLevel;
- private long lastReward;
- private long eventPoints;
- @OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
- @JoinColumn(name = "userId", referencedColumnName = "userId")
- private List transactions;
-
- public BotUser() {
- level = 1;
- }
-
- public BotUser(long userId) {
- this.userId = userId;
- level = 1;
- permissionLevel = 1;
- }
-
- public BotUser(long userId,
- int level,
- long xp,
- long coins,
- long diamonds,
- long lastValidMessage,
- long messageCount,
- long startXp,
- long startCoins,
- long startDiamonds,
- boolean dailyUpdate,
- int permissionLevel,
- int rewardLevel,
- long lastReward,
- long eventPoints,
- List transactions) {
- this.userId = userId;
- this.level = level;
- this.xp = xp;
- this.coins = coins;
- this.diamonds = diamonds;
- this.lastValidMessage = lastValidMessage;
- this.messageCount = messageCount;
- this.startXp = startXp;
- this.startCoins = startCoins;
- this.startDiamonds = startDiamonds;
- this.dailyUpdate = dailyUpdate;
- this.permissionLevel = permissionLevel;
- this.rewardLevel = rewardLevel;
- this.lastReward = lastReward;
- this.eventPoints = eventPoints;
- this.transactions = transactions;
- }
-
- @Override
- public Long getUserId() {
- return userId;
- }
-
- @Override
- public long getCount(Pagination.CurrencyType currencyType) {
- switch (currencyType) {
- case XP:
- return getXp();
- case DIAMONDS:
- return getDiamonds();
- case COINS:
- return getCoins();
- default:
- return 0;
- }
- }
-
- public void setUserId(Long userId) {
- this.userId = userId;
- }
-
- public int getLevel() {
- return level;
- }
-
- public void setLevel(int level) {
- this.level = level;
- }
-
- public long getXp() {
- return xp;
- }
-
- public void setXp(long xp) {
- this.xp = xp;
- }
-
- public long getCoins() {
- return coins;
- }
-
- public void setCoins(long coins) {
- this.coins = coins;
- }
-
- public long getDiamonds() {
- return diamonds;
- }
-
- public void setDiamonds(long diamonds) {
- this.diamonds = diamonds;
- }
-
- public long getLastValidMessage() {
- return lastValidMessage;
- }
-
- public void setLastValidMessage(long lastValidMessage) {
- this.lastValidMessage = lastValidMessage;
- }
-
- public long getMessageCount() {
- return messageCount;
- }
-
- public void setMessageCount(long messageCount) {
- this.messageCount = messageCount;
- }
-
- public long getStartXp() {
- return startXp;
- }
-
- public void setStartXp(long startXp) {
- this.startXp = startXp;
- }
-
- public long getStartCoins() {
- return startCoins;
- }
-
- public void setStartCoins(long startCoins) {
- this.startCoins = startCoins;
- }
-
- public long getStartDiamonds() {
- return startDiamonds;
- }
-
- public void setStartDiamonds(long startDiamonds) {
- this.startDiamonds = startDiamonds;
- }
-
- public boolean isDailyUpdate() {
- return dailyUpdate;
- }
-
- public void setDailyUpdate(boolean dailyUpdate) {
- this.dailyUpdate = dailyUpdate;
- }
-
- public int getPermissionLevel() {
- return permissionLevel;
- }
-
- public void setPermissionLevel(int permissionLevel) {
- this.permissionLevel = permissionLevel;
- }
-
- public int getRewardLevel() {
- return rewardLevel;
- }
-
- public void setRewardLevel(int rewardLevel) {
- this.rewardLevel = rewardLevel;
- }
-
- public long getLastReward() {
- return lastReward;
- }
-
- public void setLastReward(long lastReward) {
- this.lastReward = lastReward;
- }
-
- public long getEventPoints() {
- return eventPoints;
- }
-
- public void setEventPoints(long eventPoints) {
- this.eventPoints = eventPoints;
- }
-
- public List getTransactions() {
- return transactions;
- }
-
- public void setTransactions(List transactions) {
- this.transactions = transactions;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/model/CollectEvent.java b/src/main/java/de/kaktushose/levelbot/database/model/CollectEvent.java
deleted file mode 100644
index ccf095e..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/model/CollectEvent.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package de.kaktushose.levelbot.database.model;
-
-import de.kaktushose.levelbot.shop.data.items.Item;
-
-import javax.persistence.*;
-
-@Table(name = "collect_events")
-@Entity
-public class CollectEvent {
-
- @Id
- private Integer eventId;
- private String name;
- private String currencyName;
- private String currencyEmote;
- @OneToOne(fetch = FetchType.EAGER)
- @JoinColumn(name = "itemId", referencedColumnName = "itemId")
- private Item item;
- private long roleId;
- private int itemBound;
- private int roleBound;
-
- public CollectEvent() {
- }
-
- public CollectEvent(Integer eventId,
- String name,
- String currencyName,
- String currencyEmote,
- Item item,
- long roleId,
- int itemBound,
- int roleBound) {
- this.eventId = eventId;
- this.name = name;
- this.currencyName = currencyName;
- this.currencyEmote = currencyEmote;
- this.item = item;
- this.roleId = roleId;
- this.itemBound = itemBound;
- this.roleBound = roleBound;
- }
-
- public Integer getEventId() {
- return eventId;
- }
-
- public void setEventId(Integer eventId) {
- this.eventId = eventId;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getCurrencyName() {
- return currencyName;
- }
-
- public void setCurrencyName(String currencyName) {
- this.currencyName = currencyName;
- }
-
- public String getCurrencyEmote() {
- return currencyEmote;
- }
-
- public void setCurrencyEmote(String currencyEmote) {
- this.currencyEmote = currencyEmote;
- }
-
- public Item getItem() {
- return item;
- }
-
- public void setItem(Item item) {
- this.item = item;
- }
-
- public long getRoleId() {
- return roleId;
- }
-
- public void setRoleId(long roleId) {
- this.roleId = roleId;
- }
-
- public int getItemBound() {
- return itemBound;
- }
-
- public void setItemBound(int itemBound) {
- this.itemBound = itemBound;
- }
-
- public int getRoleBound() {
- return roleBound;
- }
-
- public void setRoleBound(int roleBound) {
- this.roleBound = roleBound;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/model/ContestEntry.java b/src/main/java/de/kaktushose/levelbot/database/model/ContestEntry.java
deleted file mode 100644
index 8dac324..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/model/ContestEntry.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package de.kaktushose.levelbot.database.model;
-
-import de.kaktushose.levelbot.util.Pageable;
-import de.kaktushose.levelbot.util.Pagination;
-
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-@Entity
-@Table(name = "contest_entries")
-public class ContestEntry implements Pageable {
-
- @Id
- private long messageId;
- private long count;
- private long userId;
-
- public ContestEntry() {
- }
-
- public ContestEntry(long messageId, long userId, long count) {
- this.messageId = messageId;
- this.count = count;
- this.userId = userId;
- }
-
- public Long getUserId() {
- return userId;
- }
-
- public void setUserId(long userId) {
- this.userId = userId;
- }
-
- public long getCount(Pagination.CurrencyType currencyType) {
- return count;
- }
-
- public void setCount(long count) {
- this.count = count;
- }
-
- public long getMessageId() {
- return messageId;
- }
-
- public void setMessageId(long messageId) {
- this.messageId = messageId;
- }
-
- public long getCount() {
- return count;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/model/CurrencyChance.java b/src/main/java/de/kaktushose/levelbot/database/model/CurrencyChance.java
deleted file mode 100644
index 7471696..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/model/CurrencyChance.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package de.kaktushose.levelbot.database.model;
-
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-@Entity
-@Table(name = "currency_chances")
-public class CurrencyChance {
-
- @Id
- private Integer id;
- private int amount;
- private int chance;
- private int type;
-
- public CurrencyChance() {
- }
-
- public CurrencyChance(int id, int amount, int chance, int type) {
- this.id = id;
- this.amount = amount;
- this.chance = chance;
- this.type = type;
- }
-
- public Integer getId() {
- return id;
- }
-
- public void setId(Integer id) {
- this.id = id;
- }
-
- public int getAmount() {
- return amount;
- }
-
- public void setAmount(int amount) {
- this.amount = amount;
- }
-
- public int getChance() {
- return chance;
- }
-
- public void setChance(int chance) {
- this.chance = chance;
- }
-
- public int getType() {
- return type;
- }
-
- public void setType(int type) {
- this.type = type;
- }
-
- @Override
- public String toString() {
- return "CurrencyChance{" +
- "id=" + id +
- ", amount=" + amount +
- ", chance=" + chance +
- ", type=" + type +
- '}';
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/model/GuildSettings.java b/src/main/java/de/kaktushose/levelbot/database/model/GuildSettings.java
deleted file mode 100644
index 57d3999..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/model/GuildSettings.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package de.kaktushose.levelbot.database.model;
-
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-@Entity
-@Table(name = "guild_settings")
-public class GuildSettings {
-
- @Id
- private Long guildId;
- private String version;
- private String botToken;
- private String botPrefix;
- private long botChannelId;
- private long messageCooldown;
- private String youtubeApiKey;
- private long eventChannelId;
- private String eventEmote;
- private int collectEventId;
- private long statisticsMessageId;
- private long logChannelId;
-
- public GuildSettings() {
- }
-
- public GuildSettings(Long guildId,
- String version,
- String botToken,
- String botPrefix,
- long botChannelId,
- long messageCooldown,
- String youtubeApiKey,
- long eventChannelId,
- String eventEmote,
- int collectEventId,
- long statisticsMessageId,
- long logChannelId) {
- this.guildId = guildId;
- this.version = version;
- this.botToken = botToken;
- this.botPrefix = botPrefix;
- this.botChannelId = botChannelId;
- this.messageCooldown = messageCooldown;
- this.youtubeApiKey = youtubeApiKey;
- this.eventChannelId = eventChannelId;
- this.eventEmote = eventEmote;
- this.collectEventId = collectEventId;
- this.statisticsMessageId = statisticsMessageId;
- this.logChannelId = logChannelId;
- }
-
- public Long getGuildId() {
- return guildId;
- }
-
- public void setGuildId(Long guildId) {
- this.guildId = guildId;
- }
-
- public String getVersion() {
- return version;
- }
-
- public void setVersion(String version) {
- this.version = version;
- }
-
- public String getBotToken() {
- return botToken;
- }
-
- public void setBotToken(String botToken) {
- this.botToken = botToken;
- }
-
- public String getBotPrefix() {
- return botPrefix;
- }
-
- public void setBotPrefix(String botPrefix) {
- this.botPrefix = botPrefix;
- }
-
- public long getBotChannelId() {
- return botChannelId;
- }
-
- public long getLogChannelId() {
- return logChannelId;
- }
-
- public void setBotChannelId(long botChannelId) {
- this.botChannelId = botChannelId;
- }
-
- public long getMessageCooldown() {
- return messageCooldown;
- }
-
- public void setMessageCooldown(long messageCooldown) {
- this.messageCooldown = messageCooldown;
- }
-
- public String getYoutubeApiKey() {
- return youtubeApiKey;
- }
-
- public void setYoutubeApiKey(String youtubeApiKey) {
- this.youtubeApiKey = youtubeApiKey;
- }
-
- public long getEventChannelId() {
- return eventChannelId;
- }
-
- public void setEventChannelId(long eventChannelId) {
- this.eventChannelId = eventChannelId;
- }
-
- public String getEventEmote() {
- return eventEmote;
- }
-
- public void setEventEmote(String eventEmote) {
- this.eventEmote = eventEmote;
- }
-
- public int getCollectEventId() {
- return collectEventId;
- }
-
- public void setCollectEventId(int collectEventId) {
- this.collectEventId = collectEventId;
- }
-
- public long getStatisticsMessageId() {
- return statisticsMessageId;
- }
-
- public void setStatisticsMessageId(long statisticsMessageId) {
- this.statisticsMessageId = statisticsMessageId;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/model/NitroBooster.java b/src/main/java/de/kaktushose/levelbot/database/model/NitroBooster.java
deleted file mode 100644
index 6dc545b..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/model/NitroBooster.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package de.kaktushose.levelbot.database.model;
-
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-@Entity
-@Table(name = "nitro_boosters")
-public class NitroBooster {
-
- @Id
- private Long userId;
- private long boostStart;
- private boolean active;
-
- public NitroBooster() {
-
- }
-
- public NitroBooster(Long userId, long boostStart, boolean active) {
- this.userId = userId;
- this.boostStart = boostStart;
- this.active = active;
- }
-
- public Long getUserId() {
- return userId;
- }
-
- public void setUserId(Long userId) {
- this.userId = userId;
- }
-
- public long getBoostStart() {
- return boostStart;
- }
-
- public void setBoostStart(long boostStart) {
- this.boostStart = boostStart;
- }
-
- public boolean isActive() {
- return active;
- }
-
- public void setActive(boolean active) {
- this.active = active;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/model/Rank.java b/src/main/java/de/kaktushose/levelbot/database/model/Rank.java
deleted file mode 100644
index c03d09c..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/model/Rank.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package de.kaktushose.levelbot.database.model;
-
-import javax.persistence.*;
-import java.util.List;
-
-@Entity
-@Table(name = "ranks")
-public class Rank {
-
- @Id
- private Integer rankId;
- private long roleId;
- private int bound;
- private String color;
- private String name;
- @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
- @JoinColumn(name = "rankId", referencedColumnName = "rankId")
- private List rewards;
-
- public Rank() {
- }
-
- public Rank(Integer rankId, long roleId, int bound, String color, String name) {
- this.rankId = rankId;
- this.roleId = roleId;
- this.bound = bound;
- this.color = color;
- this.name = name;
- }
-
- public Integer getRankId() {
- return rankId;
- }
-
- public void setRankId(Integer rankId) {
- this.rankId = rankId;
- }
-
- public long getRoleId() {
- return roleId;
- }
-
- public void setRoleId(long roleId) {
- this.roleId = roleId;
- }
-
- public int getBound() {
- return bound;
- }
-
- public void setBound(int bound) {
- this.bound = bound;
- }
-
- public String getColor() {
- return color;
- }
-
- public void setColor(String color) {
- this.color = color;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public List getRankRewards() {
- return rewards;
- }
-
- public void setRankRewards(List rewards) {
- this.rewards = rewards;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Rank rank = (Rank) o;
- return rankId.equals(rank.getRankId());
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/model/Reward.java b/src/main/java/de/kaktushose/levelbot/database/model/Reward.java
deleted file mode 100644
index c9bec3b..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/model/Reward.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package de.kaktushose.levelbot.database.model;
-
-import de.kaktushose.levelbot.shop.data.items.Item;
-
-import javax.persistence.*;
-
-@Entity
-@Table(name = "rewards")
-public class Reward {
-
- @Id
- private Integer rewardId;
- private int coins;
- private int xp;
- private int diamonds;
- @ManyToOne(cascade = CascadeType.ALL)
- @JoinColumn(name = "itemId", referencedColumnName = "itemId")
- private Item item;
- private String message;
-
- public Reward() {
- }
-
- public Reward(Integer rewardId, int coins, int xp, int diamonds, Item item, String message) {
- this.rewardId = rewardId;
- this.coins = coins;
- this.xp = xp;
- this.diamonds = diamonds;
- this.item = item;
- this.message = message;
- }
-
- public Integer getRewardId() {
- return rewardId;
- }
-
- public void setRewardId(Integer rewardId) {
- this.rewardId = rewardId;
- }
-
- public int getCoins() {
- return coins;
- }
-
- public void setCoins(int coins) {
- this.coins = coins;
- }
-
- public int getXp() {
- return xp;
- }
-
- public void setXp(int xp) {
- this.xp = xp;
- }
-
- public int getDiamonds() {
- return diamonds;
- }
-
- public void setDiamonds(int diamonds) {
- this.diamonds = diamonds;
- }
-
- public Item getItem() {
- return item;
- }
-
- public void setItem(Item item) {
- this.item = item;
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/repositories/ChancesRepository.java b/src/main/java/de/kaktushose/levelbot/database/repositories/ChancesRepository.java
deleted file mode 100644
index ec3beb2..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/repositories/ChancesRepository.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package de.kaktushose.levelbot.database.repositories;
-
-import de.kaktushose.levelbot.database.model.CurrencyChance;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.CrudRepository;
-
-import java.util.List;
-
-/*
-defined in table currency_chances
-type 0 = xp
-type 1 = coins
-type 2 = diamonds
- */
-public interface ChancesRepository extends CrudRepository {
-
- @Query(value = "SELECT * FROM currency_chances WHERE type = 0", nativeQuery = true)
- List getXpChances();
-
- @Query(value = "SELECT * FROM currency_chances WHERE type = 1", nativeQuery = true)
- List getCoinChances();
-
- @Query(value = "SELECT * FROM currency_chances WHERE type = 2", nativeQuery = true)
- List getDiamondChances();
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/repositories/CollectEventRepository.java b/src/main/java/de/kaktushose/levelbot/database/repositories/CollectEventRepository.java
deleted file mode 100644
index b75a4ac..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/repositories/CollectEventRepository.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package de.kaktushose.levelbot.database.repositories;
-
-import de.kaktushose.levelbot.database.model.CollectEvent;
-import org.springframework.data.repository.CrudRepository;
-
-public interface CollectEventRepository extends CrudRepository {
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/repositories/ContestRepository.java b/src/main/java/de/kaktushose/levelbot/database/repositories/ContestRepository.java
deleted file mode 100644
index 7218a6b..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/repositories/ContestRepository.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package de.kaktushose.levelbot.database.repositories;
-
-import de.kaktushose.levelbot.database.model.ContestEntry;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.CrudRepository;
-
-import java.util.List;
-
-public interface ContestRepository extends CrudRepository {
-
- @Query(value = "SELECT * FROM contest_entries order by count desc", nativeQuery = true)
- List getContestResult();
-
- boolean existsByUserId(long userId);
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/repositories/NitroBoosterRepository.java b/src/main/java/de/kaktushose/levelbot/database/repositories/NitroBoosterRepository.java
deleted file mode 100644
index 3e22585..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/repositories/NitroBoosterRepository.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package de.kaktushose.levelbot.database.repositories;
-
-import de.kaktushose.levelbot.database.model.NitroBooster;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.CrudRepository;
-
-import java.util.List;
-
-public interface NitroBoosterRepository extends CrudRepository {
-
- @Query(value = "SELECT * FROM nitro_boosters where active = true", nativeQuery = true)
- List getActiveNitroBoosters();
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/repositories/RankRepository.java b/src/main/java/de/kaktushose/levelbot/database/repositories/RankRepository.java
deleted file mode 100644
index f8d7280..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/repositories/RankRepository.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package de.kaktushose.levelbot.database.repositories;
-
-import de.kaktushose.levelbot.database.model.Rank;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.CrudRepository;
-import org.springframework.data.repository.query.Param;
-
-public interface RankRepository extends CrudRepository {
-
- @Query(value = "SELECT * FROM ranks where bound <= :xp order by bound desc limit 1", nativeQuery = true)
- Rank getRankByXp(@Param("xp") long xp);
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/repositories/RewardRepository.java b/src/main/java/de/kaktushose/levelbot/database/repositories/RewardRepository.java
deleted file mode 100644
index fa1891f..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/repositories/RewardRepository.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package de.kaktushose.levelbot.database.repositories;
-
-import de.kaktushose.levelbot.database.model.Reward;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.CrudRepository;
-
-import java.util.List;
-
-public interface RewardRepository extends CrudRepository {
-
- @Query(value = "SELECT * FROM rewards WHERE reward_id = 12", nativeQuery = true)
- Reward getMonthlyNitroBoosterReward();
-
- @Query(value = "SELECT * FROM rewards WHERE reward_id = 11", nativeQuery = true)
- Reward getOneTimeNitroBoosterReward();
-
- @Query(value = "SELECT * FROM rewards WHERE reward_id > 15", nativeQuery = true)
- List getDailyRewards();
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/repositories/SettingsRepository.java b/src/main/java/de/kaktushose/levelbot/database/repositories/SettingsRepository.java
deleted file mode 100644
index 4ace01b..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/repositories/SettingsRepository.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package de.kaktushose.levelbot.database.repositories;
-
-import de.kaktushose.levelbot.database.model.GuildSettings;
-import org.springframework.data.jpa.repository.Modifying;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.CrudRepository;
-import org.springframework.data.repository.query.Param;
-
-import javax.transaction.Transactional;
-import java.util.List;
-import java.util.Optional;
-
-public interface SettingsRepository extends CrudRepository {
-
- @Query(value = "SELECT * FROM guild_settings WHERE guild_id = :guildId", nativeQuery = true)
- Optional getGuildSettings(@Param("guildId") long guildId);
-
- @Query(value = "SELECT * FROM ignored_channels", nativeQuery = true)
- List getIgnoredChannels();
-
- @Query(value = "SELECT * FROM rewarded_users", nativeQuery = true)
- List getRewardedUsers();
-
- @Modifying
- @Transactional
- @Query(value = "INSERT INTO ignored_channels VALUES (:channelId)", nativeQuery = true)
- void addIgnoredChannel(@Param("channelId") long channelId);
-
- @Modifying
- @Transactional
- @Query(value = "INSERT INTO rewarded_users VALUES (:userId)", nativeQuery = true)
- void addRewardedUser(@Param("userId") long userId);
-
- @Modifying
- @Transactional
- @Query(value = "DELETE FROM ignored_channels where channel_id = :channelId", nativeQuery = true)
- void removeIgnoredChannel(@Param("channelId") long channelId);
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/repositories/UserRepository.java b/src/main/java/de/kaktushose/levelbot/database/repositories/UserRepository.java
deleted file mode 100644
index 897b236..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/repositories/UserRepository.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package de.kaktushose.levelbot.database.repositories;
-
-import de.kaktushose.levelbot.database.model.BotUser;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.CrudRepository;
-import org.springframework.data.repository.query.Param;
-
-import java.util.List;
-
-public interface UserRepository extends CrudRepository {
-
- @Query(value = "SELECT user_id FROM users", nativeQuery = true)
- List findAllIds();
-
- @Query(value = "SELECT user_id FROM users where permission_level <= 0", nativeQuery = true)
- List findMutedUsers();
-
- @Query(value = "SELECT user_id FROM users where permission_level >= :level", nativeQuery = true)
- List findByPermissionLevel(@Param("level") int permissionLevel);
-
- @Query(value = "SELECT * FROM users where daily = true", nativeQuery = true)
- List getAllWithDaily();
-
- @Query(value = "SELECT * FROM users order by xp desc", nativeQuery = true)
- List getXpLeaderboard();
-
- @Query(value = "SELECT * FROM users order by coins desc", nativeQuery = true)
- List getCoinsLeaderboard();
-
- @Query(value = "SELECT * FROM users order by diamonds desc", nativeQuery = true)
- List getDiamondsLeaderboard();
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/services/BoosterService.java b/src/main/java/de/kaktushose/levelbot/database/services/BoosterService.java
deleted file mode 100644
index e34cdbc..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/services/BoosterService.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package de.kaktushose.levelbot.database.services;
-
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.model.NitroBooster;
-import de.kaktushose.levelbot.database.model.Reward;
-import de.kaktushose.levelbot.database.repositories.NitroBoosterRepository;
-import de.kaktushose.levelbot.shop.data.items.ItemCategory;
-import de.kaktushose.levelbot.shop.data.items.ItemVariant;
-import de.kaktushose.levelbot.shop.data.ShopService;
-import de.kaktushose.levelbot.spring.ApplicationContextHolder;
-import net.dv8tion.jda.api.entities.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationContext;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class BoosterService {
-
- private static final Logger log = LoggerFactory.getLogger(BoosterService.class);
- private final NitroBoosterRepository nitroBoosterRepository;
- private final Levelbot levelbot;
- private final ShopService shopService;
- private final UserService userService;
- private final SettingsService settingsService;
-
- public BoosterService(Levelbot levelbot) {
- ApplicationContext context = ApplicationContextHolder.getContext();
- nitroBoosterRepository = context.getBean(NitroBoosterRepository.class);
- this.shopService = levelbot.getShopService();
- this.settingsService = levelbot.getSettingsService();
- userService = levelbot.getUserService();
- this.levelbot = levelbot;
- }
-
- public void updateBoosterStatus(Guild guild, TextChannel botChannel, EmbedCache embedCache) {
- // iterate through all actual nitro boosters
- log.debug("updateBoosterStatus started:");
- guild.findMembers(member -> member.getTimeBoosted() != null).onSuccess(boosterList -> {
- log.debug("Queried members: {}", Arrays.toString(boosterList.toArray()));
- boosterList.forEach(member -> {
- long userId = member.getIdLong();
- log.debug("Checking on {}...", member);
- // user is already registered as an active booster in db, skip this one
- if (isActiveNitroBooster(userId)) {
- log.debug("Member is active booster!");
- return;
- }
-
- // user is in db, must be a resumed booster
- if (isNitroBooster(userId)) {
- changeNitroBoosterStatus(userId, true);
- addMonthlyReward(userId);
- shopService.addItem(userId, ItemCategory.PREMIUM, ItemVariant.UNLIMITED);
- botChannel.sendMessage(member.getAsMention())
- .and(botChannel.sendMessageEmbeds(embedCache.getEmbed("nitroBoostResume")
- .injectValue("user", member.getEffectiveName())
- .toMessageEmbed()
- )).queue();
- log.debug("Member is inactive booster!");
- return;
- }
- // else, user is not in db, must be a first time booster
- createNewNitroBooster(userId);
- addOneTimeReward(userId);
- shopService.addItem(userId, ItemCategory.PREMIUM, ItemVariant.UNLIMITED);
- botChannel.sendMessage(member.getAsMention())
- .and(botChannel.sendMessageEmbeds(embedCache.getEmbed("nitroBoostStart")
- .injectValue("user", member.getEffectiveName())
- .toMessageEmbed()
- )).queue();
- log.debug("Member is new booster!");
- });
-
- log.debug("Comparing with active boosters...");
- // iterate through all active boosters and compare with actual boosters
- getActiveNitroBoosters().forEach(nitroBooster -> {
- Long userId = nitroBooster.getUserId();
- Member member = guild.retrieveMemberById(userId).complete();
- log.debug("Checking on {}...", member);
- if (boosterList.stream().map(ISnowflake::getIdLong).noneMatch(userId::equals)) {
- log.debug("Member stopped boosting!");
- changeNitroBoosterStatus(userId, false);
- shopService.removeItem(userId, ItemCategory.PREMIUM, ItemVariant.UNLIMITED);
- botChannel.sendMessage(member.getAsMention())
- .and(botChannel.sendMessageEmbeds(embedCache.getEmbed("nitroBoostStop")
- .injectValue("user", member.getAsMention())
- .toMessageEmbed()
- )).queue();
- }
- log.debug("Member is still boosting!");
- });
- }).onError(throwable -> {
- log.debug("Querying members failed!", throwable);
- throw new IllegalStateException("Unable to query boosters!", throwable);
- });
- log.debug("updateBoosterStatus finished!");
- }
-
- public List getAllNitroBoosters() {
- List result = new ArrayList<>();
- nitroBoosterRepository.findAll().forEach(result::add);
- return result;
- }
-
- public List getActiveNitroBoosters() {
- return nitroBoosterRepository.getActiveNitroBoosters();
- }
-
- public boolean isNitroBooster(long userId) {
- return nitroBoosterRepository.findById(userId).isPresent();
- }
-
- public boolean isActiveNitroBooster(long userId) {
- return getActiveNitroBoosters().stream().map(NitroBooster::getUserId).anyMatch(((Long) userId)::equals);
- }
-
- public void createNewNitroBooster(long userId) {
- nitroBoosterRepository.save(new NitroBooster(userId, System.currentTimeMillis(), true));
- }
-
- public void changeNitroBoosterStatus(long userId, boolean active) {
- if (!isNitroBooster(userId)) {
- return;
- }
- NitroBooster nitroBooster = nitroBoosterRepository.findById(userId).orElseThrow();
- nitroBooster.setActive(active);
- nitroBoosterRepository.save(nitroBooster);
- }
-
- public String addMonthlyReward(long userId) {
- Reward reward = settingsService.getMonthlyNitroBoosterReward();
- userService.addCoins(userId, reward.getCoins());
- userService.addXp(userId, reward.getXp());
- userService.addDiamonds(userId, reward.getDiamonds());
- if (reward.getItem() != null) {
- shopService.addItem(userId, reward.getItem().getItemId());
- }
- return reward.getMessage();
- }
-
- public String addOneTimeReward(long userId) {
- Reward reward = settingsService.getOneTimeNitroBoosterReward();
- userService.addCoins(userId, reward.getCoins());
- userService.addXp(userId, reward.getXp());
- userService.addDiamonds(userId, reward.getDiamonds());
- if (reward.getItem() != null) {
- shopService.addItem(userId, reward.getItem().getItemId());
- }
- return reward.getMessage();
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/services/EventService.java b/src/main/java/de/kaktushose/levelbot/database/services/EventService.java
deleted file mode 100644
index 539c125..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/services/EventService.java
+++ /dev/null
@@ -1,181 +0,0 @@
-package de.kaktushose.levelbot.database.services;
-
-import de.kaktushose.levelbot.database.model.CollectEvent;
-import de.kaktushose.levelbot.database.model.ContestEntry;
-import de.kaktushose.levelbot.database.model.CurrencyChance;
-import de.kaktushose.levelbot.database.repositories.ChancesRepository;
-import de.kaktushose.levelbot.database.repositories.CollectEventRepository;
-import de.kaktushose.levelbot.database.repositories.ContestRepository;
-import de.kaktushose.levelbot.spring.ApplicationContextHolder;
-import de.kaktushose.levelbot.util.Pagination;
-import net.dv8tion.jda.api.JDA;
-import net.dv8tion.jda.api.entities.Guild;
-import org.springframework.context.ApplicationContext;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-public class EventService {
-
- private final ChancesRepository chancesRepository;
- private final ContestRepository contestRepository;
- private final CollectEventRepository collectEventRepository;
- private final SettingsService settingsService;
- private final UserService userService;
-
- public EventService(SettingsService settingsService, UserService userService) {
- ApplicationContext context = ApplicationContextHolder.getContext();
- this.chancesRepository = context.getBean(ChancesRepository.class);
- this.contestRepository = context.getBean(ContestRepository.class);
- this.collectEventRepository = context.getBean(CollectEventRepository.class);
- this.settingsService = settingsService;
- this.userService = userService;
- }
-
- public String startBalanceEvent(int eventId, long guildId) {
- switch (eventId) {
- case 0:
- for (CurrencyChance chance : chancesRepository.getXpChances()) {
- chance.setAmount(chance.getAmount() * 2);
- chancesRepository.save(chance);
- }
- return "XP-Booster x2";
- case 1:
- for (CurrencyChance chance : chancesRepository.getCoinChances()) {
- chance.setAmount(chance.getAmount() * 2);
- chancesRepository.save(chance);
- }
- return "Münzen-Rush x2";
- case 2:
- for (CurrencyChance chance : chancesRepository.getDiamondChances()) {
- if (chance.getAmount() == 0) {
- chance.setChance(80);
- chancesRepository.save(chance);
- }
- }
- return "Diamanten-Regen x2";
- case 3:
- settingsService.setMessageCooldown(guildId, TimeUnit.MINUTES.toMillis(5));
- return "Cooldown -67%";
- default:
- return "N/A";
- }
- }
-
- public String stopBalanceEvent(int eventId, long guildId) {
- switch (eventId) {
- case 0:
- for (CurrencyChance chance : chancesRepository.getXpChances()) {
- chance.setAmount(chance.getAmount() / 2);
- chancesRepository.save(chance);
- }
- return "XP-Booster x2";
- case 1:
- for (CurrencyChance chance : chancesRepository.getCoinChances()) {
- chance.setAmount(chance.getAmount() / 2);
- chancesRepository.save(chance);
- }
- return "Münzen-Rush x2";
- case 2:
- for (CurrencyChance chance : chancesRepository.getDiamondChances()) {
- if (chance.getAmount() == 0) {
- chance.setChance(90);
- chancesRepository.save(chance);
- }
- }
- return "Diamanten-Regen x2";
- case 3:
- settingsService.setMessageCooldown(guildId, TimeUnit.MINUTES.toMillis(15));
- return "Cooldown -67%";
- default:
- return "N/A";
- }
- }
-
- public void startContestEvent(long guildId, long channelId, String emote) {
- settingsService.setEventChannelId(guildId, channelId);
- settingsService.setEventEmote(guildId, emote.replaceAll(":", ""));
- contestRepository.deleteAll();
- }
-
- public void stopContestEvent(long guildId) {
- settingsService.setEventChannelId(guildId, 0);
- settingsService.setEventEmote(guildId, "");
- }
-
- public boolean voteCountExists(long userId) {
- return contestRepository.existsByUserId(userId);
- }
-
- public boolean isSelfUser(long messageId, long userId) {
- return userId == contestRepository.findById(messageId).orElseThrow().getUserId();
- }
-
- public void increaseVoteCount(long messageId) {
- ContestEntry entry = contestRepository.findById(messageId).orElseThrow();
- entry.setCount(entry.getCount(Pagination.CurrencyType.CONTEST) + 1);
- contestRepository.save(entry);
- }
-
- public void decreaseVoteCount(long messageId) {
- ContestEntry entry = contestRepository.findById(messageId).orElseThrow();
- entry.setCount(entry.getCount(Pagination.CurrencyType.CONTEST) - 1);
- contestRepository.save(entry);
- }
-
- public void createVoteCount(long messageId, long userId) {
- contestRepository.save(new ContestEntry(messageId, userId, 0));
- }
-
- public void deleteVoteCount(long messageId) {
- if (!contestRepository.existsById(messageId)) {
- return;
- }
- contestRepository.deleteById(messageId);
- }
-
- public Pagination getVoteResult(int pageSize, JDA jda) {
- return new Pagination(pageSize, contestRepository.getContestResult(), jda, Pagination.CurrencyType.CONTEST);
- }
-
- public boolean contestEventExistsById(int id) {
- return collectEventRepository.existsById(id);
- }
-
- public boolean collectEventExistsById(int id) {
- return collectEventRepository.existsById(id);
- }
-
- public CollectEvent getCollectEvent(int id) {
- return collectEventRepository.findById(id).orElseThrow();
- }
-
- public List getAllCollectEvents() {
- List result = new ArrayList<>();
- collectEventRepository.findAll().forEach(result::add);
- return result;
- }
-
- public String startCollectEvent(int id, Guild guild) {
- settingsService.setActiveCollectEvent(guild.getIdLong(), id);
- userService.getAllUsers().forEach(botUser -> userService.resetEventPoints(botUser.getUserId()));
- return getCollectEvent(id).getName();
- }
-
- public boolean stopCollectEvent(long guildId) {
- if (!isCollectEventActive(guildId)) {
- return false;
- }
- settingsService.setActiveCollectEvent(guildId, -1);
- return true;
- }
-
- public CollectEvent getActiveCollectEvent(long guildId) {
- return getCollectEvent(settingsService.getActiveCollectEventId(guildId));
- }
-
- public boolean isCollectEventActive(long guildId) {
- return settingsService.getActiveCollectEventId(guildId) > -1;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/services/LevelService.java b/src/main/java/de/kaktushose/levelbot/database/services/LevelService.java
deleted file mode 100644
index 074e83d..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/services/LevelService.java
+++ /dev/null
@@ -1,215 +0,0 @@
-package de.kaktushose.levelbot.database.services;
-
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.model.BotUser;
-import de.kaktushose.levelbot.database.model.CurrencyChance;
-import de.kaktushose.levelbot.database.model.Rank;
-import de.kaktushose.levelbot.database.model.Reward;
-import de.kaktushose.levelbot.database.repositories.ChancesRepository;
-import de.kaktushose.levelbot.database.repositories.RankRepository;
-import de.kaktushose.levelbot.database.repositories.UserRepository;
-import de.kaktushose.levelbot.shop.data.items.ItemCategory;
-import de.kaktushose.levelbot.shop.data.ShopService;
-import de.kaktushose.levelbot.shop.data.items.Item;
-import de.kaktushose.levelbot.shop.data.items.ItemRepository;
-import de.kaktushose.levelbot.spring.ApplicationContextHolder;
-import de.kaktushose.levelbot.util.Pagination;
-import net.dv8tion.jda.api.JDA;
-import org.springframework.context.ApplicationContext;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.ThreadLocalRandom;
-
-public class LevelService {
-
- private final UserRepository userRepository;
- private final RankRepository rankRepository;
- private final ItemRepository itemRepository;
- private final ChancesRepository chancesRepository;
- private final UserService userService;
- private final SettingsService settingsService;
- private final ShopService shopService;
- private final Levelbot levelbot;
-
- public LevelService(Levelbot levelbot) {
- ApplicationContext context = ApplicationContextHolder.getContext();
- userRepository = context.getBean(UserRepository.class);
- rankRepository = context.getBean(RankRepository.class);
- itemRepository = context.getBean(ItemRepository.class);
- chancesRepository = context.getBean(ChancesRepository.class);
- this.userService = levelbot.getUserService();
- this.settingsService = levelbot.getSettingsService();
- shopService = levelbot.getShopService();
- this.levelbot = levelbot;
- }
-
- public Rank getRank(int rankId) {
- return rankRepository.findById(rankId).orElseThrow();
- }
-
- public Rank getPreviousRank(long userId) {
- BotUser botUser = userService.getUserById(userId);
- if (botUser.getLevel() == 1) {
- return getRank(1);
- }
- return getRank(botUser.getLevel() - 1);
- }
-
- public Rank getCurrentRank(long userId) {
- BotUser botUser = userService.getUserById(userId);
- return getRank(botUser.getLevel());
- }
-
- public Rank getNextRank(long userId) {
- BotUser botUser = userService.getUserById(userId);
- if (botUser.getLevel() == 13) {
- return getRank(13);
- }
- return getRank(botUser.getLevel() + 1);
- }
-
- public List- getItemsByCategoryId(int categoryId) {
- return itemRepository.findByCategoryId(categoryId);
- }
-
- public Item getItem(int itemId) {
- return itemRepository.findById(itemId).orElseThrow();
- }
-
- public boolean setItemPrice(int itemId, int price) {
- if (!itemRepository.existsById(itemId)) {
- return false;
- }
- Item item = getItem(itemId);
- item.setPrice(price);
- itemRepository.save(item);
- return true;
- }
-
- public Pagination getXpLeaderboard(int pageSize, JDA jda) {
- return new Pagination(pageSize, userRepository.getXpLeaderboard(), jda, Pagination.CurrencyType.XP);
- }
-
- public Pagination getCoinsLeaderboard(int pageSize, JDA jda) {
- return new Pagination(pageSize, userRepository.getCoinsLeaderboard(), jda, Pagination.CurrencyType.COINS);
- }
-
- public Pagination getDiamondsLeaderboard(int pageSize, JDA jda) {
- return new Pagination(pageSize, userRepository.getDiamondsLeaderboard(), jda, Pagination.CurrencyType.DIAMONDS);
- }
-
- public boolean isValidMessage(long userId, long guildId, long channelId) {
- BotUser botUser = userService.getUserById(userId);
- if (settingsService.isIgnoredChannel(channelId)) {
- return false;
- }
- if (botUser.getPermissionLevel() < 1) {
- return false;
- }
- return System.currentTimeMillis() - botUser.getLastValidMessage() >= settingsService.getMessageCooldown(guildId);
- }
-
- public long randomXp() {
- List chances = chancesRepository.getXpChances();
- int random = ThreadLocalRandom.current().nextInt(1, 101);
- for (CurrencyChance chance : chances) {
- if (random <= chance.getChance()) {
- return chance.getAmount();
- }
- }
- return 0;
- }
-
- public long randomCoins() {
- List chances = chancesRepository.getCoinChances();
- int random = ThreadLocalRandom.current().nextInt(1, 101);
- for (CurrencyChance chance : chances) {
- if (random <= chance.getChance()) {
- return chance.getAmount();
- }
- }
- return 0;
- }
-
- public long randomDiamonds() {
- List chances = chancesRepository.getDiamondChances();
- int random = ThreadLocalRandom.current().nextInt(1, 101);
- for (CurrencyChance chance : chances) {
- if (random <= chance.getChance()) {
- return chance.getAmount();
- }
- }
- return 0;
- }
-
- public Optional onValidMessage(long userId) {
- userService.updateLastValidMessage(userId);
- userService.updateMessageCount(userId);
-
- long diamonds = randomDiamonds();
- long coins = randomCoins();
- if (shopService.hasItemOfCategory(userId, ItemCategory.COIN_BOOSTER)) {
- coins += 2;
- }
- long xp = randomXp();
- if (shopService.hasItemOfCategory(userId, ItemCategory.XP_BOOSTER)) {
- xp += 2;
- }
-
- userService.addDiamonds(userId, diamonds);
- userService.addCoins(userId, coins);
- long newXp = userService.addXp(userId, xp);
-
- if (getCurrentRank(userId).getRankId() == 13) {
- return Optional.empty();
- }
-
- if (newXp < getNextRank(userId).getBound()) {
- return Optional.empty();
- }
-
- Rank rank = rankRepository.getRankByXp(newXp);
-
- return Optional.of(getRank(userService.setRank(userId, rank.getRankId())));
- }
-
- public Optional getDailyReward(long userId) {
- BotUser botUser = userService.getUserById(userId);
-
- int rewardLevel;
- if (System.currentTimeMillis() - botUser.getLastReward() >= 172800000L) {
- rewardLevel = userService.resetRewardLevel(userId);
- } else if (System.currentTimeMillis() - botUser.getLastReward() >= 86400000L) {
- rewardLevel = userService.increaseRewardLevel(userId);
- } else {
- return Optional.empty();
- }
-
- Reward reward = settingsService.getReward(rewardLevel);
- userService.addCoins(userId, reward.getCoins());
- userService.addXp(userId, reward.getXp());
- userService.addDiamonds(userId, reward.getDiamonds());
- userService.updateLastReward(userId);
- if (reward.getItem() != null) {
- shopService.addItem(userId, reward.getItem().getItemId());
- }
-
- return Optional.of(reward.getMessage());
- }
-
- public String applyRewards(long userId, int rankId) {
- Rank rank = getRank(rankId);
- StringBuilder rewardText = new StringBuilder();
- rank.getRankRewards().forEach(rankReward -> {
- userService.addCoins(userId, rankReward.getCoins());
- userService.addDiamonds(userId, rankReward.getDiamonds());
- userService.addXp(userId, rankReward.getXp());
- if (rankReward.getItem() != null) {
- shopService.addItem(userId, rankReward.getItem().getItemId());
- }
- rewardText.append(rankReward.getMessage()).append("\n");
- });
- return rewardText.substring(0, rewardText.length() - 1);
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/services/SettingsService.java b/src/main/java/de/kaktushose/levelbot/database/services/SettingsService.java
deleted file mode 100644
index 66b298f..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/services/SettingsService.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package de.kaktushose.levelbot.database.services;
-
-import de.kaktushose.levelbot.database.model.GuildSettings;
-import de.kaktushose.levelbot.database.model.Reward;
-import de.kaktushose.levelbot.database.repositories.RewardRepository;
-import de.kaktushose.levelbot.database.repositories.SettingsRepository;
-import de.kaktushose.levelbot.spring.ApplicationContextHolder;
-import org.springframework.context.ApplicationContext;
-
-import java.util.List;
-
-public class SettingsService {
-
- private final SettingsRepository settingsRepository;
- private final RewardRepository rewardRepository;
-
- public SettingsService() {
- ApplicationContext context = ApplicationContextHolder.getContext();
- this.settingsRepository = context.getBean(SettingsRepository.class);
- this.rewardRepository = context.getBean(RewardRepository.class);
- }
-
- private GuildSettings getGuildSettings(long guildId) {
- return settingsRepository.getGuildSettings(guildId).orElseThrow();
- }
-
- public long getBotChannelId(long guildId) {
- return getGuildSettings(guildId).getBotChannelId();
- }
-
- public long getLogChannelId(long guildId) {
- return getGuildSettings(guildId).getLogChannelId();
- }
-
- public String getBotPrefix(long guildId) {
- return getGuildSettings(guildId).getBotPrefix();
- }
-
- public String getBotToken(long guildId) {
- return getGuildSettings(guildId).getBotToken();
- }
-
- public String getVersion(long guildId) {
- return getGuildSettings(guildId).getVersion();
- }
-
- public long getMessageCooldown(long guildId) {
- return getGuildSettings(guildId).getMessageCooldown();
- }
-
- public void setMessageCooldown(long guildId, long cooldown) {
- GuildSettings settings = getGuildSettings(guildId);
- settings.setMessageCooldown(cooldown);
- settingsRepository.save(settings);
- }
-
- public String getYoutubeApiKey(long guildId) {
- return getGuildSettings(guildId).getYoutubeApiKey();
- }
-
- public boolean isIgnoredChannel(long channelId) {
- return settingsRepository.getIgnoredChannels().contains(channelId);
- }
-
- public List getIgnoredChannels() {
- return settingsRepository.getIgnoredChannels();
- }
-
- public void addIgnoredChannel(long channelId) {
- settingsRepository.addIgnoredChannel(channelId);
- }
-
- public void removeIgnoredChannel(long channelId) {
- settingsRepository.removeIgnoredChannel(channelId);
- }
-
- public Reward getReward(int rewardLevel) {
- return rewardRepository.findById(15 + rewardLevel).orElseThrow();
- }
-
- public Reward getMonthlyNitroBoosterReward() {
- return rewardRepository.findById(12).orElseThrow();
- }
-
- public Reward getOneTimeNitroBoosterReward() {
- return rewardRepository.findById(11).orElseThrow();
- }
-
- public List getRewardedUsers() {
- return settingsRepository.getRewardedUsers();
- }
-
- public void addRewardedUser(long userId) {
- settingsRepository.addRewardedUser(userId);
- }
-
- public void setEventChannelId(long guildId, long channelId) {
- GuildSettings settings = getGuildSettings(guildId);
- settings.setEventChannelId(channelId);
- settingsRepository.save(settings);
- }
-
- public long getEventChannelId(long guildId) {
- GuildSettings settings = getGuildSettings(guildId);
- return settings.getEventChannelId();
- }
-
- public void setEventEmote(long guildId, String emote) {
- GuildSettings settings = getGuildSettings(guildId);
- settings.setEventEmote(emote);
- settingsRepository.save(settings);
- }
-
- public String getEventEmote(long guildId) {
- GuildSettings settings = getGuildSettings(guildId);
- return settings.getEventEmote();
- }
-
- public void setActiveCollectEvent(long guildId, int id) {
- GuildSettings settings = getGuildSettings(guildId);
- settings.setCollectEventId(id);
- settingsRepository.save(settings);
- }
-
- public int getActiveCollectEventId(long guildId) {
- return getGuildSettings(guildId).getCollectEventId();
- }
-
- public long getStatisticsMessageId(long guildId) {
- return getGuildSettings(guildId).getStatisticsMessageId();
- }
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/database/services/UserService.java b/src/main/java/de/kaktushose/levelbot/database/services/UserService.java
deleted file mode 100644
index 88bfe38..0000000
--- a/src/main/java/de/kaktushose/levelbot/database/services/UserService.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package de.kaktushose.levelbot.database.services;
-
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.model.BotUser;
-import de.kaktushose.levelbot.database.repositories.UserRepository;
-import de.kaktushose.levelbot.shop.data.items.FrozenItem;
-import de.kaktushose.levelbot.shop.data.items.FrozenItemRepository;
-import de.kaktushose.levelbot.shop.data.items.Item;
-import de.kaktushose.levelbot.shop.data.items.ItemRepository;
-import de.kaktushose.levelbot.shop.data.transactions.Transaction;
-import de.kaktushose.levelbot.shop.data.transactions.TransactionRepository;
-import de.kaktushose.levelbot.spring.ApplicationContextHolder;
-import org.springframework.context.ApplicationContext;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-public class UserService {
-
- private final UserRepository userRepository;
- private final TransactionRepository transactionRepository;
- private final ItemRepository itemRepository;
- private final FrozenItemRepository frozenItemRepository;
-
- public UserService() {
- ApplicationContext context = ApplicationContextHolder.getContext();
- userRepository = context.getBean(UserRepository.class);
- transactionRepository = context.getBean(TransactionRepository.class);
- itemRepository = context.getBean(ItemRepository.class);
- frozenItemRepository = context.getBean(FrozenItemRepository.class);
- }
-
- public List getAllUsers() {
- List result = new ArrayList<>();
- userRepository.findAll().forEach(result::add);
- return result;
- }
-
- public List getAllUserIds() {
- return userRepository.findAllIds();
- }
-
- public BotUser getUserById(long userId) {
- return userRepository.findById(userId).orElseThrow();
- }
-
- public List getMutedUsers() {
- return userRepository.findMutedUsers();
- }
-
- public List getUsersByPermission(int permissionLevel) {
- return userRepository.findByPermissionLevel(permissionLevel);
- }
-
- public List getUsersByDailyEnabled() {
- return userRepository.getAllWithDaily();
- }
-
- public BotUser createUser(long userId) {
- return userRepository.save(new BotUser(userId));
- }
-
- public BotUser createUserIfAbsent(long userId) {
- Optional optional = userRepository.findById(userId);
- if (optional.isEmpty()) {
- return createUser(userId);
- }
- return optional.get();
- }
-
- public void deleteUser(long id) {
- userRepository.deleteById(id);
- }
-
- public void exchangeDiamonds(long userId, long diamonds) {
- BotUser botUser = getUserById(userId);
- botUser.setDiamonds(botUser.getDiamonds() - diamonds);
- botUser.setCoins(botUser.getCoins() + diamonds * 20);
- userRepository.save(botUser);
- }
-
- public boolean switchDaily(long userId) {
- BotUser botUser = getUserById(userId);
- botUser.setDailyUpdate(!botUser.isDailyUpdate());
- return userRepository.save(botUser).isDailyUpdate();
- }
-
- public void setPermission(long userId, int permissionLevel) {
- BotUser botUser = getUserById(userId);
- botUser.setPermissionLevel(permissionLevel);
- userRepository.save(botUser);
- }
-
- public long addCoins(long userId, long amount) {
- BotUser botUser = getUserById(userId);
- botUser.setCoins(botUser.getCoins() + amount);
- userRepository.save(botUser);
- return botUser.getCoins();
- }
-
- public long addXp(long userId, long amount) {
- BotUser botUser = getUserById(userId);
- botUser.setXp(botUser.getXp() + amount);
- userRepository.save(botUser);
- return botUser.getXp();
- }
-
- public long addDiamonds(long userId, long amount) {
- BotUser botUser = getUserById(userId);
- botUser.setDiamonds(botUser.getDiamonds() + amount);
- userRepository.save(botUser);
- return botUser.getDiamonds();
- }
-
- public void setCoins(long userId, int amount) {
- BotUser botUser = getUserById(userId);
- botUser.setCoins(amount);
- userRepository.save(botUser);
- }
-
- public void setXp(long userId, int amount) {
- BotUser botUser = getUserById(userId);
- botUser.setXp(amount);
- userRepository.save(botUser);
- }
-
- public void setDiamonds(long userId, int amount) {
- BotUser botUser = getUserById(userId);
- botUser.setDiamonds(amount);
- userRepository.save(botUser);
- }
-
- public void updateLastValidMessage(long userId) {
- BotUser botUser = getUserById(userId);
- botUser.setLastValidMessage(System.currentTimeMillis());
- userRepository.save(botUser);
- }
-
- public void updateMessageCount(long userId) {
- BotUser botUser = getUserById(userId);
- botUser.setMessageCount(botUser.getMessageCount() + 1);
- userRepository.save(botUser);
- }
-
- public void updateUserStatistics(long userId) {
- BotUser botUser = getUserById(userId);
- botUser.setStartCoins(botUser.getCoins());
- botUser.setStartXp(botUser.getXp());
- botUser.setStartDiamonds(botUser.getDiamonds());
- userRepository.save(botUser);
- }
-
- public int setRank(long userId, int rank) {
- BotUser botUser = getUserById(userId);
- if (botUser.getLevel() == 13) {
- return 13;
- }
- botUser.setLevel(rank);
- userRepository.save(botUser);
- return botUser.getLevel();
- }
-
- public int increaseRewardLevel(long userId) {
- BotUser botUser = getUserById(userId);
- int newLevel = botUser.getRewardLevel() + 1;
- newLevel = newLevel > 7 ? 1 : newLevel;
- botUser.setRewardLevel(newLevel);
- userRepository.save(botUser);
- return newLevel;
- }
-
- public int resetRewardLevel(long userId) {
- BotUser botUser = getUserById(userId);
- botUser.setRewardLevel(1);
- userRepository.save(botUser);
- return 1;
- }
-
- public void updateLastReward(long userId) {
- BotUser botUser = getUserById(userId);
- botUser.setLastReward(System.currentTimeMillis());
- userRepository.save(botUser);
- }
-
- public void resetEventPoints(long userId) {
- BotUser botUser = getUserById(userId);
- botUser.setEventPoints(0);
- userRepository.save(botUser);
- }
-
- public long increaseEventPoints(long userId) {
- BotUser botUser = getUserById(userId);
- botUser.setEventPoints(botUser.getEventPoints() + 1);
- return userRepository.save(botUser).getEventPoints();
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/listener/ContestEventListener.java b/src/main/java/de/kaktushose/levelbot/listener/ContestEventListener.java
deleted file mode 100644
index a85a0c4..0000000
--- a/src/main/java/de/kaktushose/levelbot/listener/ContestEventListener.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package de.kaktushose.levelbot.listener;
-
-import de.kaktushose.levelbot.database.services.EventService;
-import de.kaktushose.levelbot.database.services.SettingsService;
-import net.dv8tion.jda.api.events.message.guild.GenericGuildMessageEvent;
-import net.dv8tion.jda.api.events.message.guild.GuildMessageDeleteEvent;
-import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
-import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
-import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveAllEvent;
-import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEmoteEvent;
-import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent;
-import net.dv8tion.jda.api.hooks.ListenerAdapter;
-import org.jetbrains.annotations.NotNull;
-
-public class ContestEventListener extends ListenerAdapter {
-
- private final SettingsService settingsService;
- private final EventService eventService;
-
- public ContestEventListener(SettingsService settingsService, EventService eventService) {
- this.settingsService = settingsService;
- this.eventService = eventService;
- }
-
- @Override
- public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) {
- long guildId = event.getGuild().getIdLong();
- if (event.getAuthor().isBot()) {
- return;
- }
-
- if (event.getChannel().getIdLong() != settingsService.getEventChannelId(guildId)) {
- return;
- }
-
- if (eventService.voteCountExists(event.getAuthor().getIdLong())) {
- event.getMessage().delete().queue();
- return;
- }
-
- event.getMessage().addReaction(settingsService.getEventEmote(guildId)).queue();
- eventService.createVoteCount(event.getMessage().getIdLong(), event.getAuthor().getIdLong());
- }
-
- @Override
- public void onGuildMessageReactionAdd(@NotNull GuildMessageReactionAddEvent event) {
- long guildId = event.getGuild().getIdLong();
- if (event.getUser().isBot()) {
- return;
- }
- if (event.getChannel().getIdLong() != settingsService.getEventChannelId(guildId)) {
- return;
- }
- if (eventService.isSelfUser(event.getMessageIdLong(), event.getUserIdLong())) {
- event.getReaction().removeReaction(event.getUser()).queue();
- return;
- }
- if (event.getReactionEmote().getName().equals(settingsService.getEventEmote(guildId))) {
- eventService.increaseVoteCount(event.getMessageIdLong());
- }
- }
-
- // single reaction removed
- @Override
- public void onGuildMessageReactionRemove(@NotNull GuildMessageReactionRemoveEvent event) {
- long guildId = event.getGuild().getIdLong();
- if (event.getChannel().getIdLong() != settingsService.getEventChannelId(guildId)) {
- return;
- }
- if (event.getReactionEmote().getName().equals(settingsService.getEventEmote(guildId))) {
- eventService.decreaseVoteCount(event.getMessageIdLong());
- }
- }
-
- // all reactions of a emote removed
- @Override
- public void onGuildMessageReactionRemoveEmote(@NotNull GuildMessageReactionRemoveEmoteEvent event) {
- long guildId = event.getGuild().getIdLong();
- if (event.getChannel().getIdLong() != settingsService.getEventChannelId(guildId)) {
- return;
- }
- if (event.getReactionEmote().getName().equals(settingsService.getEventEmote(guildId))) {
- removeEntry(event);
- }
- }
-
- // all reactions removed
- @Override
- public void onGuildMessageReactionRemoveAll(@NotNull GuildMessageReactionRemoveAllEvent event) {
- if (event.getChannel().getIdLong() != settingsService.getEventChannelId(event.getGuild().getIdLong())) {
- return;
- }
- removeEntry(event);
- }
-
- // message deleted
- @Override
- public void onGuildMessageDelete(@NotNull GuildMessageDeleteEvent event) {
- if (event.getChannel().getIdLong() != settingsService.getEventChannelId(event.getGuild().getIdLong())) {
- return;
- }
- removeEntry(event);
- }
-
- private void removeEntry(GenericGuildMessageEvent event) {
- eventService.deleteVoteCount(event.getMessageIdLong());
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/listener/DailyRewardListener.java b/src/main/java/de/kaktushose/levelbot/listener/DailyRewardListener.java
deleted file mode 100644
index cd1968f..0000000
--- a/src/main/java/de/kaktushose/levelbot/listener/DailyRewardListener.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package de.kaktushose.levelbot.listener;
-
-import de.kaktushose.levelbot.bot.Levelbot;
-import net.dv8tion.jda.api.MessageBuilder;
-import net.dv8tion.jda.api.entities.User;
-import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
-import net.dv8tion.jda.api.hooks.ListenerAdapter;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-
-public class DailyRewardListener extends ListenerAdapter {
-
- // this should find its way into the database one day as well
- public static final long DAILY_REWARD_MESSAGE_ID = 851454384893067274L;
- private final Levelbot levelbot;
-
- public DailyRewardListener(Levelbot levelbot) {
- this.levelbot = levelbot;
- }
-
- @Override
- public void onGuildMessageReactionAdd(@NotNull GuildMessageReactionAddEvent event) {
- // bots should just be ignored
- if (event.getUser().isBot()) {
- return;
- }
- // must be right message
- if (event.getMessageIdLong() != DAILY_REWARD_MESSAGE_ID) {
- return;
- }
-
- if (levelbot.getUserService().getMutedUsers().contains(event.getUser().getIdLong())) {
- return;
- }
-
- // must be :gift: emote
- if (!event.getReactionEmote().getName().equals("\uD83C\uDF81")) {
- return;
- }
- User user = event.getUser();
- Optional reward = levelbot.getLevelService().getDailyReward(user.getIdLong());
- MessageBuilder builder = new MessageBuilder().append(user.getAsMention());
- if (reward.isPresent()) {
- builder.setEmbeds(levelbot.getEmbedCache()
- .getEmbed("dailyReward")
- .injectValue("user", user.getName())
- .injectValue("reward", reward.get())
- .toMessageEmbed()
- );
- event.getChannel().sendMessage(builder.build()).queue(message -> message.delete().queueAfter(30, TimeUnit.SECONDS));
- } else {
- long timePassed = System.currentTimeMillis() - levelbot.getUserService().getUserById(user.getIdLong()).getLastReward();
- long millis = TimeUnit.HOURS.toMillis(24) - timePassed;
- long hours = TimeUnit.MILLISECONDS.toHours(millis) - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(millis));
- builder.setEmbeds(levelbot.getEmbedCache()
- .getEmbed("rewardAlreadyClaimed")
- .injectValue("hours", hours)
- .toMessageEmbed()
- );
- event.getChannel().sendMessage(builder.build()).queue(message -> message.delete().queueAfter(30, TimeUnit.SECONDS));
- }
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/listener/JoinLeaveListener.java b/src/main/java/de/kaktushose/levelbot/listener/JoinLeaveListener.java
deleted file mode 100644
index 6343849..0000000
--- a/src/main/java/de/kaktushose/levelbot/listener/JoinLeaveListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package de.kaktushose.levelbot.listener;
-
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.model.BotUser;
-import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
-import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
-import net.dv8tion.jda.api.hooks.ListenerAdapter;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.concurrent.TimeUnit;
-
-public class JoinLeaveListener extends ListenerAdapter {
-
- private final Levelbot levelbot;
-
- public JoinLeaveListener(Levelbot levelbot) {
- this.levelbot = levelbot;
- }
-
- @Override
- public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) {
- BotUser botUser = levelbot.getUserService().createUserIfAbsent(event.getMember().getIdLong());
- levelbot.getUserService().addCoins(botUser.getUserId(), 100);
- }
-
- @Override
- public void onGuildMemberRemove(@NotNull GuildMemberRemoveEvent event) {
- levelbot.getUserService().deleteUser(event.getUser().getIdLong());
- levelbot.getBoosterService().changeNitroBoosterStatus(event.getUser().getIdLong(), false);
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/listener/LevelListener.java b/src/main/java/de/kaktushose/levelbot/listener/LevelListener.java
deleted file mode 100644
index 81a4b58..0000000
--- a/src/main/java/de/kaktushose/levelbot/listener/LevelListener.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package de.kaktushose.levelbot.listener;
-
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.model.CollectEvent;
-import de.kaktushose.levelbot.database.model.Rank;
-import de.kaktushose.levelbot.database.services.EventService;
-import de.kaktushose.levelbot.database.services.LevelService;
-import de.kaktushose.levelbot.database.services.UserService;
-import de.kaktushose.levelbot.shop.data.ShopService;
-import net.dv8tion.jda.api.entities.Guild;
-import net.dv8tion.jda.api.entities.TextChannel;
-import net.dv8tion.jda.api.entities.User;
-import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
-import net.dv8tion.jda.api.hooks.ListenerAdapter;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Optional;
-
-public class LevelListener extends ListenerAdapter {
-
- private final LevelService levelService;
- private final EventService eventService;
- private final UserService userService;
- private final ShopService shopService;
- private final EmbedCache embedCache;
- private final Levelbot levelbot;
-
- public LevelListener(Levelbot levelbot) {
- this.levelService = levelbot.getLevelService();
- this.eventService = levelbot.getEventService();
- this.userService = levelbot.getUserService();
- this.shopService = levelbot.getShopService();
- this.embedCache = levelbot.getEmbedCache();
- this.levelbot = levelbot;
- }
-
- @Override
- public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) {
- Guild guild = event.getGuild();
- long guildId = event.getGuild().getIdLong();
- User author = event.getAuthor();
- long userId = author.getIdLong();
- if (author.isBot()) {
- return;
- }
- if (!levelService.isValidMessage(userId, guildId, event.getChannel().getIdLong())) {
- return;
- }
- if (event.getMessage().getContentStripped().length() < 10) {
- return;
- }
-
- TextChannel channel = levelbot.getBotChannel();
-
- if (eventService.isCollectEventActive(guildId)) {
- CollectEvent collectEvent = eventService.getActiveCollectEvent(guildId);
- long eventPoints = userService.increaseEventPoints(userId);
-
- if (eventPoints == 1) {
- guild.addRoleToMember(userId, guild.getRoleById(collectEvent.getRoleId())).queue();
-
- channel.sendMessage(author.getAsMention())
- .and(channel.sendMessageEmbeds(embedCache.getEmbed("collectEventRoleReward")
- .injectValue("user", author.getName())
- .toMessageEmbed())
- ).queue();
- } else if (eventPoints == 12) {
- userService.addXp(userId, 50);
-
- channel.sendMessage(author.getAsMention())
- .and(channel.sendMessageEmbeds(embedCache.getEmbed("collectEventXpReward")
- .injectValue("user", author.getName())
- .toMessageEmbed())
- ).queue();
- } else if (eventPoints == 24) {
- userService.addCoins(userId, 100);
-
- channel.sendMessage(author.getAsMention())
- .and(channel.sendMessageEmbeds(embedCache.getEmbed("collectEventCoinsReward")
- .injectValue("user", author.getName())
- .toMessageEmbed())
- ).queue();
- }
- }
-
- Optional optional = levelService.onValidMessage(userId);
- if (optional.isEmpty()) {
- return;
- }
-
- Rank currentRank = optional.get();
- Rank nextRank = levelService.getNextRank(userId);
- String rewards = levelService.applyRewards(userId, currentRank.getRankId());
-
- levelbot.addRankRole(userId, currentRank.getRankId());
- levelbot.removeRankRole(userId, levelService.getPreviousRank(userId).getRankId());
-
- String nextRankInfo = currentRank.equals(nextRank) ? "N/A" : String.format("<@&%d>", nextRank.getRoleId());
- String xp = currentRank.equals(nextRank) ? "0" : String.valueOf(nextRank.getBound());
-
- channel.sendMessage(author.getAsMention())
- .and(channel.sendMessageEmbeds(embedCache.getEmbed("levelUp")
- .injectValue("user", author.getAsMention())
- .injectValue("color", currentRank.getColor())
- .injectValue("currentRank", guild.getRoleById(currentRank.getRoleId()).getAsMention())
- .injectValue("nextRank", nextRankInfo)
- .injectValue("reward", rewards)
- .injectValue("xp", xp)
- .toMessageEmbed())
- ).queue();
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/ShopListener.java b/src/main/java/de/kaktushose/levelbot/shop/ShopListener.java
deleted file mode 100644
index b9dd163..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/ShopListener.java
+++ /dev/null
@@ -1,206 +0,0 @@
-package de.kaktushose.levelbot.shop;
-
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.discord.reactionwaiter.ReactionWaiter;
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.model.BotUser;
-import de.kaktushose.levelbot.database.services.LevelService;
-import de.kaktushose.levelbot.database.services.UserService;
-import de.kaktushose.levelbot.shop.data.ShopService;
-import de.kaktushose.levelbot.shop.data.items.Item;
-import de.kaktushose.levelbot.util.NumberEmojis;
-import net.dv8tion.jda.api.MessageBuilder;
-import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.entities.Message;
-import net.dv8tion.jda.api.entities.TextChannel;
-import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
-import net.dv8tion.jda.api.exceptions.ErrorHandler;
-import net.dv8tion.jda.api.hooks.ListenerAdapter;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-import static net.dv8tion.jda.api.requests.ErrorResponse.UNKNOWN_MESSAGE;
-
-public class ShopListener extends ListenerAdapter {
-
- // this should find its way into the database one day
- public static final String PREMIUM_MESSAGE_ID = "851454666591698965";
- public static final String DJ_MESSAGE_ID = "851454738904907827";
- public static final String NICKNAME_MESSAGE_ID = "851454813623681024";
- public static final String COINS_BOOSTER_MESSAGE_ID = "851454959224225813";
- public static final String XP_BOOSTER_MESSAGE_ID = "851454895788654625";
- private static final Long LEVEL_SYSTEM_CHANNEL_ID = 851388807239827466L;
- private static final String CONFIRM = "✅";
- private static final String CANCEL = "❌";
- private final Set activeUsers;
- private final UserService userService;
- private final ShopService shopService;
- private final LevelService levelService;
- private final EmbedCache embedCache;
- private final Levelbot levelbot;
-
- public ShopListener(Levelbot levelbot) {
- this.userService = levelbot.getUserService();
- this.shopService = levelbot.getShopService();
- this.levelService = levelbot.getLevelService();
- this.embedCache = levelbot.getEmbedCache();
- this.levelbot = levelbot;
- this.activeUsers = new HashSet<>();
- }
-
- @Override
- public void onGuildMessageReactionAdd(@NotNull GuildMessageReactionAddEvent event) {
- // bots should just be ignored
- if (event.getUser().isBot()) {
- return;
- }
-
- // must be in channel #levelsystem
- if (event.getChannel().getIdLong() != LEVEL_SYSTEM_CHANNEL_ID) {
- return;
- }
-
- if (levelbot.getUserService().getMutedUsers().contains(event.getUser().getIdLong())) {
- event.getReaction().removeReaction(event.getUser()).queue(
- null, new ErrorHandler().ignore(UNKNOWN_MESSAGE)
- );
- return;
- }
-
- // indicates active purchase
- if (activeUsers.contains(event.getUser().getIdLong())) {
- event.getReaction().removeReaction(event.getUser()).queue(
- null, new ErrorHandler().ignore(UNKNOWN_MESSAGE)
- );
- return;
- }
-
- Member member = event.getMember();
- ItemCategory itemCategory;
- switch (event.getMessageId()) {
- case PREMIUM_MESSAGE_ID:
- itemCategory = ItemCategory.PREMIUM;
- break;
- case DJ_MESSAGE_ID:
- itemCategory = ItemCategory.DJ;
- break;
- case NICKNAME_MESSAGE_ID:
- itemCategory = ItemCategory.NICKNAME;
- break;
- case COINS_BOOSTER_MESSAGE_ID:
- itemCategory = ItemCategory.COINS_BOOSTER;
- break;
- case XP_BOOSTER_MESSAGE_ID:
- itemCategory = ItemCategory.XP_BOOSTER;
- break;
- default:
- event.getReaction().removeReaction(member.getUser()).queue(
- null, new ErrorHandler().ignore(UNKNOWN_MESSAGE)
- );
- return;
- }
-
- int variant;
- switch (event.getReactionEmote().getName()) {
- case NumberEmojis.ONE:
- variant = 0;
- break;
- case NumberEmojis.TWO:
- variant = 1;
- break;
- case NumberEmojis.THREE:
- variant = 2;
- break;
- default:
- event.getReaction().removeReaction(member.getUser()).queue();
- return;
- }
-
- if ((itemCategory == ItemCategory.COINS_BOOSTER || itemCategory == ItemCategory.XP_BOOSTER) && variant == 2) {
- event.getReaction().removeReaction(member.getUser()).queue();
- return;
- }
-
- Item item = levelService.getItemsByCategoryId(itemCategory.id).get(variant);
- BotUser botUser = userService.getUserById(member.getIdLong());
- String fail = null;
- if (shopService.hasItemOfCategory(member.getIdLong(), item.getCategoryId())) {
- fail = "Du besitzt dieses Item bereits!";
- }
- if (botUser.getCoins() < item.getPrice()) {
- fail = "Du hast nicht genug Münzen!";
- }
-
- TextChannel channel = event.getChannel();
-
- Consumer delete = success -> success.delete().queueAfter(
- 30, TimeUnit.SECONDS, null, new ErrorHandler().ignore(UNKNOWN_MESSAGE)
- );
-
- MessageBuilder builder = new MessageBuilder().append(member.getAsMention());
-
- if (fail != null) {
- channel.sendMessage( // transaction failed
- builder.setEmbeds(embedCache.getEmbed("shopError")
- .injectValue("message", fail)
- .toMessageEmbed()
- ).build()
- ).queue(delete);
- } else {
- activeUsers.add(member.getIdLong());
- channel.sendMessage( // confirm transaction
- builder.setEmbeds(embedCache.getEmbed("shopConfirm")
- .injectValue("item", item.getName())
- .injectValue("price", item.getPrice())
- .toMessageEmbed()
- ).build()
- ).queue(confirmMessage -> { // wait for reactions
- confirmMessage.delete().queueAfter( // delete confirm message after 30 secs if nothing happens
- 30, TimeUnit.SECONDS,
- success -> activeUsers.remove(member.getIdLong()),
- new ErrorHandler().ignore(UNKNOWN_MESSAGE)
- );
- confirmMessage.addReaction(CONFIRM).and(confirmMessage.addReaction(CANCEL)).queue();
- ReactionWaiter waiter = new ReactionWaiter(confirmMessage, event.getMember(), CONFIRM, CANCEL);
- waiter.onEvent(reactionEvent -> { // on reaction confirm or cancel emoji
- confirmMessage.delete().queue();
- if (reactionEvent.getEmote().equals(CONFIRM)) {
- shopService.buyItem(botUser.getUserId(), item.getItemId());
- channel.sendMessageEmbeds( // successful transaction
- embedCache.getEmbed("shopSuccess")
- .injectValue("item", item.getName())
- .injectValue("days", TimeUnit.MILLISECONDS.toDays(item.getDuration()))
- .toMessageEmbed()
- ).queue(delete);
- levelbot.getLogChannel().sendMessageEmbeds(embedCache.getEmbed("buyLog")
- .injectValue("user", member.getAsMention())
- .injectValue("item", item.getName())
- .toMessageEmbed()
- ).queue();
- }
- activeUsers.remove(member.getIdLong());
- waiter.stopWaiting(false);
- });
- });
- }
- event.getReaction().removeReaction(member.getUser()).queue();
- }
-
- private enum ItemCategory {
- PREMIUM(0),
- DJ(1),
- NICKNAME(2),
- COINS_BOOSTER(3),
- XP_BOOSTER(4);
-
- public final int id;
-
- ItemCategory(int id) {
- this.id = id;
- }
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/commands/AddItemCommand.java b/src/main/java/de/kaktushose/levelbot/shop/commands/AddItemCommand.java
deleted file mode 100644
index 7ab6084..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/commands/AddItemCommand.java
+++ /dev/null
@@ -1,245 +0,0 @@
-package de.kaktushose.levelbot.shop.commands;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.discord.reactionwaiter.EmoteType;
-import de.kaktushose.discord.reactionwaiter.ReactionWaiter;
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.model.BotUser;
-import de.kaktushose.levelbot.database.services.LevelService;
-import de.kaktushose.levelbot.database.services.UserService;
-import de.kaktushose.levelbot.shop.data.ShopService;
-import de.kaktushose.levelbot.shop.data.items.Item;
-import de.kaktushose.levelbot.util.NumberEmojis;
-import net.dv8tion.jda.api.EmbedBuilder;
-import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.entities.Message;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-@CommandController("additem")
-@Permission("moderator")
-public class AddItemCommand {
-
- private static final String BACK = "◀️";
- private static final String CANCEL = "❌";
- private static final String PREMIUM = "⭐";
- private static final String DJ = "\uD83C\uDFB5";
- private static final String NICKNAME = "\uD83D\uDC68\uD83C\uDFFD";
- private static final String COIN_BOOSTER = "\uD83D\uDCB0";
- private static final String XP_BOOSTER = "\uD83C\uDF1F";
- private final Map specificShops;
- @Inject
- private UserService userService;
- @Inject
- private ShopService shopService;
- @Inject
- private LevelService levelService;
- @Inject
- private EmbedCache embedCache;
- @Inject
- private Levelbot levelbot;
- private EmbedBuilder shopOverview;
-
- public AddItemCommand() {
- specificShops = new HashMap<>();
- }
-
- @Command(
- name = "Level-Shop",
- usage = "{prefix}additem ",
- desc = "Fügt ein Item einem anderen Nutzer hinzu",
- category = "Moderation"
- )
- public void onAddItem(CommandEvent event, Member member) {
- generateEmbeds(member.getAsMention());
- sendDefaultShop(event, null, member);
- }
-
- private void sendDefaultShop(CommandEvent event, Message shopMessage, Member target) {
- Consumer success = message -> {
-
- message.clearReactions()
- .and(message.addReaction(PREMIUM))
- .and(message.addReaction(DJ))
- .and(message.addReaction(NICKNAME))
- .and(message.addReaction(COIN_BOOSTER))
- .and(message.addReaction(XP_BOOSTER))
- .and(message.addReaction(CANCEL))
- .queue();
-
- ReactionWaiter reactionWaiter = new ReactionWaiter(message, event.getMember(), PREMIUM, DJ, NICKNAME, COIN_BOOSTER, XP_BOOSTER, CANCEL);
- reactionWaiter.onEvent(reactionEvent -> {
- switch (reactionEvent.getEmote()) {
- case PREMIUM:
- sendSpecificShop(event, message, target, ItemCategory.PREMIUM);
- break;
- case DJ:
- sendSpecificShop(event, message, target, ItemCategory.DJ);
- break;
- case NICKNAME:
- sendSpecificShop(event, message, target, ItemCategory.NICKNAME);
- break;
- case COIN_BOOSTER:
- sendSpecificShop(event, message, target, ItemCategory.COINS_BOOSTER);
- break;
- case XP_BOOSTER:
- sendSpecificShop(event, message, target, ItemCategory.XP_BOOSTER);
- break;
- case CANCEL:
- message.delete().and(event.getMessage().delete()).queue();
- break;
- }
- reactionWaiter.stopWaiting(false);
- });
- };
-
- if (shopMessage == null) {
- event.reply(shopOverview, success);
- } else {
- shopMessage.editMessage(shopOverview.build()).queue(success);
- }
- }
-
- private void sendSpecificShop(CommandEvent event, Message shopMessage, Member target, ItemCategory itemCategory) {
- EmbedBuilder embedBuilder = specificShops.get(itemCategory);
- List
- items = levelService.getItemsByCategoryId(itemCategory.id);
- long amount = items.stream().filter(Item::isVisible).count();
- Consumer success = message -> {
- message.clearReactions().queue();
- for (int i = 0; i < amount; i++) {
- message.addReaction(EmoteType.getNumber(i + 1).unicode).queue();
- }
- message.addReaction(BACK)
- .and(message.addReaction(CANCEL))
- .queue();
-
- ReactionWaiter reactionWaiter = new ReactionWaiter(
- message,
- event.getMember(),
- BACK, CANCEL,
- NumberEmojis.ONE, NumberEmojis.TWO, NumberEmojis.THREE, NumberEmojis.FOUR
- );
- reactionWaiter.onEvent(reactionEvent -> {
- int variant = 0;
- switch (reactionEvent.getEmote()) {
- case NumberEmojis.ONE:
- variant = 1;
- break;
- case NumberEmojis.TWO:
- variant = 2;
- break;
- case NumberEmojis.THREE:
- variant = 3;
- break;
- case NumberEmojis.FOUR:
- variant = 4;
- break;
- case BACK:
- sendDefaultShop(event, message, target);
- reactionWaiter.stopWaiting(false);
- return;
- case CANCEL:
- message.delete().and(event.getMessage().delete()).queue();
- reactionWaiter.stopWaiting(false);
- return;
- }
- if (amount < variant) {
- return;
- }
-
- Item item = items.get(variant - 1);
- Optional buyResult = addItem(target, item);
-
- if (buyResult.isEmpty()) {
- message.editMessage(embedCache.getEmbed("addItemSuccess")
- .injectValue("user", target.getAsMention())
- .injectValue("item", item.getName())
- .injectValue("days", TimeUnit.MILLISECONDS.toDays(item.getDuration()))
- .toMessageEmbed()
- ).and(message.clearReactions()).queue();
- } else {
- message.editMessage(embedCache.getEmbed("shopError")
- .injectValue("message", buyResult.get())
- .toMessageEmbed()
- ).queue(errorMessage -> {
- errorMessage.clearReactions().queue();
- errorMessage.addReaction(BACK).and(errorMessage.addReaction(CANCEL)).queue();
- ReactionWaiter waiter = new ReactionWaiter(message, event.getMember(), BACK, CANCEL);
- waiter.onEvent(errorMessageEvent -> {
- if (errorMessageEvent.getEmote().equals(BACK)) {
- sendDefaultShop(event, message, target);
- } else {
- message.delete().and(event.getMessage().delete()).queue();
- }
- waiter.stopWaiting(false);
- });
- });
- }
- reactionWaiter.stopWaiting(false);
- });
- };
-
- if (shopMessage == null) {
- event.reply(embedBuilder, success);
- } else {
- shopMessage.editMessage(embedBuilder.build()).queue(success);
- }
- }
-
- private Optional addItem(Member member, Item item) {
- BotUser botUser = userService.getUserById(member.getIdLong());
-
- if (shopService.hasItem(member.getIdLong(), item.getItemId())) {
- return Optional.of(member.getAsMention() + " besitzt dieses Item bereits!");
- }
-
- shopService.addItem(botUser.getUserId(), item.getItemId());
-
- return Optional.empty();
- }
-
- private void generateEmbeds(String mention) {
- shopOverview = embedCache.getEmbed("shopOverview").injectValue("user", mention).toEmbedBuilder();
-
- for (ItemCategory itemCategory : ItemCategory.values()) {
- EmbedBuilder specificShop = embedCache.getEmbed("specificShop").toEmbedBuilder();
- List
- items = levelService.getItemsByCategoryId(itemCategory.id);
- for (int i = 0; i < items.size(); i++) {
- Item item = items.get(i);
- if (!item.isVisible()) {
- continue;
- }
- specificShop.addField(
- String.format("%s: %s", EmoteType.getNumber(i + 1).unicode, item.getName()),
- String.format("Preis: %s :moneybag:\nDauer: %d Tage", item.getPrice(), TimeUnit.MILLISECONDS.toDays(item.getDuration())),
- false
- );
- }
- specificShops.put(itemCategory, specificShop);
- }
- }
-
- private enum ItemCategory {
- PREMIUM(0),
- DJ(1),
- NICKNAME(2),
- COINS_BOOSTER(3),
- XP_BOOSTER(4);
-
- public final int id;
-
- ItemCategory(int id) {
- this.id = id;
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/de/kaktushose/levelbot/shop/commands/InitShopCommand.java b/src/main/java/de/kaktushose/levelbot/shop/commands/InitShopCommand.java
deleted file mode 100644
index de038ca..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/commands/InitShopCommand.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package de.kaktushose.levelbot.shop.commands;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.services.SettingsService;
-import de.kaktushose.levelbot.listener.DailyRewardListener;
-import de.kaktushose.levelbot.shop.ShopListener;
-import de.kaktushose.levelbot.util.NumberEmojis;
-import net.dv8tion.jda.api.entities.TextChannel;
-
-@CommandController("initshop")
-@Permission("moderator")
-public class InitShopCommand {
-
- @Inject
- private SettingsService settingsService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Reaction Shop einrichten",
- usage = "{prefix}initshop ",
- desc = "Fügt die benötigten Reactions für den Shop hinzu",
- category = "Moderation"
- )
- public void initShop(CommandEvent event, TextChannel channel) {
- channel.retrieveMessageById(ShopListener.PREMIUM_MESSAGE_ID).queue(msg -> msg.clearReactions()
- .and(msg.addReaction(NumberEmojis.ONE))
- .and(msg.addReaction(NumberEmojis.TWO))
- .and(msg.addReaction(NumberEmojis.THREE))
- .queue()
- );
- channel.retrieveMessageById(ShopListener.DJ_MESSAGE_ID).queue(msg -> msg.clearReactions()
- .and(msg.addReaction(NumberEmojis.ONE))
- .and(msg.addReaction(NumberEmojis.TWO))
- .and(msg.addReaction(NumberEmojis.THREE))
- .queue()
- );
- channel.retrieveMessageById(ShopListener.NICKNAME_MESSAGE_ID).queue(msg -> msg.clearReactions()
- .and(msg.addReaction(NumberEmojis.ONE))
- .and(msg.addReaction(NumberEmojis.TWO))
- .and(msg.addReaction(NumberEmojis.THREE))
- .queue()
- );
- channel.retrieveMessageById(ShopListener.COINS_BOOSTER_MESSAGE_ID).queue(msg -> msg.clearReactions()
- .and(msg.addReaction(NumberEmojis.ONE))
- .and(msg.addReaction(NumberEmojis.TWO))
- .queue()
- );
- channel.retrieveMessageById(ShopListener.XP_BOOSTER_MESSAGE_ID).queue(msg -> msg.clearReactions()
- .and(msg.addReaction(NumberEmojis.ONE))
- .and(msg.addReaction(NumberEmojis.TWO))
- .queue()
- );
- channel.retrieveMessageById(DailyRewardListener.DAILY_REWARD_MESSAGE_ID).queue(msg -> msg.clearReactions()
- .and(msg.addReaction("\uD83C\uDF81"))
- .queue()
- );
- event.reply(embedCache.getEmbed("shopInitSuccess"));
- }
-}
-
diff --git a/src/main/java/de/kaktushose/levelbot/shop/commands/RemoveItemCommand.java b/src/main/java/de/kaktushose/levelbot/shop/commands/RemoveItemCommand.java
deleted file mode 100644
index 88fe981..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/commands/RemoveItemCommand.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package de.kaktushose.levelbot.shop.commands;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.discord.reactionwaiter.EmoteType;
-import de.kaktushose.discord.reactionwaiter.ReactionWaiter;
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.shop.data.ShopService;
-import de.kaktushose.levelbot.shop.data.items.Item;
-import de.kaktushose.levelbot.util.NumberEmojis;
-import net.dv8tion.jda.api.EmbedBuilder;
-import net.dv8tion.jda.api.entities.Member;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-@CommandController({"remove", "rm"})
-@Permission("moderator")
-public class RemoveItemCommand {
-
- @Inject
- private ShopService shopService;
- @Inject
- private EmbedCache embedCache;
- @Inject
- private Levelbot levelbot;
-
- @Command(
- name = "Item entfernen",
- usage = "{prefix}remove ",
- desc = "Entfernt ein Item aus dem Besitz eines Benutzers",
- category = "Moderation"
- )
- public void onRemoveItem(CommandEvent event, Member member) {
- List
- items = shopService.getItems(member.getIdLong());
- AtomicInteger counter = new AtomicInteger(1);
- List emotes = new ArrayList<>();
- EmbedBuilder builder = embedCache.getEmbed("removeItem")
- .injectValue("user", member.getAsMention())
- .toEmbedBuilder();
-
- items.forEach(item -> {
- String emote = EmoteType.getNumber(counter.getAndIncrement()).unicode;
- emotes.add(emote);
- builder.addField(emote + ": " + item.getName(), "", false);
- });
-
- event.reply(builder, chooseMessage -> {
- emotes.forEach(emote -> chooseMessage.addReaction(emote).queue());
-
- ReactionWaiter reactionWaiter = new ReactionWaiter(chooseMessage, event.getMember(), emotes);
- reactionWaiter.onEvent(reactionEvent -> {
- Item forRemoval;
- switch (reactionEvent.getEmote()) {
- case NumberEmojis.ONE:
- forRemoval = items.get(0);
- break;
- case NumberEmojis.TWO:
- forRemoval = items.get(1);
- break;
- case NumberEmojis.THREE:
- forRemoval = items.get(2);
- break;
- case NumberEmojis.FOUR:
- forRemoval = items.get(3);
- break;
- case NumberEmojis.FIVE:
- forRemoval = items.get(4);
- break;
- default:
- return;
- }
- shopService.removeItem(member.getIdLong(), forRemoval.getItemId());
- reactionWaiter.stopWaiting(false);
- chooseMessage.delete().queue();
- event.reply(embedCache.getEmbed("removeItemSuccess").injectValue("user", member.getAsMention()));
- });
- });
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/commands/SetPriceCommand.java b/src/main/java/de/kaktushose/levelbot/shop/commands/SetPriceCommand.java
deleted file mode 100644
index 79e6ec4..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/commands/SetPriceCommand.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package de.kaktushose.levelbot.shop.commands;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.Permission;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-import de.kaktushose.levelbot.database.services.LevelService;
-
-@CommandController("setprice")
-@Permission("moderator")
-public class SetPriceCommand {
-
- @Inject
- private LevelService levelService;
- @Inject
- private EmbedCache embedCache;
-
- @Command(
- name = "Preis ändern",
- usage = "{prefix}setprice ",
- desc = "Setzt den Preis eines Items auf den angegebenen Wert",
- category = "Moderation"
- )
- public void onSetPrice(CommandEvent event, int itemId, int price) {
- if (levelService.setItemPrice(itemId, price)) {
- event.reply(embedCache.getEmbed("itemPriceChanged"));
- } else {
- event.reply(embedCache.getEmbed("itemNotFound").injectValue("id", itemId));
- }
- }
-}
-
diff --git a/src/main/java/de/kaktushose/levelbot/shop/commands/ShopDeprecatedCommand.java b/src/main/java/de/kaktushose/levelbot/shop/commands/ShopDeprecatedCommand.java
deleted file mode 100644
index 6aaa884..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/commands/ShopDeprecatedCommand.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package de.kaktushose.levelbot.shop.commands;
-
-import com.github.kaktushose.jda.commands.annotations.Command;
-import com.github.kaktushose.jda.commands.annotations.CommandController;
-import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.dispatching.CommandEvent;
-import com.github.kaktushose.jda.commands.embeds.EmbedCache;
-
-@CommandController("kaufen")
-public class ShopDeprecatedCommand {
-
- @Inject
- private EmbedCache embedCache;
-
- @Command
- public void onBuy(CommandEvent event) {
- event.reply(embedCache.getEmbed("shopCommandDeprecated"));
- }
-
- @Command("dummy")
- public void onDummy(CommandEvent event) {
- onBuy(event);
- }
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/data/ShopService.java b/src/main/java/de/kaktushose/levelbot/shop/data/ShopService.java
deleted file mode 100644
index 05c3576..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/data/ShopService.java
+++ /dev/null
@@ -1,163 +0,0 @@
-package de.kaktushose.levelbot.shop.data;
-
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.model.BotUser;
-import de.kaktushose.levelbot.database.repositories.UserRepository;
-import de.kaktushose.levelbot.database.services.UserService;
-import de.kaktushose.levelbot.shop.data.items.*;
-import de.kaktushose.levelbot.shop.data.transactions.Transaction;
-import de.kaktushose.levelbot.shop.data.transactions.TransactionRepository;
-import de.kaktushose.levelbot.spring.ApplicationContextHolder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationContext;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-public class ShopService {
-
- private final static Logger log = LoggerFactory.getLogger(ShopService.class);
- private final UserRepository userRepository;
- private final TransactionRepository transactionRepository;
- private final ItemRepository itemRepository;
- private final FrozenItemRepository frozenItemRepository;
- private final UserService userService;
- private final Levelbot levelbot;
-
- public ShopService(Levelbot levelbot) {
- ApplicationContext context = ApplicationContextHolder.getContext();
- userRepository = context.getBean(UserRepository.class);
- transactionRepository = context.getBean(TransactionRepository.class);
- itemRepository = context.getBean(ItemRepository.class);
- frozenItemRepository = context.getBean(FrozenItemRepository.class);
- userService = levelbot.getUserService();
- this.levelbot = levelbot;
- }
-
- public boolean hasItem(long userId, int itemId) {
- return transactionRepository.existsByUserIdAndItemId(userId, itemId);
- }
-
- public boolean hasItemOfCategory(long userId, ItemCategory category) {
- return hasItemOfCategory(userId, category.getCategoryId());
- }
-
- public boolean hasItemOfCategory(long userId, int category) {
- return transactionRepository.existsByUserIdAndCategoryId(userId, category);
- }
-
- public List
- getItems(long userId) {
- return itemRepository.findItemsByUserId(userId);
- }
-
- public void buyItem(long userId, int itemId) {
- BotUser botUser = userService.getUserById(userId);
- Item item = itemRepository.findById(itemId).orElseThrow();
- transactionRepository.save(addItemToUser(botUser, item));
- botUser.setCoins(botUser.getCoins() - item.getPrice());
- userRepository.save(botUser);
- levelbot.addItemRole(botUser.getUserId(), item.getItemId());
- }
-
- public void addItem(long userId, ItemCategory category, ItemVariant variant) {
- addItem(userId, category.getItemId(variant));
- }
-
- public void addItem(long userId, int itemId) {
- Item item = itemRepository.findById(itemId).orElseThrow();
-
- if (itemId == 3) {
- if (hasItemOfCategory(userId, ItemCategory.PREMIUM)) {
- frozenItemRepository.save(FrozenItem.fromTransaction(userId, getTransaction(userId, itemId)));
- removeItem(userId, itemId);
- }
- }
-
- BotUser botUser = userService.getUserById(userId);
- Transaction transaction;
- if (hasItemOfCategory(userId, item.getCategoryId())) {
- // TODO add getItemByCategoryId method
- int id = getItems(userId).stream().filter(i -> i.getCategoryId() == item.getCategoryId())
- .findFirst()
- .orElseThrow()
- .getItemId();
- transaction = getTransaction(userId, id);
- transaction.setBuyTime(transaction.getBuyTime() + item.getDuration());
- } else {
- transaction = addItemToUser(botUser, item);
- levelbot.addItemRole(userId, item.getItemId());
- }
-
- transactionRepository.save(transaction);
- userRepository.save(botUser);
- }
-
- private Transaction addItemToUser(BotUser botUser, Item item) {
- Transaction transaction = new Transaction();
- transaction.setBuyTime(System.currentTimeMillis());
- transaction.setItem(item);
- transaction.setUserId(botUser.getUserId());
- botUser.getTransactions().add(transaction);
- return transaction;
- }
-
- public Transaction getTransaction(long userId, int itemId) {
- return transactionRepository.findByUserIdAndItemId(userId, itemId).stream().findFirst().orElseThrow();
- }
-
- public void removeItem(long userId, ItemCategory category, ItemVariant variant) {
- removeItem(userId, category.getItemId(variant));
- }
-
- public void removeItem(long userId, int itemId) {
- transactionRepository.deleteByUserIdAndItemId(userId, itemId);
- BotUser botUser = userService.getUserById(userId);
-
- if (itemId == 3) {
- if (frozenItemRepository.existsById(userId)) {
- FrozenItem frozenItem = frozenItemRepository.findById(userId).orElseThrow();
-
- Transaction transaction = new Transaction();
- transaction.setBuyTime(
- frozenItem.getBuyTime() + (System.currentTimeMillis() - frozenItem.getStartTime())
- );
- transaction.setItem(frozenItem.getItem());
- botUser.getTransactions().add(transaction);
-
- frozenItemRepository.delete(frozenItem);
- transactionRepository.save(transaction);
- userRepository.save(botUser);
- return;
- }
- }
-
- levelbot.removeItemRole(userId, itemId);
- }
-
- public void checkForExpiredItems() {
- for (Transaction transaction : transactionRepository.findExpiringTransactions()) {
- Item item = transaction.getItem();
- long remaining = item.getRemainingTimeAsLong(transaction.getBuyTime());
- long userId = transaction.getUserId();
- int itemId = item.getItemId();
-
- if (itemId == ItemCategory.PREMIUM.getItemId(ItemVariant.UNLIMITED)) {
- continue;
- }
- if (remaining <= 0) {
- removeItem(userId, itemId);
- levelbot.sendItemExpiredInformation(userId, itemId, transaction.getBuyTime());
- } else if (remaining < 86400000) {
- levelbot.getTaskScheduler().addSingleTask(() -> {
- try {
- removeItem(userId, itemId);
- levelbot.sendItemExpiredInformation(userId, itemId, transaction.getBuyTime());
- } catch (Throwable t) {
- log.error("An exception has occurred while removing an item!", t);
- }
- }, remaining, TimeUnit.MILLISECONDS);
- }
- }
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/data/items/FrozenItem.java b/src/main/java/de/kaktushose/levelbot/shop/data/items/FrozenItem.java
deleted file mode 100644
index 4ca0e78..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/data/items/FrozenItem.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package de.kaktushose.levelbot.shop.data.items;
-
-import de.kaktushose.levelbot.shop.data.transactions.Transaction;
-
-import javax.persistence.*;
-
-/**
- * This class covers the edge case where a user has normal premium but receives unlimited as well. Unlimited will become
- * the active item and the normal premium will be moved to this table until unlimited gets removed again.
- */
-@Entity
-@Table(name = "frozen_items")
-public class FrozenItem {
-
- @Id
- private long userId;
- private long startTime;
- private long buyTime;
- @OneToOne(fetch = FetchType.EAGER)
- @JoinColumn(name = "itemId", referencedColumnName = "itemId")
- private Item item;
-
- public FrozenItem() {
- }
-
- public FrozenItem(long userId, long startTime, long buyTime, Item item) {
- this.userId = userId;
- this.startTime = startTime;
- this.buyTime = buyTime;
- this.item = item;
- }
-
- public static FrozenItem fromTransaction(long userId, Transaction transaction) {
- return new FrozenItem(userId, System.currentTimeMillis(), transaction.getBuyTime(), transaction.getItem());
- }
-
- public long getUserId() {
- return userId;
- }
-
- public void setUserId(long userId) {
- this.userId = userId;
- }
-
- public long getStartTime() {
- return startTime;
- }
-
- public void setStartTime(long startTime) {
- this.startTime = startTime;
- }
-
- public long getBuyTime() {
- return buyTime;
- }
-
- public void setBuyTime(long buyTime) {
- this.buyTime = buyTime;
- }
-
- public Item getItem() {
- return item;
- }
-
- public void setItem(Item item) {
- this.item = item;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/data/items/FrozenItemRepository.java b/src/main/java/de/kaktushose/levelbot/shop/data/items/FrozenItemRepository.java
deleted file mode 100644
index 42afd16..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/data/items/FrozenItemRepository.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package de.kaktushose.levelbot.shop.data.items;
-
-import org.springframework.data.repository.CrudRepository;
-
-public interface FrozenItemRepository extends CrudRepository {
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/data/items/Item.java b/src/main/java/de/kaktushose/levelbot/shop/data/items/Item.java
deleted file mode 100644
index 9c1d5cb..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/data/items/Item.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package de.kaktushose.levelbot.shop.data.items;
-
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-import java.util.concurrent.TimeUnit;
-
-@Entity
-@Table(name = "items")
-public class Item {
-
- @Id
- private Integer itemId;
- private String name;
- private int price;
- private long duration;
- private int categoryId;
- private boolean visible;
- private long roleId;
-
- public Item() {
- }
-
- public Item(int itemId, String name, int price, long duration, int categoryId, boolean visible, long roleId) {
- this.itemId = itemId;
- this.name = name;
- this.price = price;
- this.duration = duration;
- this.categoryId = categoryId;
- this.visible = visible;
- this.roleId = roleId;
- }
-
- public Integer getItemId() {
- return itemId;
- }
-
- public void setItemId(Integer itemId) {
- this.itemId = itemId;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getPrice() {
- return price;
- }
-
- public void setPrice(int price) {
- this.price = price;
- }
-
- public long getDuration() {
- return duration;
- }
-
- public void setDuration(long duration) {
- this.duration = duration;
- }
-
- public int getCategoryId() {
- return categoryId;
- }
-
- public void setCategoryId(int categoryId) {
- this.categoryId = categoryId;
- }
-
- public boolean isVisible() {
- return visible;
- }
-
- public void setVisible(boolean visible) {
- this.visible = visible;
- }
-
- public long getRoleId() {
- return roleId;
- }
-
- public void setRoleId(long roleId) {
- this.roleId = roleId;
- }
-
- public String getRemainingTimeAsDate(long buyTime) {
- if (duration < 1) {
- return "unbegrenzt";
- }
- long millis = duration - (System.currentTimeMillis() - buyTime);
- long days = TimeUnit.MILLISECONDS.toDays(millis);
- long hours = TimeUnit.MILLISECONDS.toHours(millis) - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(millis));
- String daysPattern = days != 1 ? "%d Tage" : "ein Tag";
- String hoursPattern = hours != 1 ? "%d Stunden" : "eine Stunde";
- return String.format(daysPattern, days) + " und " + String.format(hoursPattern, hours);
- }
-
- public long getRemainingTimeAsLong(long buyTime) {
- return duration - (System.currentTimeMillis() - buyTime);
- }
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/data/items/ItemCategory.java b/src/main/java/de/kaktushose/levelbot/shop/data/items/ItemCategory.java
deleted file mode 100644
index 0a66ca3..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/data/items/ItemCategory.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package de.kaktushose.levelbot.shop.data.items;
-
-public enum ItemCategory {
-
- PREMIUM(0, 0),
- DJ_PERK(1, 4),
- NICKNAME_PERK(2, 7),
- COIN_BOOSTER(3, 10),
- XP_BOOSTER(4, 12);
-
- final int categoryId;
- final int itemIdBaseValue;
-
- ItemCategory(int categoryId, int itemIdBaseValue) {
- this.categoryId = categoryId;
- this.itemIdBaseValue = itemIdBaseValue;
- }
-
- public int getCategoryId() {
- return categoryId;
- }
-
- public int getItemId(ItemVariant variant) {
- return itemIdBaseValue + variant.getItemIdSummand();
- }
-
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/data/items/ItemRepository.java b/src/main/java/de/kaktushose/levelbot/shop/data/items/ItemRepository.java
deleted file mode 100644
index c521bff..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/data/items/ItemRepository.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package de.kaktushose.levelbot.shop.data.items;
-
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.CrudRepository;
-import org.springframework.data.repository.query.Param;
-
-import java.util.List;
-
-public interface ItemRepository extends CrudRepository
- {
-
- List
- findByCategoryId(int categoryId);
-
- @Query(value = "SELECT * FROM items where items.item_id IN (SELECT transactions.item_id FROM transactions WHERE user_id = :userId)", nativeQuery = true)
- List
- findItemsByUserId(@Param("userId") long userId);
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/data/items/ItemVariant.java b/src/main/java/de/kaktushose/levelbot/shop/data/items/ItemVariant.java
deleted file mode 100644
index d619a33..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/data/items/ItemVariant.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package de.kaktushose.levelbot.shop.data.items;
-
-public enum ItemVariant {
- LIGHT(0),
- BASIC(1),
- GOLD(2),
- UNLIMITED(3);
-
- private final int itemIdSummand;
-
- ItemVariant(int itemIdSummand) {
- this.itemIdSummand = itemIdSummand;
- }
-
- int getItemIdSummand() {
- return itemIdSummand;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/data/transactions/Transaction.java b/src/main/java/de/kaktushose/levelbot/shop/data/transactions/Transaction.java
deleted file mode 100644
index f3756d7..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/data/transactions/Transaction.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package de.kaktushose.levelbot.shop.data.transactions;
-
-import de.kaktushose.levelbot.shop.data.items.Item;
-
-import javax.persistence.*;
-
-@Entity
-@Table(name = "transactions")
-public class Transaction {
-
- @Id
- @GeneratedValue(strategy = GenerationType.AUTO)
- private Long transactionId;
- @OneToOne(fetch = FetchType.EAGER)
- @JoinColumn(name = "itemId", referencedColumnName = "itemId")
- private Item item;
- private long userId;
- private long buyTime;
-
- public Transaction() {
- }
-
- public Transaction(Long transactionId, Item item, long userId, long buyTime) {
- this.transactionId = transactionId;
- this.item = item;
- this.buyTime = buyTime;
- this.userId = userId;
- }
-
- public Long getTransactionId() {
- return transactionId;
- }
-
- public void setTransactionId(Long transactionId) {
- this.transactionId = transactionId;
- }
-
- public Item getItem() {
- return item;
- }
-
- public void setItem(Item item) {
- this.item = item;
- }
-
- public long getBuyTime() {
- return buyTime;
- }
-
- public void setBuyTime(long buyTime) {
- this.buyTime = buyTime;
- }
-
- public long getUserId() {
- return userId;
- }
-
- public void setUserId(long userId) {
- this.userId = userId;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/shop/data/transactions/TransactionRepository.java b/src/main/java/de/kaktushose/levelbot/shop/data/transactions/TransactionRepository.java
deleted file mode 100644
index 8db4ae6..0000000
--- a/src/main/java/de/kaktushose/levelbot/shop/data/transactions/TransactionRepository.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package de.kaktushose.levelbot.shop.data.transactions;
-
-import org.springframework.data.jpa.repository.Modifying;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.data.repository.CrudRepository;
-import org.springframework.data.repository.query.Param;
-
-import javax.transaction.Transactional;
-import java.util.List;
-
-public interface TransactionRepository extends CrudRepository {
-
- @Query(value = "SELECT new java.lang.Boolean(count(*) > 0) FROM Transaction WHERE user_id = :userId and item_id = :itemId")
- boolean existsByUserIdAndItemId(@Param("userId") long userId, @Param("itemId") int itemId);
-
- @Query(value = "SELECT * from transactions WHERE user_id = :userId and item_id = :itemId", nativeQuery = true)
- List findByUserIdAndItemId(@Param("userId") long userId, @Param("itemId") int itemId);
-
- @Modifying
- @Transactional
- @Query(value = "DELETE from transactions WHERE user_id = :userId and item_id = :itemId", nativeQuery = true)
- void deleteByUserIdAndItemId(@Param("userId") long userId, @Param("itemId") int itemId);
-
- @Query("SELECT new java.lang.Boolean(count(*) > 0) FROM Transaction t WHERE t.userId = :userId AND t.item.itemId in (SELECT i.itemId from Item i where i.categoryId = :categoryId)")
- boolean existsByUserIdAndCategoryId(@Param("userId") long userId, @Param("categoryId") int categoryId);
-
- @Query(value = "SELECT * FROM transactions INNER JOIN items ON items.item_id=transactions.item_id WHERE duration - ((UNIX_TIMESTAMP(NOW()) * 1000) - buy_time) < 86400000 AND transactions.item_id <> 3", nativeQuery = true)
- List findExpiringTransactions();
-}
diff --git a/src/main/java/de/kaktushose/levelbot/spring/ApplicationContextHolder.java b/src/main/java/de/kaktushose/levelbot/spring/ApplicationContextHolder.java
deleted file mode 100644
index 541d238..0000000
--- a/src/main/java/de/kaktushose/levelbot/spring/ApplicationContextHolder.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package de.kaktushose.levelbot.spring;
-
-import org.jetbrains.annotations.NotNull;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.stereotype.Component;
-
-@Component
-public class ApplicationContextHolder implements ApplicationContextAware {
-
- private static ApplicationContext context;
-
- public static ApplicationContext getContext() {
- return context;
- }
-
- @Override
- public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
- context = applicationContext;
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/util/NumberEmojis.java b/src/main/java/de/kaktushose/levelbot/util/NumberEmojis.java
deleted file mode 100644
index f6f2c81..0000000
--- a/src/main/java/de/kaktushose/levelbot/util/NumberEmojis.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package de.kaktushose.levelbot.util;
-
-/*
-For some reason, number emojis don't behave like other normal emojis, so this class provides a little workaround to prevent
-me from feeling that urgent need to delete this project and set my PC on fire every time I need to work with numbers
- */
-public class NumberEmojis {
-
- public static final String ZERO = "0️⃣";
- public static final String ONE = "1️⃣";
- public static final String TWO = "2️⃣";
- public static final String THREE = "3️⃣";
- public static final String FOUR = "4️⃣";
- public static final String FIVE = "5️⃣";
- public static final String SIX = "6️⃣";
- public static final String SEVEN = "7️⃣";
- public static final String EIGHT = "8️⃣";
- public static final String NINE = "9️⃣";
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/util/Pageable.java b/src/main/java/de/kaktushose/levelbot/util/Pageable.java
deleted file mode 100644
index 2e774ae..0000000
--- a/src/main/java/de/kaktushose/levelbot/util/Pageable.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package de.kaktushose.levelbot.util;
-
-public interface Pageable {
-
- Long getUserId();
-
- long getCount(Pagination.CurrencyType currencyType);
-
-}
diff --git a/src/main/java/de/kaktushose/levelbot/util/Pagination.java b/src/main/java/de/kaktushose/levelbot/util/Pagination.java
deleted file mode 100644
index 8c0b54a..0000000
--- a/src/main/java/de/kaktushose/levelbot/util/Pagination.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package de.kaktushose.levelbot.util;
-
-import net.dv8tion.jda.api.JDA;
-import net.dv8tion.jda.api.entities.User;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class Pagination {
-
- private final CurrencyType currencyType;
- private final JDA jda;
- private final List extends Pageable> leaderboard;
- private final int pageSize; // elements per page
- private int index; // current page index
-
- public Pagination(int pageSize, List extends Pageable> leaderboard, JDA jda, CurrencyType currencyType) {
- this.pageSize = pageSize;
- this.leaderboard = leaderboard;
- this.jda = jda;
- this.currencyType = currencyType;
- this.index = 0;
- }
-
- public void nextPage() {
- index++;
- if (index + 1 > pages()) {
- index--;
- }
- }
-
- public void previousPage() {
- index--;
- if (index < 0) {
- index = 0;
- }
- }
-
- public List getPage() {
- int fromIndex = index == 0 ? 0 : index * pageSize;
- int toIndex = index == 0 ? pageSize : index * pageSize + pageSize;
-
- // end of list reached, set toIndex to list size
- if (toIndex > leaderboard.size()) {
- toIndex = leaderboard.size();
- }
-
- return leaderboard.subList(fromIndex, toIndex).stream().map(this::format).collect(Collectors.toList());
- }
-
- public int size() {
- return leaderboard.size();
- }
-
- public int index() {
- return index;
- }
-
- public int pages() {
- return (int) Math.ceil((float) leaderboard.size() / (float) pageSize);
- }
-
- private String format(Pageable pageable) {
- User user = jda.getUserById(pageable.getUserId());
- switch (currencyType) {
- case XP:
- return String.format("%s#%s (%d XP)", user.getName(), user.getDiscriminator(), pageable.getCount(CurrencyType.XP));
- case COINS:
- return String.format("%s#%s (%d Münzen)", user.getName(), user.getDiscriminator(), pageable.getCount(CurrencyType.COINS));
- case DIAMONDS:
- return String.format("%s#%s (%d Diamanten)", user.getName(), user.getDiscriminator(), pageable.getCount(CurrencyType.DIAMONDS));
- case CONTEST:
- return String.format("%s#%s (%d Votes)", user.getName(), user.getDiscriminator(), pageable.getCount(CurrencyType.CONTEST));
- default:
- throw new IllegalArgumentException("Unsupported currency type!");
- }
- }
-
- public enum CurrencyType {
- XP,
- COINS,
- DIAMONDS,
- CONTEST
- }
-}
diff --git a/src/main/java/de/kaktushose/levelbot/util/Statistics.java b/src/main/java/de/kaktushose/levelbot/util/Statistics.java
deleted file mode 100644
index 57e0071..0000000
--- a/src/main/java/de/kaktushose/levelbot/util/Statistics.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package de.kaktushose.levelbot.util;
-
-import com.google.api.client.http.HttpRequestInitializer;
-import com.google.api.client.http.javanet.NetHttpTransport;
-import com.google.api.client.json.jackson2.JacksonFactory;
-import com.google.api.services.youtube.YouTube;
-import com.google.api.services.youtube.model.ChannelListResponse;
-import com.google.api.services.youtube.model.ChannelStatistics;
-import de.kaktushose.levelbot.bot.Levelbot;
-import net.dv8tion.jda.api.OnlineStatus;
-import net.dv8tion.jda.api.entities.Guild;
-import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.utils.concurrent.Task;
-import net.dv8tion.jda.internal.utils.concurrent.task.GatewayTask;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.text.NumberFormat;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
-
-public class Statistics {
-
- private static final Logger log = LoggerFactory.getLogger(Statistics.class);
- private final Levelbot levelbot;
- private final String youtubeApiKey;
- private int totalMemberCount;
- private int onlineMemberCount;
- private int lsMemberCount;
- private int etsMemberCount;
- private int notrufMemberCount;
- private int omsiMemberCount;
- private int wrsMemberCount;
- private int gtaMemberCount;
- private int boosterMemberCount;
- private int boosterCount;
- private int premiumMemberCount;
- private String ytFollowerCount;
- private String ytVideoCount;
- private String ytViewCount;
- private String boosterMemberList;
- private String premiumMemberList;
-
- public Statistics(Levelbot levelbot, long guildId) {
- this.levelbot = levelbot;
- youtubeApiKey = levelbot.getSettingsService().getYoutubeApiKey(guildId);
- }
-
- public Task queryStatistics() {
- Guild guild = levelbot.getGuild();
- CompletableFuture future = new CompletableFuture<>();
- Task
> reference = guild.loadMembers()
- .onSuccess(members -> {
- // general member count
- totalMemberCount = members.size();
- onlineMemberCount = (int) members.stream().filter(member -> !member.getOnlineStatus().equals(OnlineStatus.OFFLINE)).count();
- // game count
- lsMemberCount = getGameCount(members, "Farming Simulator");
- etsMemberCount = getGameCount(members, "Euro Truck Simulator");
- notrufMemberCount = getGameCount(members, "Notruf 112");
- omsiMemberCount = getGameCount(members, "OMSI");
- wrsMemberCount = getGameCount(members, "Winter Resort Simulator");
- gtaMemberCount = getGameCount(members, "Grand Theft Auto");
- // booster
- List boosterList = members.stream().filter(member -> member.getTimeBoosted() != null).collect(Collectors.toList());
- boosterMemberCount = boosterList.size();
- StringBuilder boosters = new StringBuilder();
- boosterList.forEach(member -> boosters.append(member.getAsMention()).append(", "));
- boosterMemberList = boosters.length() > 1 ? boosters.substring(0, boosters.length() - 2) : "";
- boosterCount = guild.getBoostCount();
- // premium
- List premiumMembers = members.stream()
- .filter(member -> member.getRoles().contains(guild.getRolesByName("premium", true).get(0)))
- .collect(Collectors.toList());
- premiumMemberCount = premiumMembers.size();
- StringBuilder premium = new StringBuilder();
- premiumMembers.forEach(member -> premium.append(member.getAsMention()).append(", "));
- premiumMemberList = premium.length() > 1 ? premium.substring(0, premium.length() - 2) : "";
- // yt
- try {
- NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.GERMANY);
- ChannelStatistics channelStatistics = getYoutubeStatistics();
- ytFollowerCount = numberFormat.format(channelStatistics.getSubscriberCount().intValue());
- ytVideoCount = numberFormat.format(channelStatistics.getVideoCount().intValue());
- ytViewCount = numberFormat.format(channelStatistics.getViewCount().intValue());
- } catch (IOException e) {
- log.error("Unable to query youtube follower count!", e);
- }
- future.complete(this);
- })
- .onError(future::completeExceptionally);
- return new GatewayTask<>(future, reference::cancel);
- }
-
- private int getGameCount(List members, String name) {
- int count = 0;
- for (Member member : members) {
- if (member.getActivities().isEmpty()) {
- continue;
- }
- if (member.getActivities().get(0).getName().contains(name)) {
- count++;
- }
- }
- return count;
- }
-
- private ChannelStatistics getYoutubeStatistics() throws IOException {
- HttpRequestInitializer httpRequestInitializer = request -> {
- };
- YouTube youTube = new YouTube.Builder(new NetHttpTransport(), new JacksonFactory(), httpRequestInitializer)
- .setApplicationName("Levelbot")
- .build();
- YouTube.Channels.List search = youTube.channels().list("statistics");
- search.setForUsername("nordrheintvplay");
- search.setKey(youtubeApiKey);
- ChannelListResponse response = search.execute();
- return response.getItems().get(0).getStatistics();
- }
-}
diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF
index 5c5daac..3702dff 100644
--- a/src/main/resources/META-INF/MANIFEST.MF
+++ b/src/main/resources/META-INF/MANIFEST.MF
@@ -1,2 +1,2 @@
Manifest-Version: 1.0
-Main-Class: de.kaktushose.levelbot.Bootstrapper
+Main-Class: com.github.kaktushose.nplaybot.Bootstrapper
diff --git a/src/test/java/BoosterServiceTest.java b/src/test/java/BoosterServiceTest.java
deleted file mode 100644
index 22c6d4f..0000000
--- a/src/test/java/BoosterServiceTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-import de.kaktushose.levelbot.Bootstrapper;
-import de.kaktushose.levelbot.database.model.BotUser;
-import de.kaktushose.levelbot.database.services.BoosterService;
-import de.kaktushose.levelbot.database.services.UserService;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInstance;
-import org.springframework.boot.SpringBootConfiguration;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.jdbc.Sql;
-
-import java.util.NoSuchElementException;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-@SpringBootConfiguration
-@SpringBootTest(classes = Bootstrapper.class)
-@TestInstance(TestInstance.Lifecycle.PER_CLASS)
-@Sql(scripts = "classpath:truncate_all.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
-public class BoosterServiceTest {
-
- private BoosterService boosterService;
- private UserService userService;
-
- @BeforeAll
- public void setup() {
- LevelbotMock levelbot = new LevelbotMock();
- boosterService = levelbot.getBoosterService();
- userService = levelbot.getUserService();
- }
-
- @Test
- public void getAllNitroBoosters_WithoutUsers_ShouldReturnEmptyList() {
- assertTrue( boosterService.getAllNitroBoosters().isEmpty());
- }
-
- @Test
- public void getAllNitroBoosters_WithUsers_ShouldReturnNotEmptyList() {
- boosterService.createNewNitroBooster(0);
- boosterService.createNewNitroBooster(1);
- boosterService.createNewNitroBooster(2);
- assertEquals(3, boosterService.getAllNitroBoosters().size());
- }
-
- @Test
- public void createNewNitroBooster_ShouldBeActiveBooster() {
- boosterService.createNewNitroBooster(0);
- assertTrue(boosterService.isNitroBooster(0));
- }
-
- @Test
- public void isNitroBooster_WithoutUsers_ShouldReturnFalse() {
- assertFalse(boosterService.isNitroBooster(0));
- }
-
- @Test
- public void isNitroBooster_WithUsers_ShouldReturnTrue() {
- boosterService.createNewNitroBooster(0);
- assertTrue(boosterService.isNitroBooster(0));
- }
-
- @Test
- public void isActiveNitroBooster_WithoutUsers_ShouldReturnFalse() {
- assertFalse(boosterService.isActiveNitroBooster(0));
- }
-
- @Test
- public void isActiveNitroBooster_WithUsers_ShouldReturnTrue() {
- boosterService.createNewNitroBooster(0);
- assertTrue(boosterService.isActiveNitroBooster(0));
- }
-
- @Test
- public void changeNitroBoosterStatus_WithTrue_ShouldBeActiveBooster() {
- boosterService.createNewNitroBooster(0);
- boosterService.changeNitroBoosterStatus(0, true);
- assertTrue(boosterService.isNitroBooster(0));
- }
-
- @Test
- public void addMonthlyReward_ShouldAddCurrencies() {
- userService.createUser(0);
- String rewardText = boosterService.addMonthlyReward(0);
- BotUser botUser = userService.getUserById(0);
- assertEquals(50, botUser.getXp());
- assertEquals(50, botUser.getCoins());
- assertEquals(5, botUser.getDiamonds());
- assertFalse(rewardText.isEmpty());
- }
-
- @Test
- public void addMonthlyReward_WithoutUsers_ShouldThrow() {
- assertThrows(NoSuchElementException.class, () -> boosterService.addMonthlyReward(0));
- }
-
- @Test
- public void addOneTime_ShouldAddCurrencies() {
- userService.createUser(0);
- String rewardText = boosterService.addOneTimeReward(0);
- BotUser botUser = userService.getUserById(0);
- assertEquals(250, botUser.getXp());
- assertEquals(250, botUser.getCoins());
- assertEquals(25, botUser.getDiamonds());
- assertFalse(rewardText.isEmpty());
- }
-
- @Test
- public void addOneTimeReward_WithoutUsers_ShouldThrow() {
- assertThrows(NoSuchElementException.class, () -> boosterService.addOneTimeReward(0));
- userService.createUser(0);
- userService.createUser(1);
- }
-}
diff --git a/src/test/java/LevelbotMock.java b/src/test/java/LevelbotMock.java
deleted file mode 100644
index bfa9f19..0000000
--- a/src/test/java/LevelbotMock.java
+++ /dev/null
@@ -1,32 +0,0 @@
-import de.kaktushose.levelbot.bot.Levelbot;
-import de.kaktushose.levelbot.database.services.BoosterService;
-import de.kaktushose.levelbot.database.services.SettingsService;
-import de.kaktushose.levelbot.database.services.UserService;
-
-public class LevelbotMock extends Levelbot {
-
- private final UserService userService;
- private final SettingsService settingsService;
- private final BoosterService boosterService;
-
- public LevelbotMock() {
- this.userService = new UserService();
- this.settingsService = new SettingsServiceMock();
- this.boosterService = new BoosterService(this);
- }
-
- @Override
- public UserService getUserService() {
- return userService;
- }
-
- @Override
- public SettingsService getSettingsService() {
- return settingsService;
- }
-
- @Override
- public BoosterService getBoosterService() {
- return boosterService;
- }
-}
diff --git a/src/test/java/SettingsServiceMock.java b/src/test/java/SettingsServiceMock.java
deleted file mode 100644
index 97cd3b2..0000000
--- a/src/test/java/SettingsServiceMock.java
+++ /dev/null
@@ -1,16 +0,0 @@
-import de.kaktushose.levelbot.database.model.Reward;
-import de.kaktushose.levelbot.database.services.SettingsService;
-
-public class SettingsServiceMock extends SettingsService {
-
- @Override
- public Reward getMonthlyNitroBoosterReward() {
- return new Reward(0, 50, 50, 5, null, "Reward");
- }
-
- @Override
- public Reward getOneTimeNitroBoosterReward() {
- return new Reward(1, 250, 250, 25, null, "Reward");
- }
-
-}
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
deleted file mode 100644
index 8cac730..0000000
--- a/src/test/resources/application.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-spring.datasource.url = jdbc:h2:mem:levelbot;
-spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
\ No newline at end of file
diff --git a/src/test/resources/truncate_all.sql b/src/test/resources/truncate_all.sql
deleted file mode 100644
index e50f396..0000000
--- a/src/test/resources/truncate_all.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-TRUNCATE TABLE nitro_boosters;
-DELETE FROM users;
\ No newline at end of file
diff --git a/welcomeEmbeds.json b/welcomeEmbeds.json
deleted file mode 100644
index 074134c..0000000
--- a/welcomeEmbeds.json
+++ /dev/null
@@ -1,131 +0,0 @@
-{
- "logo": {
- "title": "Offizieller NPLAY Discord",
- "description": "https://discord.gg/nplay",
- "thumbnail": {
- "url": "https://cdn.discordapp.com/attachments/850466263216947252/970283398063079464/nplay_logo_standard.jpg"
- },
- "image": {
- "url": "https://cdn.discordapp.com/attachments/850466263216947252/970283152163627008/Discord-LogoWordmark-White.png"
- },
- "color": "#aeff00"
- },
- "welcome": {
- "title": "Der Simulatoren Discord",
- "description":"Mit unserem NPLAY Discord-Server wollen wir Dir neue Möglichkeiten bieten: Diskutiere über die Welt der Simulatoren, tausche Dich über die neuesten Videos auf dem Kanal aus, nimm an exklusiven Gewinnspielen teil und finde andere Gamer zum gemeinsamen Zocken!\n\nUnd das alles auf einer modernen Plattform in angenehmer Atmosphäre.\n\nDie folgenden Informationen sollen Dir dabei helfen, dich auf dem Server schnell und unkompliziert zurechtzufinden.\n\nSollten dennoch Fragen offenbleiben, steht Dir unser Serverteam jederzeit zur Verfügung.\n\nWir wünschen Dir viel Spaß beim Chatten und Unterhalten!\nDein NPLAY Team",
- "author": {
- "name": "NPLAY",
- "icon_url": "https://media.discordapp.net/attachments/510209791214223380/659861897360703488/regular_picture.png"
- },
- "image":{
- "url":"https://cdn.discordapp.com/attachments/386959481558401025/960906185215733781/NPLAY_Entwurf.jpg"
- },
- "color": "#aeff00"
- },
- "statistics": {
- "title": "Fehler!",
- "description": "Da ist etwas schiefgelaufen. Bitte kontaktiere <@393843637437464588>!",
- "color": "#aa0c14"
- },
- "team": {
- "title": "Serverteam",
- "description": "Wir sind jederzeit für Dich da!\n\n<@278591435417059328> | Inhaber\n<@307973135746072578> | Serverleitung\n\n<@393843637437464588> | Moderation, Entwickler des Level-Systems\n<@315877643616649220> | Moderation\n<@522867524484726785> | Moderation\n<@142670727236026368> | Moderation\n<@427782609058398229> | Moderation\n\n*Bei Fragen oder anderen Anliegen freuen wir uns auf Deine Nachricht\nim Support oder via PN.*",
- "color": "#aeff00"
- },
- "categories": {
- "title": "Serverkategorien",
- "description":"Der Server ist in 4 übersichtliche Kategorien aufgeteilt:\n\n**- Informationen:**\nHier findest du alle wichtigen Kanäle zu den organisatorischen Aspekten des Servers sowie den Support.\n\n**- Projekte:**\nTausche Dich hier mit anderen Zuschauern über die Entwicklung des NPLAY YouTube-Kanals und dessen aktuelle Projekte aus.\n\n**- Simulatoren:**\nDiskutiere in den Spiele-Kanälen über Updates, teile deine Bilder und schönste Spielerlebnisse, oder erhalte Support. In <#606645000687583236> finden alle Spiele Platz, für die es keinen eigenen Kanal gibt!\n\n**- Community:**\nDer Bereich des Servers, in welchem alles abseits der Simulatoren diskutiert werden kann: Im <#575918262689333259> können interessante News gepostet und im <#386277336406032385> kann ausgelassen geplaudert werden. Die besten Beiträge des Servers sind jederzeit im <#690664642623701012> zu finden!\n\n*Zudem bieten wir einen Unbegrenzten Talk sowie einen 2 User Talk an.\nBei Bedarf können jederzeit weitere Kanäle eröffnet werden.*",
- "color": "#aeff00"
- },
- "rules": {
- "title": "Serverregeln",
- "description":"*Wir haben ein paar Regeln aufgestellt, um auf dem Server eine angenehme Diskussionskultur zu wahren. Mit dem Serverbeitritt akzeptierst Du die Einhaltung dieser Regeln.*",
- "fields": [
- {
- "name":"1. ALLGEMEINES",
- "value":"a) Sei höflich zu anderen Nutzern auf dem Server – nutze ihn so, dass sich jeder in angenehmer Atmosphäre unterhalten kann! \nb) Den Anweisungen des Serverteams ist immer Folge zu leisten.\nc) Das mehrmalige Verlassen und Wiederbetreten des Servers ist nicht erlaubt.\nd) Private Daten wie Telefonnummern, Adressen, Passwörter usw. dürfen nicht öffentlich ausgetauscht werden.",
- "inline":false
- },
- {
- "name":"2. CHATREGELN",
- "value":"a) Jegliche Formen von Beleidigung, Missachtung, Diskriminierung, Hetze, Rassismus etc. gegenüber anderen Usern und Dritten sind in den Text- und Sprachkanälen strengstens untersagt.\nb) Werbung für eigene oder fremde Inhalte ist auf dem Server untersagt. Auch Werbung per Privatnachricht an Mitglieder des Servers ist verboten (Ausnahme: Inhalte von NPLAY). Eine Genehmigung kann in Ausnahmefällen bei der Serverleitung angefragt werden. Werbeverbote gelten insbesondere für fragwürdige Shops, wie MMOGA, G2A, Kinguin usw.\nc) In den Chats sind nur Inhalte erwünscht, die der Kanalbeschreibung entsprechen. Trolling, Spamming sowie die ausnahmslose Verwendung von Caps oder Emojis sind verboten. Das gilt auch für Privatnachrichten.\nd) Beiträge sind in der Regel auf Deutsch zu verfassen. Kurze Diskussionsstränge in anderen Sprachen sind zulässig.\ne) Für die Sprachkanäle gilt zudem: Keine Aufnahme von Gesprächen, keine Stimmverzerrer, Soundboards nur mit Einverständnis der anderen User. Kein Channel-Hopping.",
- "inline":false
- },
- {
- "name":"3. IDENTITÄT",
- "value":"a) Nur ein Account je Person auf dem Server erlaubt. Doppel-Accounts werden gesperrt! \nb) Der Nickname darf nicht zur Verwechslung mit anderen Persönlichkeiten führen und keine falsche Identität vortäuschen. Er darf keine Kürzel (z.b:[xyz]) enthalten, nicht nur aus einzelnen Zeichen bestehen (z.B. „!“ ) und muss aus lateinischen Schriftzeichen zusammengesetzt sein (keine Schnörkelschrift o.ä.). User mit anstößigen Namen werden gesperrt!\nc) Nicknameänderungen sind nach Möglichkeit zu vermeiden. Sie erfolgen im Falle eines Regelverstoßes durch das Serverteam. User, die ihren Nicknamen nicht selbstständig ändern können, fragen für eine Änderung das Serverteam. \n\n*Das Kopieren unserer Fassung der Serverregeln ist untersagt. Bei entsprechenden Zwischenfällen behalten wir uns einen Ausschluss vom Server vor.*",
- "inline":false
- }
- ],
- "color": "#aeff00"
- },
- "rule violations": {
- "title": "Regelverstöße",
- "description":":bangbang: Im Falle eines Verstoßes müssen wir Maßnahmen ergreifen. Diese hängen von vielen individuellen Umständen ab: Wie schwer wiegt der Regelbruch? Ist der User bereits auffällig geworden? Und vor allem: Was muss getan werden, um auf dem Server eine angenehme Diskussionskultur zu bewahren? \n\nHäufig gehen wir dabei wie folgt vor:\n\n__1+ 2. Verstoß:__ **Warnung** über den Carl-Bot mit Hinweis auf das Fehlverhalten, ggf. klärendes Gespräch\n__Ab 3. Verstoß:__ **Mute für bis zu 30 Tage** über den Carl-Bot mit Angabe des Grundes\n__Spätestens ab 5. Verstoß:__ **Temporärer oder dauerhafter Bann** über den Carl-Bot mit Angabe des Grundes\n\nDiese Reihenfolge ist unverbindlich. So erfolgt beispielsweise bei einer schweren Beleidigung eines anderen Servermitglieds selbstverständlich direkt ein dauerhafter Bann, während das fünfmalige Verwenden von Caps höchstens zu einem Mute führt.\n\nBei Fragen dazu wende Dich gerne an das Moderationsteam.",
- "color": "#aeff00"
- },
- "links": {
- "title": "Nützliche Links",
- "fields": [
- {
- "name": "Youtube",
- "value": "https://bit.ly/2QkZHA6",
- "inline": true
- },
- {
- "name": "Facebook-Seite:",
- "value": "https://bit.ly/39i2jqS",
- "inline": true
- },
- {
- "name": "Facebook-Gruppe:",
- "value": "https://bit.ly/37bEzD1",
- "inline": true
- },
- {
- "name": "Instagram:",
- "value": "https://bit.ly/2EVMvwf",
- "inline": true
- },
- {
- "name": "Twitter:",
- "value": "https://bit.ly/35YgkYQ",
- "inline": true
- },
- {
- "name": "Twitch:",
- "value": "https://bit.ly/2tOJOtY",
- "inline": true
- },
- {
- "name": "Website:",
- "value": "https://nplay.de/",
- "inline": true
- },
- {
- "name": "Nitrado:",
- "value": "https://bit.ly/LSServerNitrado",
- "inline": true
- },
- {
- "name": "Discord:",
- "value": "https://discord.gg/nplay",
- "inline": true
- }
- ],
- "color": "#aeff00"
- },
- "levelSystem": {
- "title": "Level-System",
- "description": "Unser selbst entwickeltes, abwechslungsreiches Level-System belohnt Dich mit tollen Geschenken, wie gratis Keys für aktuelle Simulatoren!\n\nDu hast NITRO? Booste unseren Server und erhalte ein tolles Supportpaket, unter anderem mit einer dauerhaften PREMIUM-Rolle!\n\nSchau dich im Kanal <#851388807239827466> um und erfahre, wie der Bot funktioniert!\nSteuere den Bot mit einfachen Befehlen in <#665625766444138537>.\n\nSchau auf unserem Entwickler-Discord vorbei, um auch über die vielen neuen Erweiterungen in der Zukunft informiert zu bleiben!\nhttps://discord.gg/JYWezvQ",
- "image": {
- "url": "https://media.discordapp.net/attachments/487343298910879767/668939091772964904/BannerHQ.png"
- },
- "color": "#aeff00"
- },
- "support": {
- "title": "Support",
- "description":"- In<#386279631189311500> helfen wir Dir bei Problemen und Fragen rund um den Discord-Server. Außerdem freuen wir uns jederzeit über Deine Wünsche - wir behalten die Zukunft im Auge und wollen das User-Erlebnis weiter verbessern.\n\n- Alle Fragen rund um Gaming und den Kanal NPLAY bitte in den entsprechenden Spiele-Kanälen in \"Simulatoren\" bzw. in <#459805064840740864> stellen und dort mit anderen Usern austauschen!",
- "color": "#aeff00"
- }
-}
From 1a0310c7b00a673fb224062316ca8ad7728454fe Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 20:09:51 +0100
Subject: [PATCH 02/66] dockerize bot
---
.env.example | 7 +++++++
.gitignore | 2 ++
Dockerfile | 13 +++++++++++++
docker-compose.yml | 41 +++++++++++++++++++++++++++++++++++++++++
pom.xml | 1 +
5 files changed, 64 insertions(+)
create mode 100644 .env.example
create mode 100644 Dockerfile
create mode 100644 docker-compose.yml
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..d446086
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,7 @@
+MYSQL_ROOT_PASSWORD=password
+MYSQL_DATABASE=nplaybot
+MYSQL_USER=bot
+MYSQL_PASSWORD=password
+GF_SECURITY_ADMIN_PASSWORD=password
+BOT_TOKEN=token
+BOT_PRODUCTION=true
diff --git a/.gitignore b/.gitignore
index 8e84f37..017595c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,5 @@ buildNumber.properties
.mvn/wrapper/maven-wrapper.jar
### Project ###
+.env
+/data
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..2eb96a0
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,13 @@
+FROM maven:3.9.5-amazoncorretto-21-debian AS builder
+
+WORKDIR /bot
+
+COPY . .
+
+RUN mvn clean package -DskipTests
+
+FROM openjdk:21
+
+COPY --from=builder /bot/target/NPLAY-Bot.jar ./NPLAY-Bot.jar
+
+CMD ["java", "-jar", "NPLAY-Bot.jar"]
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..de23645
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,41 @@
+version: "3"
+
+services:
+ mariadb:
+ image: mariadb
+ restart: always
+ environment:
+ MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
+ MYSQL_DATABASE: ${MYSQL_DATABASE}
+ MYSQL_USER: ${MYSQL_USER}
+ MYSQL_PASSWORD: ${MYSQL_PASSWORD}
+ volumes:
+ - ./data/db:/var/lib/mysql
+ ports:
+ - "3306:3306"
+
+ grafana:
+ image: grafana/grafana
+ restart: always
+ environment:
+ GF_SECURITY_ADMIN_PASSWORD: ${GF_SECURITY_ADMIN_PASSWORD}
+ ports:
+ - "3000:3000"
+ depends_on:
+ - mariadb
+
+ bot:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ image: nplay-bot
+ restart: on-failure
+ environment:
+ BOT_TOKEN: ${BOT_TOKEN}
+ BOT_PRODUCTION: ${BOT_PRODUCTION}
+ DB_USER: ${MYSQL_USER}
+ DB_PASSWORD: ${MYSQL_PASSWORD}
+ ports:
+ - "8080:8080"
+ depends_on:
+ - mariadb
diff --git a/pom.xml b/pom.xml
index 5912a45..e295810 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,6 +15,7 @@
+ NPLAY-Bot
org.apache.maven.plugins
From 08a103f13a96b0bcb537d28f4a817b069b04715f Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 20:26:26 +0100
Subject: [PATCH 03/66] update workflows
---
.github/dependabot.yml | 17 -----------------
.github/workflows/deploy.yml | 33 +++++++++++++++++++++++----------
.github/workflows/maven.yml | 8 ++++----
3 files changed, 27 insertions(+), 31 deletions(-)
delete mode 100644 .github/dependabot.yml
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index 00c8e3b..0000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-# To get started with Dependabot version updates, you'll need to specify which
-# package ecosystems to update and where the package manifests are located.
-# Please see the documentation for all configuration options:
-# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
-
-version: 2
-updates:
- - package-ecosystem: "maven" # See documentation for possible values
- directory: "/" # Location of package manifests
- target-branch: "dev"
- schedule:
- interval: "weekly"
- ignore:
- - dependency-name: "jda*"
- update-types: ["version-update:semver-major"]
- - dependency-name: "*"
- update-types: ["version-update:semver-patch"]
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index a40ec11..ad0fe2b 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -2,20 +2,33 @@ name: Deploy
on:
push:
- branches: [ master ]
+ branches: [ rewrite ]
workflow_dispatch:
jobs:
deploy:
-
runs-on: ubuntu-latest
-
steps:
- - name: Execute build script via ssh
- uses: appleboy/ssh-action@master
+ - name: Build Image
+ id: build-image
+ uses: redhat-actions/buildah-build@v2
+ with:
+ image: nplaybot
+ tags: latest ${{ github.sha }}
+ containerfiles: |
+ ./Dockerfile
+ oci: true
+
+ - name: Push To ghcr.io
+ id: push-to-ghcr
+ uses: redhat-actions/push-to-registry@v2
with:
- host: ${{ secrets.SSH_HOST }}
- username: ${{ secrets.SSH_USERNAME }}
- key: ${{ secrets.SSH_KEY }}
- port: ${{ secrets.SSH_PORT }}
- script: nohup bash /home/levelbot/scripts/workflow.sh > /home/levelbot/scripts/nohup.log 2>&1 & tail -f /home/levelbot/scripts/nohup.log &
+ image: ${{ steps.build-image.outputs.image }}
+ tags: ${{ steps.build-image.outputs.tags }}
+ registry: ghcr.io/kaktushose/levelbot
+ username: Kaktushose
+ password: ${{ github.token }}
+ extra-args: |
+ --disable-content-trust
+ - name: Print image url
+ run: echo "Image pushed to ${{ steps.push-to-ghcr.outputs.registry-paths }}"
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index c1218cf..8b8a2d2 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -2,9 +2,9 @@ name: Java CI
on:
push:
- branches: [ master, dev ]
+ branches: [ main, development, rewrite ]
pull_request:
- branches: [ master, dev ]
+ branches: [ main, development, rewrite ]
jobs:
build:
@@ -13,9 +13,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- - name: Set up JDK 11
+ - name: Set up JDK 21
uses: actions/setup-java@v1
with:
- java-version: 11
+ java-version: 21
- name: Build with Maven
run: mvn -B package --file pom.xml
From 495a68e321c4a0c399c9f27047daf90c6e0811c0 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 20:36:11 +0100
Subject: [PATCH 04/66] fix deploy workflow
---
.github/workflows/deploy.yml | 1 +
README.md | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index ad0fe2b..f2ca6eb 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -9,6 +9,7 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
+ - uses: actions/checkout@v2
- name: Build Image
id: build-image
uses: redhat-actions/buildah-build@v2
diff --git a/README.md b/README.md
index a09f7d3..6aae679 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-[![Java CI](https://github.com/Kaktushose/Levelbot/actions/workflows/maven.yml/badge.svg)](https://github.com/Kaktushose/Levelbot/actions/workflows/maven.yml)
-[![Deploy](https://github.com/Kaktushose/Levelbot/actions/workflows/deploy.yml/badge.svg)](https://github.com/Kaktushose/Levelbot/actions/workflows/deploy.yml)
+[![Java CI](https://github.com/Kaktushose/Levelbot/actions/workflows/maven.yml/badge.svg?branch=rewrite)](https://github.com/Kaktushose/Levelbot/actions/workflows/maven.yml)
+[![Deploy](https://github.com/Kaktushose/Levelbot/actions/workflows/deploy.yml/badge.svg?branch=rewrite)](https://github.com/Kaktushose/Levelbot/actions/workflows/deploy.yml)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/6eaa0127de99428795b4f5f759da188a)](https://www.codacy.com/gh/Kaktushose/Levelbot/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Kaktushose/Levelbot&utm_campaign=Badge_Grade)
![Generic badge](https://img.shields.io/badge/Version-2.3.0-86c240".svg)
[![license-shield](https://img.shields.io/badge/License-Apache%202.0-lightgrey.svg)]()
From d803339c67984add4841b24e4fbb215d6afad340 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 20:39:38 +0100
Subject: [PATCH 05/66] fix deploy workflow
---
.github/workflows/deploy.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index f2ca6eb..864b946 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -10,6 +10,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
+ with:
+ ref: ${{ github.ref }}
- name: Build Image
id: build-image
uses: redhat-actions/buildah-build@v2
From 62db8c035969314c0c291e09012f6391db3df868 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 21:03:49 +0100
Subject: [PATCH 06/66] update compose file to use ghcr
---
docker-compose.yml | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/docker-compose.yml b/docker-compose.yml
index de23645..10de536 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -25,10 +25,7 @@ services:
- mariadb
bot:
- build:
- context: .
- dockerfile: Dockerfile
- image: nplay-bot
+ image: ghcr.io/kaktushose/levelbot/nplaybot:latest
restart: on-failure
environment:
BOT_TOKEN: ${BOT_TOKEN}
From cca5ae3cbb0f364dce310bee43db526862a85ba7 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 21:04:41 +0100
Subject: [PATCH 07/66] use different port for mariadb while in rewrite
---
docker-compose.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docker-compose.yml b/docker-compose.yml
index 10de536..51ee909 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -12,7 +12,7 @@ services:
volumes:
- ./data/db:/var/lib/mysql
ports:
- - "3306:3306"
+ - "3307:3307"
grafana:
image: grafana/grafana
From 70a77b8f4fb5da0e9fc22bdae5fb9d7ed659c9f2 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 21:47:07 +0100
Subject: [PATCH 08/66] bootstrap jda bot
---
docker-compose.yml | 2 --
.../kaktushose/nplaybot/Bootstrapper.java | 14 +++++++-
.../com/github/kaktushose/nplaybot/Bot.java | 33 +++++++++++++++++++
.../nplaybot/HelloWorldCommand.java | 14 ++++++++
4 files changed, 60 insertions(+), 3 deletions(-)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/Bot.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/HelloWorldCommand.java
diff --git a/docker-compose.yml b/docker-compose.yml
index 51ee909..acdf496 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -32,7 +32,5 @@ services:
BOT_PRODUCTION: ${BOT_PRODUCTION}
DB_USER: ${MYSQL_USER}
DB_PASSWORD: ${MYSQL_PASSWORD}
- ports:
- - "8080:8080"
depends_on:
- mariadb
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java b/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
index 7879bd1..4153a44 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
@@ -9,6 +9,18 @@ public class Bootstrapper {
private final static Logger log = LoggerFactory.getLogger(Bootstrapper.class);
public static void main(String[] args) {
- log.info("Hello World!");
+ long startTime = System.currentTimeMillis();
+ try {
+ log.info("Starting NPLAY-Bot...");
+
+ Bot bot = Bot.start(System.getenv("BOT_TOKEN"));
+ Thread.setDefaultUncaughtExceptionHandler((t, e) -> log.error("An uncaught exception has occurred!", e));
+ Runtime.getRuntime().addShutdownHook(new Thread(bot::shutdown));
+
+ log.info("Successfully started NPLAY-Bot! Took {} ms", System.currentTimeMillis() - startTime);
+ } catch (InterruptedException e) {
+ log.error("Failed to start!", e);
+ System.exit(1);
+ }
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
new file mode 100644
index 0000000..8e4d035
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -0,0 +1,33 @@
+package com.github.kaktushose.nplaybot;
+
+import com.github.kaktushose.jda.commands.JDACommands;
+import net.dv8tion.jda.api.JDA;
+import net.dv8tion.jda.api.JDABuilder;
+import net.dv8tion.jda.api.OnlineStatus;
+import net.dv8tion.jda.api.entities.Activity;
+
+public class Bot {
+
+ private final JDA jda;
+ private final JDACommands jdaCommands;
+
+ private Bot(String token) throws InterruptedException {
+ jda = JDABuilder.createDefault(token)
+ .setActivity(Activity.customStatus("starting..."))
+ .setStatus(OnlineStatus.IDLE)
+ .build().awaitReady();
+
+ jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.0"));
+
+ jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
+ }
+
+ public static Bot start(String token) throws InterruptedException {
+ return new Bot(token);
+ }
+
+ public void shutdown() {
+ jdaCommands.shutdown();
+ jda.shutdown();
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/HelloWorldCommand.java b/src/main/java/com/github/kaktushose/nplaybot/HelloWorldCommand.java
new file mode 100644
index 0000000..523d913
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/HelloWorldCommand.java
@@ -0,0 +1,14 @@
+package com.github.kaktushose.nplaybot;
+
+import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+
+@Interaction
+public class HelloWorldCommand {
+
+ @SlashCommand("hello")
+ public void onCommand(CommandEvent event) {
+ event.reply("Hello World!");
+ }
+}
From fb6d2b3f265adcabc84c88140e3f501b5dba7b66 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 22:50:33 +0100
Subject: [PATCH 09/66] add logs to docker
---
.github/workflows/deploy.yml | 2 +-
.github/workflows/maven.yml | 2 +-
docker-compose.yml | 2 ++
src/main/resources/logback.xml | 2 +-
4 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 864b946..6aebffc 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -9,7 +9,7 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
ref: ${{ github.ref }}
- name: Build Image
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 8b8a2d2..6c592df 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up JDK 21
uses: actions/setup-java@v1
with:
diff --git a/docker-compose.yml b/docker-compose.yml
index acdf496..ff02634 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -32,5 +32,7 @@ services:
BOT_PRODUCTION: ${BOT_PRODUCTION}
DB_USER: ${MYSQL_USER}
DB_PASSWORD: ${MYSQL_PASSWORD}
+ volumes:
+ - ./data/logs:/bot/logs
depends_on:
- mariadb
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index 65cb6dd..8022665 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -8,7 +8,7 @@
- ./levelbot.log
+ ./logs/bot.log
%date [%t] %level %logger - %msg%n
From 25fa18f310f4ab759a7a0383cb43758438cf1166 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 22:56:59 +0100
Subject: [PATCH 10/66] test deployment
---
src/main/java/com/github/kaktushose/nplaybot/Bot.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 8e4d035..983c61a 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -17,7 +17,7 @@ private Bot(String token) throws InterruptedException {
.setStatus(OnlineStatus.IDLE)
.build().awaitReady();
- jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.0"));
+ jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.1"));
jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
}
From c986edc45621cd352007cb0ec8248071e1234023 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 23:03:42 +0100
Subject: [PATCH 11/66] test deployment
---
src/main/java/com/github/kaktushose/nplaybot/Bot.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 983c61a..1a26986 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -17,7 +17,7 @@ private Bot(String token) throws InterruptedException {
.setStatus(OnlineStatus.IDLE)
.build().awaitReady();
- jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.1"));
+ jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.2"));
jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
}
From bcdcf7f1080ba85c7622e0185744893132d48f82 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 23:45:39 +0100
Subject: [PATCH 12/66] test deployment
---
.github/workflows/deploy.yml | 2 +-
src/main/java/com/github/kaktushose/nplaybot/Bot.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 6aebffc..5b0c957 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -20,7 +20,7 @@ jobs:
tags: latest ${{ github.sha }}
containerfiles: |
./Dockerfile
- oci: true
+ oci: false
- name: Push To ghcr.io
id: push-to-ghcr
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 1a26986..6ca1c7c 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -17,7 +17,7 @@ private Bot(String token) throws InterruptedException {
.setStatus(OnlineStatus.IDLE)
.build().awaitReady();
- jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.2"));
+ jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.3"));
jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
}
From 6df2e1ced89408db194c1dc112b736413796e1ef Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 27 Nov 2023 23:51:07 +0100
Subject: [PATCH 13/66] test deployment
---
src/main/java/com/github/kaktushose/nplaybot/Bot.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 6ca1c7c..f06cb45 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -17,7 +17,7 @@ private Bot(String token) throws InterruptedException {
.setStatus(OnlineStatus.IDLE)
.build().awaitReady();
- jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.3"));
+ jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.4"));
jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
}
From 44f441a028e0b2172f863ccfa60245ad4732cba7 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Thu, 30 Nov 2023 22:17:41 +0100
Subject: [PATCH 14/66] add flyway for database migrations
---
.env.example | 2 +-
Dockerfile | 2 ++
docker-compose.yml | 35 +++++++++++++++++++++++++++++++++--
3 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/.env.example b/.env.example
index d446086..05840f9 100644
--- a/.env.example
+++ b/.env.example
@@ -4,4 +4,4 @@ MYSQL_USER=bot
MYSQL_PASSWORD=password
GF_SECURITY_ADMIN_PASSWORD=password
BOT_TOKEN=token
-BOT_PRODUCTION=true
+MYSQL_URL=jdbc:mariadb://localhost:3306/DB
diff --git a/Dockerfile b/Dockerfile
index 2eb96a0..7e951de 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,4 +10,6 @@ FROM openjdk:21
COPY --from=builder /bot/target/NPLAY-Bot.jar ./NPLAY-Bot.jar
+COPY src/main/resources/db/migration ./db/migration
+
CMD ["java", "-jar", "NPLAY-Bot.jar"]
diff --git a/docker-compose.yml b/docker-compose.yml
index ff02634..9ac060e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -3,6 +3,7 @@ version: "3"
services:
mariadb:
image: mariadb
+ container_name: nplay-database
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
@@ -12,10 +13,11 @@ services:
volumes:
- ./data/db:/var/lib/mysql
ports:
- - "3307:3307"
+ - "3307:3306"
grafana:
image: grafana/grafana
+ container_name: nplay-grafana
restart: always
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GF_SECURITY_ADMIN_PASSWORD}
@@ -24,8 +26,23 @@ services:
depends_on:
- mariadb
+ flyway:
+ image: redgate/flyway
+ container_name: nplay-flyway
+ restart: on-failure
+ environment:
+ FLYWAY_URL: ${MYSQL_URL}
+ FLYWAY_USER: ${MYSQL_USER}
+ FLYWAY_PASSWORD: ${MYSQL_PASSWORD}
+ volumes:
+ - db-migrations:/db/migration
+ command: -locations=filesystem:/db/migration migrate
+ depends_on:
+ - mariadb
+
bot:
image: ghcr.io/kaktushose/levelbot/nplaybot:latest
+ container_name: nplay-bot
restart: on-failure
environment:
BOT_TOKEN: ${BOT_TOKEN}
@@ -33,6 +50,20 @@ services:
DB_USER: ${MYSQL_USER}
DB_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- - ./data/logs:/bot/logs
+ - db-migrations:/db/migration
+ - ./data/logs:/logs
depends_on:
- mariadb
+
+ watchtower:
+ image: containrrr/watchtower
+ container_name: nplay-watchtower
+ environment:
+ TZ: Europe/Berlin
+ WATCHTOWER_CLEANUP: true
+ WATCHTOWER_POLL_INTERVAL: 30
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+
+volumes:
+ db-migrations:
From 1ce5f49ee17e8f8d7f58320f479da7d282be0797 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Thu, 30 Nov 2023 23:30:57 +0100
Subject: [PATCH 15/66] update logback file policy
---
.gitignore | 1 +
src/main/resources/logback.xml | 12 ++++++++----
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/.gitignore b/.gitignore
index 017595c..4ac50ea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,4 @@ buildNumber.properties
### Project ###
.env
/data
+/logs
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index 8022665..efed044 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -1,5 +1,4 @@
-
@@ -7,11 +6,16 @@
-
- ./logs/bot.log
+
+ ./logs/nplaybot.log
- %date [%t] %level %logger - %msg%n
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+ ./logs/nplaybot.%d{yyyy-MM-dd}.log
+ 30
+
From 6e219a5bafa694c49af3c0130d66d4888da5a522 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Sun, 3 Dec 2023 20:15:03 +0100
Subject: [PATCH 16/66] first pass on leveling system
---
pom.xml | 10 +++
.../kaktushose/nplaybot/Bootstrapper.java | 4 +-
.../com/github/kaktushose/nplaybot/Bot.java | 12 +++-
.../github/kaktushose/nplaybot/Database.java | 34 ++++++++++
.../nplaybot/HelloWorldCommand.java | 14 ----
.../nplaybot/rank/MessageListener.java | 4 ++
.../kaktushose/nplaybot/rank/RankService.java | 65 +++++++++++++++++++
.../nplaybot/rank/UserStatisticsTask.java | 14 ++++
.../rank/commands/RankInfoCommand.java | 4 ++
.../rank/commands/SetRankCommand.java | 4 ++
.../rank/commands/SwitchDailyCommand.java | 4 ++
.../kaktushose/nplaybot/rank/model/Rank.java | 4 ++
.../nplaybot/rank/model/UserInfo.java | 3 +
.../nplaybot/scheduler/ScheduledTask.java | 4 ++
.../nplaybot/scheduler/TaskScheduler.java | 5 ++
.../migration/V1.0.0__setup_rank_system.sql | 35 ++++++++++
16 files changed, 202 insertions(+), 18 deletions(-)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/Database.java
delete mode 100644 src/main/java/com/github/kaktushose/nplaybot/HelloWorldCommand.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/MessageListener.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/UserStatisticsTask.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/commands/SetRankCommand.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/commands/SwitchDailyCommand.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/model/Rank.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/scheduler/ScheduledTask.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
create mode 100644 src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
diff --git a/pom.xml b/pom.xml
index e295810..2cbf584 100644
--- a/pom.xml
+++ b/pom.xml
@@ -72,6 +72,16 @@
jda-commands
4.0.0-beta.1
+
+ com.zaxxer
+ HikariCP
+ 5.1.0
+
+
+ org.mariadb.jdbc
+ mariadb-java-client
+ 3.3.1
+
org.slf4j
slf4j-api
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java b/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
index 4153a44..f842ac9 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
@@ -13,12 +13,12 @@ public static void main(String[] args) {
try {
log.info("Starting NPLAY-Bot...");
- Bot bot = Bot.start(System.getenv("BOT_TOKEN"));
+ var bot = Bot.start(System.getenv("BOT_TOKEN"));
Thread.setDefaultUncaughtExceptionHandler((t, e) -> log.error("An uncaught exception has occurred!", e));
Runtime.getRuntime().addShutdownHook(new Thread(bot::shutdown));
log.info("Successfully started NPLAY-Bot! Took {} ms", System.currentTimeMillis() - startTime);
- } catch (InterruptedException e) {
+ } catch (Exception e) {
log.error("Failed to start!", e);
System.exit(1);
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index f06cb45..f098d0e 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -10,14 +10,21 @@ public class Bot {
private final JDA jda;
private final JDACommands jdaCommands;
+ private final Database database;
+
+ private Bot(String token) throws InterruptedException, RuntimeException {
+ try {
+ database = new Database();
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to connect to database!", e);
+ }
- private Bot(String token) throws InterruptedException {
jda = JDABuilder.createDefault(token)
.setActivity(Activity.customStatus("starting..."))
.setStatus(OnlineStatus.IDLE)
.build().awaitReady();
- jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.4"));
+ jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.0"));
jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
}
@@ -29,5 +36,6 @@ public static Bot start(String token) throws InterruptedException {
public void shutdown() {
jdaCommands.shutdown();
jda.shutdown();
+ database.closeDataSource();
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Database.java b/src/main/java/com/github/kaktushose/nplaybot/Database.java
new file mode 100644
index 0000000..fc9804f
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/Database.java
@@ -0,0 +1,34 @@
+package com.github.kaktushose.nplaybot;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public class Database {
+
+ private final HikariDataSource dataSource;
+
+ public Database() {
+ var config = new HikariConfig();
+
+ config.setJdbcUrl(System.getenv("MYSQL_URL"));
+ config.setUsername(System.getenv("MYSQL_USER"));
+ config.setPassword(System.getenv("MYSQL_PASSWORD"));
+ config.addDataSourceProperty("databaseName", System.getenv("MYSQL_DATABASE"));
+
+ dataSource = new HikariDataSource(config);
+ }
+
+ public Connection getConnection() throws SQLException {
+ return dataSource.getConnection();
+ }
+
+ public void closeDataSource() {
+ if (dataSource != null) {
+ dataSource.close();
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/HelloWorldCommand.java b/src/main/java/com/github/kaktushose/nplaybot/HelloWorldCommand.java
deleted file mode 100644
index 523d913..0000000
--- a/src/main/java/com/github/kaktushose/nplaybot/HelloWorldCommand.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.github.kaktushose.nplaybot;
-
-import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
-import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
-import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
-
-@Interaction
-public class HelloWorldCommand {
-
- @SlashCommand("hello")
- public void onCommand(CommandEvent event) {
- event.reply("Hello World!");
- }
-}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/MessageListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/MessageListener.java
new file mode 100644
index 0000000..45aa28a
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/MessageListener.java
@@ -0,0 +1,4 @@
+package com.github.kaktushose.nplaybot.rank;
+
+public class MessageListener {
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
new file mode 100644
index 0000000..68b7e6f
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -0,0 +1,65 @@
+package com.github.kaktushose.nplaybot.rank;
+
+import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.rank.model.Rank;
+import com.github.kaktushose.nplaybot.rank.model.UserInfo;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public class RankService {
+
+ private final Database database;
+
+ public RankService(Database database) {
+ this.database = database;
+ }
+
+ public UserInfo getUserInfo(long userId) {
+ try (Connection connection = database.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT xp, rank, message_count, start_xp, role_id, color, bound
+ FROM users JOIN ranks
+ WHERE user_id = ? AND rank_id = rank
+ """
+ );
+ statement.setLong(1, userId);
+
+ var result = statement.executeQuery();
+ result.next();
+ var currentRank = new Rank(
+ result.getLong("role_id"),
+ result.getString("color"),
+ result.getInt("bound") - result.getInt("xp")
+ );
+
+ statement = connection.prepareStatement("""
+ SELECT role_id, color, bound
+ FROM ranks
+ WHERE rank_id = ?
+ """
+ );
+ statement.setLong(1, result.getInt("rank") + 1);
+ result = statement.executeQuery();
+ Rank nextRank = null;
+ if (result.next()) {
+ nextRank = new Rank(
+ result.getLong("role_id"),
+ result.getString("color"),
+ result.getInt("bound") - result.getInt("xp")
+ );
+ }
+
+ return new UserInfo(
+ result.getInt("xp"),
+ currentRank,
+ nextRank,
+ result.getInt("message_count"),
+ result.getInt("xp") - result.getInt("start_xp")
+ );
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/UserStatisticsTask.java b/src/main/java/com/github/kaktushose/nplaybot/rank/UserStatisticsTask.java
new file mode 100644
index 0000000..7f475d4
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/UserStatisticsTask.java
@@ -0,0 +1,14 @@
+package com.github.kaktushose.nplaybot.rank;
+
+import com.github.kaktushose.nplaybot.scheduler.ScheduledTask;
+
+import java.util.function.Consumer;
+
+@ScheduledTask
+public class UserStatisticsTask implements Consumer {
+
+ @Override
+ public void accept(RankService rankService) {
+
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
new file mode 100644
index 0000000..7a3077c
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
@@ -0,0 +1,4 @@
+package com.github.kaktushose.nplaybot.rank.commands;
+
+public class RankInfoCommand {
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SetRankCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SetRankCommand.java
new file mode 100644
index 0000000..4934346
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SetRankCommand.java
@@ -0,0 +1,4 @@
+package com.github.kaktushose.nplaybot.rank.commands;
+
+public class SetRankCommand {
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SwitchDailyCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SwitchDailyCommand.java
new file mode 100644
index 0000000..a1eca88
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SwitchDailyCommand.java
@@ -0,0 +1,4 @@
+package com.github.kaktushose.nplaybot.rank.commands;
+
+public class SwitchDailyCommand {
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/Rank.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/Rank.java
new file mode 100644
index 0000000..e9a257e
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/Rank.java
@@ -0,0 +1,4 @@
+package com.github.kaktushose.nplaybot.rank.model;
+
+public record Rank(long roleId, String color, int missingXp) {
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
new file mode 100644
index 0000000..be8816f
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
@@ -0,0 +1,3 @@
+package com.github.kaktushose.nplaybot.rank.model;
+
+public record UserInfo(int xp, Rank currentRank, Rank nextRank, int messageCount, int xpGain) { }
diff --git a/src/main/java/com/github/kaktushose/nplaybot/scheduler/ScheduledTask.java b/src/main/java/com/github/kaktushose/nplaybot/scheduler/ScheduledTask.java
new file mode 100644
index 0000000..6e943c0
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/scheduler/ScheduledTask.java
@@ -0,0 +1,4 @@
+package com.github.kaktushose.nplaybot.scheduler;
+
+public @interface ScheduledTask {
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java b/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
new file mode 100644
index 0000000..4718ffc
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
@@ -0,0 +1,5 @@
+package com.github.kaktushose.nplaybot.scheduler;
+
+public class TaskScheduler {
+// TODO add via annotations
+}
diff --git a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
new file mode 100644
index 0000000..f349f0a
--- /dev/null
+++ b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
@@ -0,0 +1,35 @@
+create table guild_settings (
+ guild_id bigint(20) not null primary key,
+ bot_token varchar(255) not null,
+ bot_channel_id bigint(20) not null,
+ log_channel_id bigint(20) not null,
+ message_cooldown int(11) not null
+);
+create table users (
+ user_id bigint(20) not null primary key,
+ permission_level int(11) not null,
+ daily_message boolean not null,
+ xp int(11) not null,
+ rank int(11) not null,
+ last_valid_message bigint(20) not null,
+ message_count bigint(20) not null,
+ start_xp int(11) not null,
+);
+create table ranks (
+ rank_id int(11) not null primary key,
+ name varchar(255) not null,
+ color varchar(255) not null,
+ bound int(11) not null,
+ role_id bigint(20) not null
+);
+create table xp_chances (
+ amount int (11) not null primary key,
+ chance int(11) not null
+);
+create table rank_statistics (
+ timestamp bigint(20) not null primary key,
+ total_message_count int(11) not null,
+ valid_message_count int (11) not null,
+ total_xp_gain int(11) not null,
+ total_rank_ups int (11) not null
+)
From d77496ad9ab844aba59d189d8224024f555460dd Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Thu, 7 Dec 2023 14:39:08 +0100
Subject: [PATCH 17/66] switch from postgres to mariadb
---
.env.example | 11 ++--
.gitignore | 3 +-
Dockerfile | 14 +++--
docker-compose.yml | 52 +++++++------------
entrypoint.sh | 9 ++++
pom.xml | 6 +--
.../kaktushose/nplaybot/Bootstrapper.java | 2 +-
.../com/github/kaktushose/nplaybot/Bot.java | 8 +--
.../github/kaktushose/nplaybot/Database.java | 18 ++++---
9 files changed, 65 insertions(+), 58 deletions(-)
create mode 100644 entrypoint.sh
diff --git a/.env.example b/.env.example
index 05840f9..a4573c8 100644
--- a/.env.example
+++ b/.env.example
@@ -1,7 +1,6 @@
-MYSQL_ROOT_PASSWORD=password
-MYSQL_DATABASE=nplaybot
-MYSQL_USER=bot
-MYSQL_PASSWORD=password
+POSTGRES_DB=database
+POSTGRES_USER=user
+POSTGRES_PASSWORD=password
+POSTGRES_URL=jdbc:postgresql://postgres:5432/database
GF_SECURITY_ADMIN_PASSWORD=password
-BOT_TOKEN=token
-MYSQL_URL=jdbc:mariadb://localhost:3306/DB
+BOT_GUILD=0123456789
diff --git a/.gitignore b/.gitignore
index 4ac50ea..0306ffc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,7 @@ buildNumber.properties
.mvn/wrapper/maven-wrapper.jar
### Project ###
-.env
+*.env
/data
/logs
+wait-for-it.sh
diff --git a/Dockerfile b/Dockerfile
index 7e951de..ec363af 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,15 +1,23 @@
+FROM redgate/flyway as flyway
+
+WORKDIR /flyway
+
+
FROM maven:3.9.5-amazoncorretto-21-debian AS builder
WORKDIR /bot
-
COPY . .
-
RUN mvn clean package -DskipTests
FROM openjdk:21
+COPY --from=flyway /flyway ./flyway
+COPY src/main/resources/db/migration ./db/migration
+
+COPY --from=builder /bot/*.sh .
COPY --from=builder /bot/target/NPLAY-Bot.jar ./NPLAY-Bot.jar
-COPY src/main/resources/db/migration ./db/migration
+RUN chmod +x ./wait-for-it.sh ./entrypoint.sh
+ENTRYPOINT ["./entrypoint.sh"]
CMD ["java", "-jar", "NPLAY-Bot.jar"]
diff --git a/docker-compose.yml b/docker-compose.yml
index 9ac060e..ab11df0 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,19 +1,18 @@
version: "3"
services:
- mariadb:
- image: mariadb
+ postgres:
+ image: postgres
container_name: nplay-database
restart: always
environment:
- MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE: ${MYSQL_DATABASE}
- MYSQL_USER: ${MYSQL_USER}
- MYSQL_PASSWORD: ${MYSQL_PASSWORD}
+ POSTGRES_USER: ${POSTGRES_USER}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_DB: ${POSTGRES_DB}
volumes:
- - ./data/db:/var/lib/mysql
+ - ./data/db:/var/lib/postgresql/data
ports:
- - "3307:3306"
+ - "5432:5432"
grafana:
image: grafana/grafana
@@ -24,46 +23,33 @@ services:
ports:
- "3000:3000"
depends_on:
- - mariadb
-
- flyway:
- image: redgate/flyway
- container_name: nplay-flyway
- restart: on-failure
- environment:
- FLYWAY_URL: ${MYSQL_URL}
- FLYWAY_USER: ${MYSQL_USER}
- FLYWAY_PASSWORD: ${MYSQL_PASSWORD}
- volumes:
- - db-migrations:/db/migration
- command: -locations=filesystem:/db/migration migrate
- depends_on:
- - mariadb
+ - postgres
bot:
- image: ghcr.io/kaktushose/levelbot/nplaybot:latest
+ build:
+ context: .
container_name: nplay-bot
restart: on-failure
environment:
- BOT_TOKEN: ${BOT_TOKEN}
- BOT_PRODUCTION: ${BOT_PRODUCTION}
- DB_USER: ${MYSQL_USER}
- DB_PASSWORD: ${MYSQL_PASSWORD}
+ POSTGRES_USER: ${POSTGRES_USER}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_URL: ${POSTGRES_URL}
+ POSTGRES_DB: ${POSTGRES_DB}
+ BOT_GUILD: ${BOT_GUILD}
+ labels:
+ - com.centurylinklabs.watchtower.enable="true"
volumes:
- - db-migrations:/db/migration
- ./data/logs:/logs
depends_on:
- - mariadb
+ - postgres
watchtower:
image: containrrr/watchtower
container_name: nplay-watchtower
environment:
TZ: Europe/Berlin
+ WATCHTOWER_LABEL_ENABLE: true
WATCHTOWER_CLEANUP: true
WATCHTOWER_POLL_INTERVAL: 30
volumes:
- /var/run/docker.sock:/var/run/docker.sock
-
-volumes:
- db-migrations:
diff --git a/entrypoint.sh b/entrypoint.sh
new file mode 100644
index 0000000..4b83591
--- /dev/null
+++ b/entrypoint.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+set -e
+
+/wait-for-it.sh -t 30 postgres:5432
+
+/flyway/flyway migrate -url="$POSTGRES_URL" -user="$POSTGRES_USER" -password="$POSTGRES_PASSWORD" -locations=filesystem:/db/migration
+
+exec "$@"
diff --git a/pom.xml b/pom.xml
index 2cbf584..6f263cc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,9 +78,9 @@
5.1.0
- org.mariadb.jdbc
- mariadb-java-client
- 3.3.1
+ org.postgresql
+ postgresql
+ 42.7.0
org.slf4j
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java b/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
index f842ac9..9003757 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
@@ -13,7 +13,7 @@ public static void main(String[] args) {
try {
log.info("Starting NPLAY-Bot...");
- var bot = Bot.start(System.getenv("BOT_TOKEN"));
+ var bot = Bot.start(Long.parseLong(System.getenv("BOT_GUILD")));
Thread.setDefaultUncaughtExceptionHandler((t, e) -> log.error("An uncaught exception has occurred!", e));
Runtime.getRuntime().addShutdownHook(new Thread(bot::shutdown));
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index f098d0e..7fb73b2 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -12,14 +12,14 @@ public class Bot {
private final JDACommands jdaCommands;
private final Database database;
- private Bot(String token) throws InterruptedException, RuntimeException {
+ private Bot(long guildId) throws InterruptedException, RuntimeException {
try {
database = new Database();
} catch (Exception e) {
throw new RuntimeException("Unable to connect to database!", e);
}
- jda = JDABuilder.createDefault(token)
+ jda = JDABuilder.createDefault(database.getSettingsService().getBotToken(guildId))
.setActivity(Activity.customStatus("starting..."))
.setStatus(OnlineStatus.IDLE)
.build().awaitReady();
@@ -29,8 +29,8 @@ private Bot(String token) throws InterruptedException, RuntimeException {
jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
}
- public static Bot start(String token) throws InterruptedException {
- return new Bot(token);
+ public static Bot start(long guildId) throws InterruptedException {
+ return new Bot(guildId);
}
public void shutdown() {
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Database.java b/src/main/java/com/github/kaktushose/nplaybot/Database.java
index fc9804f..771b098 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Database.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Database.java
@@ -1,5 +1,6 @@
package com.github.kaktushose.nplaybot;
+import com.github.kaktushose.nplaybot.settings.SettingsService;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
@@ -9,20 +10,20 @@
public class Database {
private final HikariDataSource dataSource;
+ private final SettingsService settingsService;
public Database() {
var config = new HikariConfig();
- config.setJdbcUrl(System.getenv("MYSQL_URL"));
- config.setUsername(System.getenv("MYSQL_USER"));
- config.setPassword(System.getenv("MYSQL_PASSWORD"));
- config.addDataSourceProperty("databaseName", System.getenv("MYSQL_DATABASE"));
+ System.out.println(System.getenv("POSTGRES_URL"));
+ config.setJdbcUrl(System.getenv("POSTGRES_URL"));
+ config.setUsername(System.getenv("POSTGRES_USER"));
+ config.setPassword(System.getenv("POSTGRES_PASSWORD"));
+ config.addDataSourceProperty("databaseName", System.getenv("POSTGRES_DB"));
dataSource = new HikariDataSource(config);
- }
- public Connection getConnection() throws SQLException {
- return dataSource.getConnection();
+ settingsService = new SettingsService(dataSource);
}
public void closeDataSource() {
@@ -31,4 +32,7 @@ public void closeDataSource() {
}
}
+ public SettingsService getSettingsService() {
+ return settingsService;
+ }
}
From d2476201c79ecf124d557cfce78ea6461f951646 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 11 Dec 2023 15:51:01 +0100
Subject: [PATCH 18/66] first pass on rank system
---
.../com/github/kaktushose/nplaybot/Bot.java | 10 ++
.../github/kaktushose/nplaybot/Database.java | 10 +-
.../nplaybot/rank/MessageListener.java | 4 -
.../nplaybot/rank/RankListener.java | 26 +++
.../kaktushose/nplaybot/rank/RankService.java | 66 +++++++-
.../nplaybot/settings/SettingsService.java | 32 ++++
.../migration/V1.0.0__setup_rank_system.sql | 152 ++++++++++++++----
7 files changed, 257 insertions(+), 43 deletions(-)
delete mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/MessageListener.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 7fb73b2..b44f421 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -1,10 +1,12 @@
package com.github.kaktushose.nplaybot;
import com.github.kaktushose.jda.commands.JDACommands;
+import com.github.kaktushose.nplaybot.rank.RankListener;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.entities.Activity;
+import net.dv8tion.jda.api.requests.GatewayIntent;
public class Bot {
@@ -20,8 +22,16 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
}
jda = JDABuilder.createDefault(database.getSettingsService().getBotToken(guildId))
+ .enableIntents(
+ GatewayIntent.GUILD_MEMBERS,
+ GatewayIntent.GUILD_PRESENCES,
+ GatewayIntent.MESSAGE_CONTENT
+ )
.setActivity(Activity.customStatus("starting..."))
.setStatus(OnlineStatus.IDLE)
+ .addEventListeners(
+ new RankListener(database.getRankService())
+ )
.build().awaitReady();
jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.0"));
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Database.java b/src/main/java/com/github/kaktushose/nplaybot/Database.java
index 771b098..437987c 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Database.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Database.java
@@ -1,16 +1,15 @@
package com.github.kaktushose.nplaybot;
+import com.github.kaktushose.nplaybot.rank.RankService;
import com.github.kaktushose.nplaybot.settings.SettingsService;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
-import java.sql.Connection;
-import java.sql.SQLException;
-
public class Database {
private final HikariDataSource dataSource;
private final SettingsService settingsService;
+ private final RankService rankService;
public Database() {
var config = new HikariConfig();
@@ -24,6 +23,7 @@ public Database() {
dataSource = new HikariDataSource(config);
settingsService = new SettingsService(dataSource);
+ rankService = new RankService(dataSource);
}
public void closeDataSource() {
@@ -35,4 +35,8 @@ public void closeDataSource() {
public SettingsService getSettingsService() {
return settingsService;
}
+
+ public RankService getRankService() {
+ return rankService;
+ }
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/MessageListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/MessageListener.java
deleted file mode 100644
index 45aa28a..0000000
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/MessageListener.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.github.kaktushose.nplaybot.rank;
-
-public class MessageListener {
-}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
new file mode 100644
index 0000000..e80e6d4
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
@@ -0,0 +1,26 @@
+package com.github.kaktushose.nplaybot.rank;
+
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.hooks.ListenerAdapter;
+import org.jetbrains.annotations.NotNull;
+
+public class RankListener extends ListenerAdapter {
+
+ private final RankService rankService;
+
+ public RankListener(RankService rankService) {
+ this.rankService = rankService;
+ }
+
+ @Override
+ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
+ var author = event.getAuthor();
+ var message = event.getMessage();
+
+ if (author.isBot()) {
+ return;
+ }
+
+ event.getChannel().sendMessage("valid message: " + rankService.isValidMessage(message)).queue();
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 68b7e6f..d08b9af 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -1,22 +1,26 @@
package com.github.kaktushose.nplaybot.rank;
-import com.github.kaktushose.nplaybot.Database;
import com.github.kaktushose.nplaybot.rank.model.Rank;
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
+import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.channel.ChannelType;
+import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
public class RankService {
- private final Database database;
+ private final DataSource dataSource;
- public RankService(Database database) {
- this.database = database;
+ public RankService(DataSource dataSource) {
+ this.dataSource = dataSource;
}
public UserInfo getUserInfo(long userId) {
- try (Connection connection = database.getConnection()) {
+ try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
SELECT xp, rank, message_count, start_xp, role_id, color, bound
FROM users JOIN ranks
@@ -62,4 +66,56 @@ public UserInfo getUserInfo(long userId) {
}
}
+ public boolean isValidMessage(Message message) {
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT rank_settings.*, users.last_valid_message
+ FROM rank_settings JOIN users ON user_id = ?
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, message.getAuthor().getIdLong());
+ statement.setLong(2, message.getGuildIdLong());
+
+ var result = statement.executeQuery();
+ result.next();
+ var lastMessage = result.getLong("last_valid_message");
+ var messageCooldown = result.getInt("message_cooldown");
+ var minimumLength = result.getInt("min_message_length");
+ var validChannels = Arrays.asList((Long[]) result.getArray("valid_channels").getArray());
+
+ if (System.currentTimeMillis() - lastMessage < messageCooldown) {
+ return false;
+ }
+
+ if (message.getContentDisplay().length() < minimumLength) {
+ return false;
+ }
+
+ var channelId = message.getChannelIdLong();
+ if (message.getChannelType().isThread()) {
+ channelId = message.getChannel().asThreadChannel().getParentChannel().getIdLong();
+ }
+ return validChannels.contains(channelId);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int getRandomXp() {
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT *
+ FROM get_random_xp()
+ """
+ );
+
+ var result = statement.executeQuery();
+ result.next();
+ return result.getInt(1);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java b/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java
new file mode 100644
index 0000000..f8a19c3
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java
@@ -0,0 +1,32 @@
+package com.github.kaktushose.nplaybot.settings;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public class SettingsService {
+
+ private final DataSource dataSource;
+
+ public SettingsService(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public String getBotToken(long guildId) {
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT bot_token
+ FROM guild_settings
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, guildId);
+
+ var result = statement.executeQuery();
+ result.next();
+ return result.getString(1);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
index f349f0a..4716697 100644
--- a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
+++ b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
@@ -1,35 +1,125 @@
-create table guild_settings (
- guild_id bigint(20) not null primary key,
- bot_token varchar(255) not null,
- bot_channel_id bigint(20) not null,
- log_channel_id bigint(20) not null,
- message_cooldown int(11) not null
+CREATE TABLE guild_settings (
+ guild_id BIGINT NOT NULL PRIMARY KEY,
+ bot_token VARCHAR(255) NOT NULL,
+ bot_channel_id BIGINT NOT NULL,
+ log_channel_id BIGINT NOT NULL
);
-create table users (
- user_id bigint(20) not null primary key,
- permission_level int(11) not null,
- daily_message boolean not null,
- xp int(11) not null,
- rank int(11) not null,
- last_valid_message bigint(20) not null,
- message_count bigint(20) not null,
- start_xp int(11) not null,
+
+CREATE TABLE rank_settings (
+ guild_id BIGINT NOT NULL PRIMARY KEY,
+ message_cooldown INT NOT NULL,
+ min_message_length INT NOT NULL,
+ valid_channels BIGINT[] NOT NULL
);
-create table ranks (
- rank_id int(11) not null primary key,
- name varchar(255) not null,
- color varchar(255) not null,
- bound int(11) not null,
- role_id bigint(20) not null
+
+CREATE TABLE ranks (
+ rank_id INT NOT NULL PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ color VARCHAR(255) NOT NULL,
+ bound INT NOT NULL,
+ role_id BIGINT NOT NULL
);
-create table xp_chances (
- amount int (11) not null primary key,
- chance int(11) not null
+
+CREATE TABLE users (
+ user_id BIGINT NOT NULL PRIMARY KEY,
+ daily_message BOOLEAN NOT NULL,
+ xp INT NOT NULL,
+ rank_id INT NOT NULL REFERENCES ranks(rank_id),
+ last_valid_message BIGINT NOT NULL,
+ message_count BIGINT NOT NULL,
+ start_xp INT NOT NULL
);
-create table rank_statistics (
- timestamp bigint(20) not null primary key,
- total_message_count int(11) not null,
- valid_message_count int (11) not null,
- total_xp_gain int(11) not null,
- total_rank_ups int (11) not null
-)
+
+CREATE TABLE xp_chances (
+ amount INT NOT NULL PRIMARY KEY,
+ chance INT NOT NULL
+);
+
+CREATE TABLE rank_statistics (
+ timestamp BIGINT NOT NULL PRIMARY KEY,
+ total_message_count INT NOT NULL,
+ valid_message_count INT NOT NULL,
+ total_xp_gain INT NOT NULL,
+ total_rank_ups INT NOT NULL
+);
+
+CREATE FUNCTION update_rank_trigger()
+RETURNS TRIGGER AS
+$$
+DECLARE
+ new_rank ranks;
+BEGIN
+ SELECT INTO new_rank * FROM ranks WHERE NEW.xp >= bound ORDER BY bound DESC LIMIT 1;
+
+ UPDATE users SET rank_id = new_rank.rank_id WHERE user_id = NEW.user_id;
+
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE TRIGGER update_rank_trigger
+AFTER UPDATE OF xp ON users
+FOR EACH ROW
+EXECUTE FUNCTION update_rank_trigger();
+
+CREATE FUNCTION set_xp(id BIGINT, new_xp INT)
+RETURNS TABLE (rank_changed BOOLEAN, current_rank int, next_rank int) AS
+$$
+DECLARE
+ old_rank INT;
+ new_rank INT;
+BEGIN
+ SELECT INTO old_rank users.rank_id FROM users WHERE users.user_id = id;
+ UPDATE users SET xp = new_xp WHERE users.user_id = id;
+ SELECT INTO new_rank users.rank_id FROM users WHERE users.user_id = id;
+
+
+ SELECT INTO rank_changed old_rank <> new_rank;
+ SELECT INTO current_rank new_rank;
+ SELECT INTO next_rank new_rank + 1;
+ RETURN NEXT;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION add_xp(id BIGINT, xp_to_add INT)
+RETURNS TABLE (rank_changed BOOLEAN, current_rank int, next_rank INT, current_xp INT) AS
+$$
+DECLARE
+BEGIN
+ SELECT xp_to_add + users.xp INTO current_xp FROM users WHERE users.user_id = id;
+ SELECT INTO rank_changed, current_rank, next_rank * FROM set_xp(id, current_xp);
+ RETURN NEXT;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION get_random_xp()
+RETURNS INT AS
+$$
+DECLARE
+ result_row RECORD;
+ xp_chance INT;
+ chance_sum INT;
+BEGIN
+ xp_chance := floor(random() * 100) + 1;
+ chance_sum := 0;
+ FOR result_row IN SELECT * FROM xp_chances
+ LOOP
+ chance_sum := chance_sum + result_row.chance;
+ IF chance_sum >= xp_chance THEN
+ RETURN result_row.amount;
+ END IF;
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION add_random_xp(id BIGINT)
+RETURNS TABLE (rank_changed BOOLEAN, current_rank int, next_rank INT, current_xp INT) AS
+$$
+DECLARE
+ xp INT;
+BEGIN
+ SELECT get_random_xp INTO xp FROM get_random_xp();
+ SELECT INTO rank_changed, current_rank, next_rank, current_xp * FROM add_xp(id, xp);
+ RETURN NEXT;
+END;
+$$ LANGUAGE plpgsql;
From 77ac1ef057cfd0e4541818ae3212db78ddee246c Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Tue, 12 Dec 2023 17:47:50 +0100
Subject: [PATCH 19/66] implement xp gain, cooldown and rank up
---
docker-compose.yml | 2 +-
embeds.json | 32 ++++++
.../com/github/kaktushose/nplaybot/Bot.java | 15 ++-
.../nplaybot/rank/RankListener.java | 38 ++++++-
.../kaktushose/nplaybot/rank/RankService.java | 99 +++++++++++++------
.../kaktushose/nplaybot/rank/model/Rank.java | 4 -
.../nplaybot/rank/model/RankInfo.java | 4 +
.../nplaybot/rank/model/UserInfo.java | 5 +-
.../nplaybot/rank/model/XpChangeResult.java | 23 +++++
9 files changed, 183 insertions(+), 39 deletions(-)
create mode 100644 embeds.json
delete mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/model/Rank.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/model/RankInfo.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java
diff --git a/docker-compose.yml b/docker-compose.yml
index ab11df0..a0a1f9a 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -37,7 +37,7 @@ services:
POSTGRES_DB: ${POSTGRES_DB}
BOT_GUILD: ${BOT_GUILD}
labels:
- - com.centurylinklabs.watchtower.enable="true"
+ - com.centurylinklabs.watchtower.enable="true"
volumes:
- ./data/logs:/logs
depends_on:
diff --git a/embeds.json b/embeds.json
new file mode 100644
index 0000000..797ce8e
--- /dev/null
+++ b/embeds.json
@@ -0,0 +1,32 @@
+{
+ "rankChangeIncrease": {
+ "title": ":arrow_up: Stufenaufstieg!",
+ "description": "{user}",
+ "color": "{color}",
+ "fields": [
+ {
+ "name": "Neue Stufe:",
+ "value": ":level_slider: {currentRank}"
+ },
+ {
+ "name": "Nächste Stufe:",
+ "value": ":dart: {nextRank} (noch {xp} XP)"
+ }
+ ]
+ },
+ "rankChangeMax": {
+ "title": ":arrow_up: Stufenaufstieg!",
+ "description": "{user}",
+ "color": "{color}",
+ "fields": [
+ {
+ "name": "Neue Stufe:",
+ "value": ":level_slider: {currentRank}"
+ },
+ {
+ "name": "Herzlichen Glückwunsch",
+ "value": ":confetti_ball: Du hast hiermit die maximale Stufe erreicht"
+ }
+ ]
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index b44f421..9fa7e22 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -1,6 +1,7 @@
package com.github.kaktushose.nplaybot;
import com.github.kaktushose.jda.commands.JDACommands;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.nplaybot.rank.RankListener;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
@@ -13,6 +14,7 @@ public class Bot {
private final JDA jda;
private final JDACommands jdaCommands;
private final Database database;
+ private final EmbedCache embedCache;
private Bot(long guildId) throws InterruptedException, RuntimeException {
try {
@@ -21,6 +23,8 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
throw new RuntimeException("Unable to connect to database!", e);
}
+ embedCache = new EmbedCache("embeds.json");
+
jda = JDABuilder.createDefault(database.getSettingsService().getBotToken(guildId))
.enableIntents(
GatewayIntent.GUILD_MEMBERS,
@@ -30,10 +34,9 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
.setActivity(Activity.customStatus("starting..."))
.setStatus(OnlineStatus.IDLE)
.addEventListeners(
- new RankListener(database.getRankService())
+ new RankListener(database.getRankService(), embedCache)
)
.build().awaitReady();
-
jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.0"));
jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
@@ -48,4 +51,12 @@ public void shutdown() {
jda.shutdown();
database.closeDataSource();
}
+
+ public Database getDatabase() {
+ return database;
+ }
+
+ public EmbedCache getEmbedCache() {
+ return embedCache;
+ }
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
index e80e6d4..f3c1ef9 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
@@ -1,15 +1,24 @@
package com.github.kaktushose.nplaybot.rank;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
+import java.util.List;
+
+@SuppressWarnings("DataFlowIssue")
public class RankListener extends ListenerAdapter {
private final RankService rankService;
+ private final EmbedCache embedCache;
- public RankListener(RankService rankService) {
+ public RankListener(RankService rankService, EmbedCache embedCache) {
this.rankService = rankService;
+ this.embedCache = embedCache;
}
@Override
@@ -20,7 +29,32 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
if (author.isBot()) {
return;
}
+ if (!event.isFromGuild()) {
+ return;
+ }
+ if (!rankService.isValidMessage(message)) {
+ return;
+ }
+
+ rankService.updateValidMessage(author);
+ var result = rankService.addRandomXp(author);
+ updateRankRoles(event.getMember(), event.getGuild(), result);
+
+ if (!result.rankChanged()) {
+ return;
+ }
+ String embed = result.nextRank().isPresent() ? "rankChangeIncrease" : "rankChangeMax";
+ event.getChannel().sendMessage(
+ embedCache.getEmbed(embed).injectValues(result.getEmbedValues(author)).toMessageCreateData()
+ ).queue();
+ }
- event.getChannel().sendMessage("valid message: " + rankService.isValidMessage(message)).queue();
+ private void updateRankRoles(Member member, Guild guild, XpChangeResult result) {
+ var validRole = guild.getRoleById(result.currentRank().roleId());
+ var invalidRoles = rankService.getRankRoleIds().stream()
+ .map(guild::getRoleById)
+ .filter(it -> it != validRole)
+ .toList();
+ guild.modifyMemberRoles(member, List.of(validRole), invalidRoles).queue();
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index d08b9af..251a85d 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -1,15 +1,18 @@
package com.github.kaktushose.nplaybot.rank;
-import com.github.kaktushose.nplaybot.rank.model.Rank;
+import com.github.kaktushose.nplaybot.rank.model.RankInfo;
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
+import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
import net.dv8tion.jda.api.entities.Message;
-import net.dv8tion.jda.api.entities.channel.ChannelType;
+import net.dv8tion.jda.api.entities.User;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
public class RankService {
@@ -19,40 +22,46 @@ public RankService(DataSource dataSource) {
this.dataSource = dataSource;
}
- public UserInfo getUserInfo(long userId) {
+ private Optional getRankInfo(int rankId) {
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
- SELECT xp, rank, message_count, start_xp, role_id, color, bound
- FROM users JOIN ranks
- WHERE user_id = ? AND rank_id = rank
- """
- );
- statement.setLong(1, userId);
-
- var result = statement.executeQuery();
- result.next();
- var currentRank = new Rank(
- result.getLong("role_id"),
- result.getString("color"),
- result.getInt("bound") - result.getInt("xp")
- );
-
- statement = connection.prepareStatement("""
SELECT role_id, color, bound
FROM ranks
WHERE rank_id = ?
"""
);
- statement.setLong(1, result.getInt("rank") + 1);
- result = statement.executeQuery();
- Rank nextRank = null;
+ statement.setLong(1, rankId);
+
+ var result = statement.executeQuery();
+
if (result.next()) {
- nextRank = new Rank(
+ return Optional.of(new RankInfo(
result.getLong("role_id"),
result.getString("color"),
- result.getInt("bound") - result.getInt("xp")
- );
+ result.getInt("bound")
+ ));
}
+ return Optional.empty();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public UserInfo getUserInfo(long userId) {
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT xp, rank_id, message_count, start_xp
+ FROM users
+ WHERE user_id = ?
+ """
+ );
+ statement.setLong(1, userId);
+
+ var result = statement.executeQuery();
+ result.next();
+
+ var currentRank = getRankInfo(result.getInt("rank_id")).orElseThrow();
+ var nextRank = getRankInfo(result.getInt("rank_id") + 1);
return new UserInfo(
result.getInt("xp"),
@@ -102,17 +111,49 @@ public boolean isValidMessage(Message message) {
}
}
- public int getRandomXp() {
+ public void updateValidMessage(User user) {
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
- SELECT *
- FROM get_random_xp()
+ UPDATE users
+ SET last_valid_message = ?
+ WHERE user_id = ?
"""
);
+ statement.setLong(1, System.currentTimeMillis());
+ statement.setLong(2, user.getIdLong());
+
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public XpChangeResult addRandomXp(User user) {
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("SELECT * FROM add_random_xp(?)");
+ statement.setLong(1, user.getIdLong());
var result = statement.executeQuery();
result.next();
- return result.getInt(1);
+ return new XpChangeResult(
+ result.getBoolean("rank_changed"),
+ getRankInfo(result.getInt("current_rank")).orElseThrow(),
+ getRankInfo(result.getInt("next_rank")),
+ result.getInt("current_xp")
+ );
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public List getRankRoleIds() {
+ try (Connection connection = dataSource.getConnection()) {
+ var result = connection.prepareStatement("SELECT role_id FROM ranks").executeQuery();
+ var roleIds = new ArrayList();
+ while (result.next()) {
+ roleIds.add(result.getLong(1));
+ }
+ return roleIds;
} catch (SQLException e) {
throw new RuntimeException(e);
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/Rank.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/Rank.java
deleted file mode 100644
index e9a257e..0000000
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/model/Rank.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.github.kaktushose.nplaybot.rank.model;
-
-public record Rank(long roleId, String color, int missingXp) {
-}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/RankInfo.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/RankInfo.java
new file mode 100644
index 0000000..01317d6
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/RankInfo.java
@@ -0,0 +1,4 @@
+package com.github.kaktushose.nplaybot.rank.model;
+
+public record RankInfo(long roleId, String color, int xpBound) {
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
index be8816f..7577817 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
@@ -1,3 +1,6 @@
package com.github.kaktushose.nplaybot.rank.model;
-public record UserInfo(int xp, Rank currentRank, Rank nextRank, int messageCount, int xpGain) { }
+import java.util.Optional;
+
+public record UserInfo(int xp, RankInfo currentRank, Optional nextRank, int messageCount, int xpGain) {
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java
new file mode 100644
index 0000000..47bbafa
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java
@@ -0,0 +1,23 @@
+package com.github.kaktushose.nplaybot.rank.model;
+
+import net.dv8tion.jda.api.entities.User;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+public record XpChangeResult(boolean rankChanged, RankInfo currentRank, Optional nextRank, int currentXp) {
+
+ public Map getEmbedValues(User user) {
+ var result = new HashMap() {{
+ put("user", String.format("<@%d>", user.getIdLong()));
+ put("color", currentRank.color());
+ put("currentRank", String.format("<@&%d>", currentRank.roleId()));
+ }};
+ nextRank.ifPresent(rank -> {
+ result.put("nextRank", String.format("<@&%d>", rank.roleId()));
+ result.put("xp", rank.xpBound() - currentXp);
+ });
+ return result;
+ }
+}
From 1e064cc9fd1b961ac688e59ace32268c6e400a76 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Wed, 13 Dec 2023 19:10:23 +0100
Subject: [PATCH 20/66] implement rank info command
---
embeds.json | 65 ++++++++++++++++++-
.../com/github/kaktushose/nplaybot/Bot.java | 5 ++
.../nplaybot/rank/RankListener.java | 2 +-
.../kaktushose/nplaybot/rank/RankService.java | 5 +-
.../nplaybot/rank/UserStatisticsTask.java | 14 ----
.../rank/commands/RankInfoCommand.java | 25 +++++++
.../nplaybot/rank/model/UserInfo.java | 23 ++++++-
7 files changed, 119 insertions(+), 20 deletions(-)
delete mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/UserStatisticsTask.java
diff --git a/embeds.json b/embeds.json
index 797ce8e..f579b22 100644
--- a/embeds.json
+++ b/embeds.json
@@ -1,5 +1,5 @@
{
- "rankChangeIncrease": {
+ "rankIncrease": {
"title": ":arrow_up: Stufenaufstieg!",
"description": "{user}",
"color": "{color}",
@@ -14,7 +14,7 @@
}
]
},
- "rankChangeMax": {
+ "rankIncreaseMax": {
"title": ":arrow_up: Stufenaufstieg!",
"description": "{user}",
"color": "{color}",
@@ -28,5 +28,66 @@
"value": ":confetti_ball: Du hast hiermit die maximale Stufe erreicht"
}
]
+ },
+ "rankInfo": {
+ "title": ":information_source: Kontoinformation für",
+ "description": "{user}",
+ "color": "{color}",
+ "thumbnail": {
+ "url": "{avatarUrl}"
+ },
+ "fields": [
+ {
+ "name": "Stufe",
+ "value": ":level_slider: {currentRank}"
+ },
+ {
+ "name": "Nächste Stufe",
+ "value": ":dart: {nextRank} (noch {missingXp} XP)"
+ },
+ {
+ "name": "Aktuelle XP",
+ "value": ":star2: {currentXp}"
+ },
+ {
+ "name": "XP-Zuwachs (24h):",
+ "value": ":chart_with_upwards_trend: {xpGain}"
+ },
+ {
+ "name": "Gewertete Nachrichten:",
+ "value": ":bar_chart: {messageCount}"
+ }
+ ]
+ },
+ "rankInfoMax": {
+ "title": ":information_source: Kontoinformation für",
+ "description": "{user}",
+ "color": "{color}",
+ "thumbnail": {
+ "url": "{avatarUrl}"
+ },
+ "fields": [
+ {
+ "name": "Stufe",
+ "value": ":level_slider: {currentRank}"
+ },
+ {
+ "name": "Aktuelle XP",
+ "value": ":star2: {currentXp}"
+ },
+ {
+ "name": "XP-Zuwachs (24h):",
+ "value": ":chart_with_upwards_trend: {xpGain}"
+ },
+ {
+ "name": "Gewertete Nachrichten:",
+ "value": ":bar_chart: {messageCount}"
+ }
+ ]
+ },
+ "embedCacheReload": {
+ "title": "Erfolg",
+ "description": "Der EmbedCache wurde aktualisiert",
+ "color": "#67c94f"
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 9fa7e22..5c1b560 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -1,6 +1,7 @@
package com.github.kaktushose.nplaybot;
import com.github.kaktushose.jda.commands.JDACommands;
+import com.github.kaktushose.jda.commands.annotations.Produces;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.nplaybot.rank.RankListener;
import net.dv8tion.jda.api.JDA;
@@ -40,6 +41,8 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.0"));
jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
+
+ jdaCommands.getDependencyInjector().registerProvider(this);
}
public static Bot start(long guildId) throws InterruptedException {
@@ -52,10 +55,12 @@ public void shutdown() {
database.closeDataSource();
}
+ @Produces
public Database getDatabase() {
return database;
}
+ @Produces
public EmbedCache getEmbedCache() {
return embedCache;
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
index f3c1ef9..90c0c35 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
@@ -43,7 +43,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
if (!result.rankChanged()) {
return;
}
- String embed = result.nextRank().isPresent() ? "rankChangeIncrease" : "rankChangeMax";
+ var embed = result.nextRank().isPresent() ? "rankIncrease" : "rankIncreaseMax";
event.getChannel().sendMessage(
embedCache.getEmbed(embed).injectValues(result.getEmbedValues(author)).toMessageCreateData()
).queue();
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 251a85d..ed39ccc 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -3,6 +3,7 @@
import com.github.kaktushose.nplaybot.rank.model.RankInfo;
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
+import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
@@ -47,7 +48,7 @@ private Optional getRankInfo(int rankId) {
}
}
- public UserInfo getUserInfo(long userId) {
+ public UserInfo getUserInfo(Member member) {
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
SELECT xp, rank_id, message_count, start_xp
@@ -55,7 +56,7 @@ public UserInfo getUserInfo(long userId) {
WHERE user_id = ?
"""
);
- statement.setLong(1, userId);
+ statement.setLong(1, member.getIdLong());
var result = statement.executeQuery();
result.next();
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/UserStatisticsTask.java b/src/main/java/com/github/kaktushose/nplaybot/rank/UserStatisticsTask.java
deleted file mode 100644
index 7f475d4..0000000
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/UserStatisticsTask.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.github.kaktushose.nplaybot.rank;
-
-import com.github.kaktushose.nplaybot.scheduler.ScheduledTask;
-
-import java.util.function.Consumer;
-
-@ScheduledTask
-public class UserStatisticsTask implements Consumer {
-
- @Override
- public void accept(RankService rankService) {
-
- }
-}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
index 7a3077c..53c6b78 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
@@ -1,4 +1,29 @@
package com.github.kaktushose.nplaybot.rank.commands;
+import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.Optional;
+import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.rank.model.UserInfo;
+import net.dv8tion.jda.api.entities.Member;
+
+@Interaction
public class RankInfoCommand {
+
+ @Inject
+ private Database database;
+ @Inject
+ private EmbedCache embedCache;
+
+ @SlashCommand(value = "rank", isGuildOnly = true, desc = "Zeigt die Kontoinformationen zu einem User an")
+ public void onCommand(CommandEvent event, @Optional Member member) {
+ var target = member == null ? event.getMember() : member;
+ UserInfo userInfo = database.getRankService().getUserInfo(target);
+
+ var embed = userInfo.nextRank().isPresent() ? "rankInfo" : "rankInfoMax";
+ event.reply(embedCache.getEmbed(embed).injectValues(userInfo.getEmbedValues(target)));
+ }
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
index 7577817..1ef364b 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
@@ -1,6 +1,27 @@
package com.github.kaktushose.nplaybot.rank.model;
+import net.dv8tion.jda.api.entities.Member;
+
+import java.util.HashMap;
+import java.util.Map;
import java.util.Optional;
-public record UserInfo(int xp, RankInfo currentRank, Optional nextRank, int messageCount, int xpGain) {
+public record UserInfo(int currentXp, RankInfo currentRank, Optional nextRank, int messageCount, int xpGain) {
+
+ public Map getEmbedValues(Member member) {
+ var result = new HashMap() {{
+ put("user", String.format("<@%d>", member.getIdLong()));
+ put("color", currentRank.color());
+ put("avatarUrl", member.getEffectiveAvatarUrl());
+ put("currentRank", String.format("<@&%d>", currentRank.roleId()));
+ put("currentXp", currentXp);
+ put("xpGain", xpGain);
+ put("messageCount", messageCount);
+ }};
+ nextRank.ifPresent(rank -> {
+ result.put("nextRank", String.format("<@&%d>", rank.roleId()));
+ result.put("missingXp", rank.xpBound() - currentXp);
+ });
+ return result;
+ }
}
From 4e8472c0b7fb5bf9a5abbf06ad9d516e63718a67 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Wed, 13 Dec 2023 19:31:20 +0100
Subject: [PATCH 21/66] implement member database binding
---
.../com/github/kaktushose/nplaybot/Bot.java | 11 +++++---
.../nplaybot/rank/JoinLeaveListener.java | 25 +++++++++++++++++
.../kaktushose/nplaybot/rank/RankService.java | 27 +++++++++++++++++++
.../migration/V1.0.0__setup_rank_system.sql | 12 ++++-----
4 files changed, 66 insertions(+), 9 deletions(-)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/JoinLeaveListener.java
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 5c1b560..49aff4a 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -3,6 +3,7 @@
import com.github.kaktushose.jda.commands.JDACommands;
import com.github.kaktushose.jda.commands.annotations.Produces;
import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.nplaybot.rank.JoinLeaveListener;
import com.github.kaktushose.nplaybot.rank.RankListener;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
@@ -17,6 +18,7 @@ public class Bot {
private final Database database;
private final EmbedCache embedCache;
+ @SuppressWarnings("DataFlowIssue")
private Bot(long guildId) throws InterruptedException, RuntimeException {
try {
database = new Database();
@@ -35,14 +37,17 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
.setActivity(Activity.customStatus("starting..."))
.setStatus(OnlineStatus.IDLE)
.addEventListeners(
- new RankListener(database.getRankService(), embedCache)
+ new RankListener(database.getRankService(), embedCache),
+ new JoinLeaveListener(database.getRankService())
)
.build().awaitReady();
- jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.0"));
- jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
+ database.getRankService().indexMembers(jda.getGuildById(guildId));
+ jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
jdaCommands.getDependencyInjector().registerProvider(this);
+
+ jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.0"));
}
public static Bot start(long guildId) throws InterruptedException {
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/JoinLeaveListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/JoinLeaveListener.java
new file mode 100644
index 0000000..c2aeaec
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/JoinLeaveListener.java
@@ -0,0 +1,25 @@
+package com.github.kaktushose.nplaybot.rank;
+
+import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
+import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
+import net.dv8tion.jda.api.hooks.ListenerAdapter;
+import org.jetbrains.annotations.NotNull;
+
+public class JoinLeaveListener extends ListenerAdapter {
+
+ private final RankService rankService;
+
+ public JoinLeaveListener(RankService rankService) {
+ this.rankService = rankService;
+ }
+
+ @Override
+ public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) {
+ rankService.addUser(event.getUser());
+ }
+
+ @Override
+ public void onGuildMemberRemove(@NotNull GuildMemberRemoveEvent event) {
+ rankService.removeUser(event.getUser());
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index ed39ccc..224374a 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -3,12 +3,15 @@
import com.github.kaktushose.nplaybot.rank.model.RankInfo;
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
+import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import javax.sql.DataSource;
import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -23,6 +26,30 @@ public RankService(DataSource dataSource) {
this.dataSource = dataSource;
}
+ public void addUser(User user) {
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("INSERT INTO users VALUES(?) ON CONFLICT DO NOTHING");
+ statement.setLong(1, user.getIdLong());
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void removeUser(User user) {
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("DELETE FROM users WHERE user_id = ?");
+ statement.setLong(1, user.getIdLong());
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void indexMembers(Guild guild) {
+ guild.loadMembers(member -> addUser(member.getUser()));
+ }
+
private Optional getRankInfo(int rankId) {
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
diff --git a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
index 4716697..ea2124e 100644
--- a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
+++ b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
@@ -22,12 +22,12 @@ CREATE TABLE ranks (
CREATE TABLE users (
user_id BIGINT NOT NULL PRIMARY KEY,
- daily_message BOOLEAN NOT NULL,
- xp INT NOT NULL,
- rank_id INT NOT NULL REFERENCES ranks(rank_id),
- last_valid_message BIGINT NOT NULL,
- message_count BIGINT NOT NULL,
- start_xp INT NOT NULL
+ daily_message BOOLEAN NOT NULL DEFAULT FALSE,
+ xp INT NOT NULL DEFAULT 0,
+ rank_id INT NOT NULL REFERENCES ranks(rank_id) DEFAULT 1,
+ last_valid_message BIGINT NOT NULL DEFAULT 0,
+ message_count BIGINT NOT NULL DEFAULT 0,
+ start_xp INT NOT NULL DEFAULT 0
);
CREATE TABLE xp_chances (
From 6f5db1ced5fcd829a6bd37ed1b6828623935de00 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Wed, 13 Dec 2023 19:51:15 +0100
Subject: [PATCH 22/66] bump jda-commands version and mark producers as
skipIndex
---
pom.xml | 2 +-
src/main/java/com/github/kaktushose/nplaybot/Bot.java | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pom.xml b/pom.xml
index 6f263cc..88f2e39 100644
--- a/pom.xml
+++ b/pom.xml
@@ -70,7 +70,7 @@
com.github.Kaktushose
jda-commands
- 4.0.0-beta.1
+ 4f948157b4
com.zaxxer
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 49aff4a..5cd3960 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -60,12 +60,12 @@ public void shutdown() {
database.closeDataSource();
}
- @Produces
+ @Produces(skipIndexing = true)
public Database getDatabase() {
return database;
}
- @Produces
+ @Produces(skipIndexing = true)
public EmbedCache getEmbedCache() {
return embedCache;
}
From 390e931aed6080cf3a1889ad9508cf97057b45b4 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Thu, 14 Dec 2023 18:54:50 +0100
Subject: [PATCH 23/66] compile with parameters flag
---
pom.xml | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/pom.xml b/pom.xml
index 88f2e39..cc5bb6c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,6 +21,13 @@
org.apache.maven.plugins
maven-compiler-plugin
3.10.1
+
+
+ -parameters
+
+
+ 16
+
org.apache.maven.plugins
From 1517077b0113974071dd02b56836126a88d46db0 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Thu, 14 Dec 2023 18:55:28 +0100
Subject: [PATCH 24/66] make xp amount non primary key
---
src/main/resources/db/migration/V1.0.0__setup_rank_system.sql | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
index ea2124e..8c6f63f 100644
--- a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
+++ b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
@@ -31,7 +31,8 @@ CREATE TABLE users (
);
CREATE TABLE xp_chances (
- amount INT NOT NULL PRIMARY KEY,
+ chance_id INT NOT NULL PRIMARY KEY,
+ amount INT NOT NULL,
chance INT NOT NULL
);
From f803b7c76dea809b45746e103acdae86cad5d0a8 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Thu, 14 Dec 2023 18:55:40 +0100
Subject: [PATCH 25/66] add reload embeds command
---
.../internal/MaintenanceCommands.java | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/internal/MaintenanceCommands.java
diff --git a/src/main/java/com/github/kaktushose/nplaybot/internal/MaintenanceCommands.java b/src/main/java/com/github/kaktushose/nplaybot/internal/MaintenanceCommands.java
new file mode 100644
index 0000000..25fd2dd
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/internal/MaintenanceCommands.java
@@ -0,0 +1,22 @@
+package com.github.kaktushose.nplaybot.internal;
+
+import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import net.dv8tion.jda.api.Permission;
+
+@Interaction
+public class MaintenanceCommands {
+
+ @Inject
+ private EmbedCache embedCache;
+
+ @SlashCommand(value = "reload embeds", desc = "Aktualisiert den EmbedCache", enabledFor = Permission.BAN_MEMBERS)
+ public void onReload(CommandEvent event) {
+ embedCache.loadEmbeds();
+ event.reply(embedCache.getEmbed("embedCacheReload"));
+ }
+
+}
From 296805ad1ed9be62cf0cc23cba1022639b155770 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Thu, 14 Dec 2023 20:18:02 +0100
Subject: [PATCH 26/66] add commands for altering user xp
---
embeds.json | 10 +++
.../com/github/kaktushose/nplaybot/Bot.java | 2 +-
.../nplaybot/rank/RankListener.java | 33 ++++------
.../kaktushose/nplaybot/rank/RankService.java | 64 ++++++++++++++++---
.../rank/commands/ModifyXpCommands.java | 62 ++++++++++++++++++
.../rank/commands/SetRankCommand.java | 4 --
.../nplaybot/rank/model/XpChangeResult.java | 4 +-
.../nplaybot/settings/SettingsService.java | 21 ++++++
8 files changed, 162 insertions(+), 38 deletions(-)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java
delete mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/commands/SetRankCommand.java
diff --git a/embeds.json b/embeds.json
index f579b22..3822212 100644
--- a/embeds.json
+++ b/embeds.json
@@ -89,5 +89,15 @@
"title": "Erfolg",
"description": "Der EmbedCache wurde aktualisiert",
"color": "#67c94f"
+ },
+ "setXpResult" : {
+ "title": "Erfolg",
+ "description": "Die XP von {user} wurden auf {xp} XP gesetzt",
+ "color": "#67c94f"
+ },
+ "addXpResult" : {
+ "title": "Erfolg",
+ "description": "{user} wurden {xp} XP hinzugefügt",
+ "color": "#67c94f"
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 5cd3960..ce6fc31 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -37,7 +37,7 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
.setActivity(Activity.customStatus("starting..."))
.setStatus(OnlineStatus.IDLE)
.addEventListeners(
- new RankListener(database.getRankService(), embedCache),
+ new RankListener(database, embedCache),
new JoinLeaveListener(database.getRankService())
)
.build().awaitReady();
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
index 90c0c35..a1d1f95 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
@@ -1,23 +1,22 @@
package com.github.kaktushose.nplaybot.rank;
import com.github.kaktushose.jda.commands.data.EmbedCache;
-import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
-import net.dv8tion.jda.api.entities.Guild;
-import net.dv8tion.jda.api.entities.Member;
+import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.settings.SettingsService;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
+import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import org.jetbrains.annotations.NotNull;
-import java.util.List;
-
-@SuppressWarnings("DataFlowIssue")
public class RankListener extends ListenerAdapter {
private final RankService rankService;
+ private final SettingsService settingsService;
private final EmbedCache embedCache;
- public RankListener(RankService rankService, EmbedCache embedCache) {
- this.rankService = rankService;
+ public RankListener(Database database, EmbedCache embedCache) {
+ this.rankService = database.getRankService();
+ this.settingsService = database.getSettingsService();
this.embedCache = embedCache;
}
@@ -38,23 +37,15 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
rankService.updateValidMessage(author);
var result = rankService.addRandomXp(author);
- updateRankRoles(event.getMember(), event.getGuild(), result);
+ rankService.updateRankRoles(event.getMember(), event.getGuild(), result);
if (!result.rankChanged()) {
return;
}
var embed = result.nextRank().isPresent() ? "rankIncrease" : "rankIncreaseMax";
- event.getChannel().sendMessage(
- embedCache.getEmbed(embed).injectValues(result.getEmbedValues(author)).toMessageCreateData()
- ).queue();
- }
-
- private void updateRankRoles(Member member, Guild guild, XpChangeResult result) {
- var validRole = guild.getRoleById(result.currentRank().roleId());
- var invalidRoles = rankService.getRankRoleIds().stream()
- .map(guild::getRoleById)
- .filter(it -> it != validRole)
- .toList();
- guild.modifyMemberRoles(member, List.of(validRole), invalidRoles).queue();
+ var messageData = new MessageCreateBuilder().addContent(author.getAsMention())
+ .addEmbeds(embedCache.getEmbed(embed).injectValues(result.getEmbedValues(author)).toMessageEmbed())
+ .build();
+ settingsService.getBotChannel(event.getGuild()).sendMessage(messageData).queue();
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 224374a..1fd2df8 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -6,12 +6,10 @@
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
-import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.UserSnowflake;
import javax.sql.DataSource;
import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -26,7 +24,7 @@ public RankService(DataSource dataSource) {
this.dataSource = dataSource;
}
- public void addUser(User user) {
+ public void addUser(UserSnowflake user) {
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("INSERT INTO users VALUES(?) ON CONFLICT DO NOTHING");
statement.setLong(1, user.getIdLong());
@@ -36,7 +34,7 @@ public void addUser(User user) {
}
}
- public void removeUser(User user) {
+ public void removeUser(UserSnowflake user) {
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("DELETE FROM users WHERE user_id = ?");
statement.setLong(1, user.getIdLong());
@@ -75,7 +73,7 @@ private Optional getRankInfo(int rankId) {
}
}
- public UserInfo getUserInfo(Member member) {
+ public UserInfo getUserInfo(UserSnowflake user) {
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
SELECT xp, rank_id, message_count, start_xp
@@ -83,7 +81,7 @@ public UserInfo getUserInfo(Member member) {
WHERE user_id = ?
"""
);
- statement.setLong(1, member.getIdLong());
+ statement.setLong(1, user.getIdLong());
var result = statement.executeQuery();
result.next();
@@ -139,7 +137,7 @@ public boolean isValidMessage(Message message) {
}
}
- public void updateValidMessage(User user) {
+ public void updateValidMessage(UserSnowflake user) {
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
UPDATE users
@@ -156,7 +154,7 @@ public void updateValidMessage(User user) {
}
}
- public XpChangeResult addRandomXp(User user) {
+ public XpChangeResult addRandomXp(UserSnowflake user) {
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("SELECT * FROM add_random_xp(?)");
statement.setLong(1, user.getIdLong());
@@ -174,6 +172,53 @@ public XpChangeResult addRandomXp(User user) {
}
}
+ public XpChangeResult addXp(UserSnowflake user, int amount) {
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("SELECT * FROM add_xp(?, ?)");
+ statement.setLong(1, user.getIdLong());
+ statement.setInt(2, amount);
+
+ var result = statement.executeQuery();
+ result.next();
+ return new XpChangeResult(
+ result.getBoolean("rank_changed"),
+ getRankInfo(result.getInt("current_rank")).orElseThrow(),
+ getRankInfo(result.getInt("next_rank")),
+ result.getInt("current_xp")
+ );
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public XpChangeResult setXp(UserSnowflake user, int value) {
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("SELECT * FROM set_xp(?, ?)");
+ statement.setLong(1, user.getIdLong());
+ statement.setInt(2, value);
+
+ var result = statement.executeQuery();
+ result.next();
+ return new XpChangeResult(
+ result.getBoolean("rank_changed"),
+ getRankInfo(result.getInt("current_rank")).orElseThrow(),
+ getRankInfo(result.getInt("next_rank")),
+ value
+ );
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void updateRankRoles(Member member, Guild guild, XpChangeResult result) {
+ var validRole = guild.getRoleById(result.currentRank().roleId());
+ var invalidRoles = getRankRoleIds().stream()
+ .map(guild::getRoleById)
+ .filter(it -> it != validRole)
+ .toList();
+ guild.modifyMemberRoles(member, List.of(validRole), invalidRoles).queue();
+ }
+
public List getRankRoleIds() {
try (Connection connection = dataSource.getConnection()) {
var result = connection.prepareStatement("SELECT role_id FROM ranks").executeQuery();
@@ -186,5 +231,4 @@ public List getRankRoleIds() {
throw new RuntimeException(e);
}
}
-
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java
new file mode 100644
index 0000000..705d5ea
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java
@@ -0,0 +1,62 @@
+package com.github.kaktushose.nplaybot.rank.commands;
+
+import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.constraints.Max;
+import com.github.kaktushose.jda.commands.annotations.constraints.Min;
+import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
+
+@Interaction(ephemeral = true)
+public class ModifyXpCommands {
+
+ @Inject
+ private Database database;
+ @Inject
+ private EmbedCache embedCache;
+
+ @SlashCommand(value = "add xp", desc = "Fügt einem User XP hinzu", enabledFor = Permission.BAN_MEMBERS, isGuildOnly = true)
+ public void onAddXp(CommandEvent event, Member target, @Min(1) @Max(Integer.MAX_VALUE) int amount) {
+ var result = database.getRankService().addXp(target, amount);
+
+ event.reply(embedCache.getEmbed("addXpResult")
+ .injectValue("user", target.getAsMention())
+ .injectValue("xp", amount)
+ );
+
+ checkRankUpdate(result, target, event.getGuild());
+ }
+
+ @SlashCommand(value = "set xp", desc = "Setzt die XP von einem User auf den angegebenen Wert", enabledFor = Permission.BAN_MEMBERS, isGuildOnly = true)
+ public void onSetXp(CommandEvent event, Member target, @Min(0) @Max(Integer.MAX_VALUE) int value) {
+ var result = database.getRankService().setXp(target, value);
+
+ event.reply(embedCache.getEmbed("setXpResult")
+ .injectValue("user", target.getAsMention())
+ .injectValue("xp", value)
+ );
+
+ checkRankUpdate(result, target, event.getGuild());
+ }
+
+ private void checkRankUpdate(XpChangeResult result, Member member, Guild guild) {
+ database.getRankService().updateRankRoles(member, guild, result);
+
+ if (!result.rankChanged()) {
+ return;
+ }
+
+ var embed = result.nextRank().isPresent() ? "rankIncrease" : "rankIncreaseMax";
+ var messageData = new MessageCreateBuilder().addContent(member.getAsMention())
+ .addEmbeds(embedCache.getEmbed(embed).injectValues(result.getEmbedValues(member.getUser())).toMessageEmbed())
+ .build();
+ database.getSettingsService().getBotChannel(guild).sendMessage(messageData).queue();
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SetRankCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SetRankCommand.java
deleted file mode 100644
index 4934346..0000000
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SetRankCommand.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.github.kaktushose.nplaybot.rank.commands;
-
-public class SetRankCommand {
-}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java
index 47bbafa..0ad257e 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java
@@ -1,6 +1,6 @@
package com.github.kaktushose.nplaybot.rank.model;
-import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.UserSnowflake;
import java.util.HashMap;
import java.util.Map;
@@ -8,7 +8,7 @@
public record XpChangeResult(boolean rankChanged, RankInfo currentRank, Optional nextRank, int currentXp) {
- public Map getEmbedValues(User user) {
+ public Map getEmbedValues(UserSnowflake user) {
var result = new HashMap() {{
put("user", String.format("<@%d>", user.getIdLong()));
put("color", currentRank.color());
diff --git a/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java b/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java
index f8a19c3..72debcf 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java
@@ -1,5 +1,8 @@
package com.github.kaktushose.nplaybot.settings;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@@ -29,4 +32,22 @@ public String getBotToken(long guildId) {
throw new RuntimeException(e);
}
}
+
+ public TextChannel getBotChannel(Guild guild) {
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT bot_channel_id
+ FROM guild_settings
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, guild.getIdLong());
+
+ var result = statement.executeQuery();
+ result.next();
+ return guild.getTextChannelById(result.getLong(1));
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
From 467103bee9d692c0f5a6bb8db16cd6f771d9c6f3 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Fri, 15 Dec 2023 20:37:28 +0100
Subject: [PATCH 27/66] implement leaderboard command
---
embeds.json | 5 +
pom.xml | 2 +-
.../com/github/kaktushose/nplaybot/Bot.java | 2 +
.../kaktushose/nplaybot/rank/RankService.java | 33 +++++++
.../rank/leaderboard/LeaderboardCommand.java | 95 +++++++++++++++++++
.../rank/leaderboard/LeaderboardPage.java | 35 +++++++
6 files changed, 171 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java
diff --git a/embeds.json b/embeds.json
index 3822212..aec9acf 100644
--- a/embeds.json
+++ b/embeds.json
@@ -99,5 +99,10 @@
"title": "Erfolg",
"description": "{user} wurden {xp} XP hinzugefügt",
"color": "#67c94f"
+ },
+ "leaderboard": {
+ "title": "Leaderboard",
+ "description": "{leaderboard}",
+ "color": "#67c94f"
}
}
diff --git a/pom.xml b/pom.xml
index cc5bb6c..6835783 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,7 +77,7 @@
com.github.Kaktushose
jda-commands
- 4f948157b4
+ 3d823b1173
com.zaxxer
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index ce6fc31..aa0f957 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -10,6 +10,7 @@
import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.requests.GatewayIntent;
+import net.dv8tion.jda.api.utils.MemberCachePolicy;
public class Bot {
@@ -34,6 +35,7 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
GatewayIntent.GUILD_PRESENCES,
GatewayIntent.MESSAGE_CONTENT
)
+ .setMemberCachePolicy(MemberCachePolicy.ALL)
.setActivity(Activity.customStatus("starting..."))
.setStatus(OnlineStatus.IDLE)
.addEventListeners(
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 1fd2df8..4c2718e 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -1,5 +1,6 @@
package com.github.kaktushose.nplaybot.rank;
+import com.github.kaktushose.nplaybot.rank.leaderboard.LeaderboardPage;
import com.github.kaktushose.nplaybot.rank.model.RankInfo;
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
@@ -231,4 +232,36 @@ public List getRankRoleIds() {
throw new RuntimeException(e);
}
}
+
+ public List getLeaderboard() {
+ try (Connection connection = dataSource.getConnection()) {
+ var result = connection.prepareStatement("""
+ SELECT users.xp, users.user_id, ranks.role_id
+ FROM users JOIN ranks ON ranks.rank_id = users.rank_id
+ ORDER BY xp DESC;
+ """
+ ).executeQuery();
+
+ List pages = new ArrayList<>();
+ List rows = new ArrayList<>();
+ int rowCount = 1;
+ while (result.next()) {
+ if (rowCount == 11) {
+ pages.add(new LeaderboardPage(rows));
+ rows = new ArrayList<>();
+ rowCount = 1;
+ }
+ rows.add(new LeaderboardPage.LeaderboardRow(
+ result.getInt("xp"),
+ result.getLong("user_id"),
+ result.getLong("role_id")
+ ));
+ rowCount++;
+ }
+ return pages;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
new file mode 100644
index 0000000..cf0f407
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
@@ -0,0 +1,95 @@
+package com.github.kaktushose.nplaybot.rank.leaderboard;
+
+import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.interactions.Button;
+import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.jda.commands.dispatching.interactions.components.ComponentEvent;
+import com.github.kaktushose.jda.commands.dispatching.reply.Replyable;
+import com.github.kaktushose.jda.commands.dispatching.reply.components.Buttons;
+import com.github.kaktushose.jda.commands.dispatching.reply.components.Component;
+import com.github.kaktushose.nplaybot.Database;
+import net.dv8tion.jda.api.entities.Guild;
+
+import java.util.List;
+
+
+@Interaction
+public class LeaderboardCommand {
+
+ @Inject
+ private Database database;
+ @Inject
+ private EmbedCache embedCache;
+
+ private final int minIndex = 1;
+ private int index = 1;
+ private int maxIndex;
+ private List leaderboard;
+ private Guild guild;
+
+ @SlashCommand(value = "leaderboard", desc = "Zeigt eine Rangliste der Benutzer mit den meisten XP", isGuildOnly = true)
+ public void onCommand(CommandEvent event) {
+ guild = event.getGuild();
+ leaderboard = database.getRankService().getLeaderboard();
+ maxIndex = leaderboard.size();
+ reply(event);
+ }
+
+ @Button(emoji = "⏪")
+ public void onStart(ComponentEvent event) {
+ index = 1;
+ reply(event);
+ }
+
+ @Button(emoji = "◀️")
+ public void onBackward(ComponentEvent event) {
+ if (index > minIndex) {
+ index--;
+ }
+ reply(event);
+ }
+
+ @Button(emoji = "▶️")
+ public void onForward(ComponentEvent event) {
+ if (index < maxIndex) {
+ index++;
+ }
+ reply(event);
+ }
+
+ @Button(emoji = "⏩")
+ public void onEnd(ComponentEvent event) {
+ index = maxIndex;
+ reply(event);
+ }
+
+ private void reply(Replyable event) {
+ event.with(getButtons()).reply(
+ embedCache.getEmbed("leaderboard").injectValue("leaderboard", leaderboard.get(index - 1).getPage(guild))
+ .toEmbedBuilder()
+ .setFooter(String.format("Seite (%d/%d)", index, maxIndex))
+ );
+ }
+
+ private Component[] getButtons() {
+ if (index == minIndex) {
+ return List.of(
+ Buttons.disabled("onStart", "onBackward"),
+ Buttons.enabled("onForward", "onEnd")
+ ).toArray(new Component[0]);
+ }
+ if (index == maxIndex) {
+ return List.of(
+ Buttons.enabled("onStart", "onBackward"),
+ Buttons.disabled("onForward", "onEnd")
+ ).toArray(new Component[0]);
+ }
+ return List.of(
+ Buttons.enabled("onStart", "onBackward"),
+ Buttons.enabled("onForward", "onEnd")
+ ).toArray(new Component[0]);
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java
new file mode 100644
index 0000000..0c64b3b
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java
@@ -0,0 +1,35 @@
+package com.github.kaktushose.nplaybot.rank.leaderboard;
+
+import net.dv8tion.jda.api.entities.Guild;
+
+import java.util.List;
+import java.util.Optional;
+
+public record LeaderboardPage(List rows) {
+ public record LeaderboardRow(int xp, long userId, long roleId) {
+ }
+
+ public String getPage(Guild guild) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < rows.size(); i++) {
+ var row = rows.get(i);
+ appendRow(builder, i + 1, resolveName(guild, row.userId), row.xp, String.format("<@&%d>", row.roleId));
+ }
+ return builder.toString();
+ }
+
+ private void appendRow(StringBuilder builder, int index, String username, int xp, String role) {
+ builder.append(String.format("%d. %s %d XP (%s)\n", index, username, xp, role));
+ }
+
+ private String resolveName(Guild guild, long userId) {
+ var member = Optional.ofNullable(guild.getMemberById(userId));
+ if (member.isPresent()) {
+ return member.get().getEffectiveName();
+ }
+ // retrieve member thus it gets loaded to cache
+ guild.retrieveMemberById(userId).queue();
+ return String.format("<@%d>", userId);
+ }
+
+}
From b946651c16c29f150f9cfb85cc885490bdb73e94 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Sat, 30 Dec 2023 22:04:18 +0100
Subject: [PATCH 28/66] implement task scheduler
---
.../kaktushose/nplaybot/Bootstrapper.java | 2 +
.../com/github/kaktushose/nplaybot/Bot.java | 12 +++
.../github/kaktushose/nplaybot/Database.java | 1 -
.../nplaybot/scheduler/ScheduledTask.java | 32 +++++++-
.../nplaybot/scheduler/TaskScheduler.java | 75 ++++++++++++++++++-
5 files changed, 116 insertions(+), 6 deletions(-)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java b/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
index 9003757..6262b7b 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bootstrapper.java
@@ -9,6 +9,8 @@ public class Bootstrapper {
private final static Logger log = LoggerFactory.getLogger(Bootstrapper.class);
public static void main(String[] args) {
+ Thread.currentThread().setName("Bot");
+
long startTime = System.currentTimeMillis();
try {
log.info("Starting NPLAY-Bot...");
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index aa0f957..2da7e35 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -5,6 +5,7 @@
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.nplaybot.rank.JoinLeaveListener;
import com.github.kaktushose.nplaybot.rank.RankListener;
+import com.github.kaktushose.nplaybot.scheduler.TaskScheduler;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.OnlineStatus;
@@ -12,12 +13,15 @@
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.utils.MemberCachePolicy;
+import java.util.concurrent.TimeUnit;
+
public class Bot {
private final JDA jda;
private final JDACommands jdaCommands;
private final Database database;
private final EmbedCache embedCache;
+ private final TaskScheduler taskScheduler;
@SuppressWarnings("DataFlowIssue")
private Bot(long guildId) throws InterruptedException, RuntimeException {
@@ -49,6 +53,8 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
jdaCommands.getDependencyInjector().registerProvider(this);
+ taskScheduler = new TaskScheduler(this);
+
jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.customStatus("Version 3.0.0"));
}
@@ -57,8 +63,14 @@ public static Bot start(long guildId) throws InterruptedException {
}
public void shutdown() {
+ taskScheduler.shutdown();
jdaCommands.shutdown();
jda.shutdown();
+ try {
+ jda.awaitShutdown(1000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
database.closeDataSource();
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Database.java b/src/main/java/com/github/kaktushose/nplaybot/Database.java
index 437987c..0ff33bb 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Database.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Database.java
@@ -14,7 +14,6 @@ public class Database {
public Database() {
var config = new HikariConfig();
- System.out.println(System.getenv("POSTGRES_URL"));
config.setJdbcUrl(System.getenv("POSTGRES_URL"));
config.setUsername(System.getenv("POSTGRES_USER"));
config.setPassword(System.getenv("POSTGRES_PASSWORD"));
diff --git a/src/main/java/com/github/kaktushose/nplaybot/scheduler/ScheduledTask.java b/src/main/java/com/github/kaktushose/nplaybot/scheduler/ScheduledTask.java
index 6e943c0..046b8b1 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/scheduler/ScheduledTask.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/scheduler/ScheduledTask.java
@@ -1,4 +1,28 @@
-package com.github.kaktushose.nplaybot.scheduler;
-
-public @interface ScheduledTask {
-}
+package com.github.kaktushose.nplaybot.scheduler;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.concurrent.TimeUnit;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ScheduledTask {
+
+ boolean repeat() default true;
+
+ /**
+ * This will override {@link #initialDelay()}!
+ *
+ * @return whether this scheduled task should start at midnight
+ */
+ boolean startAtMidnight() default false;
+
+ long initialDelay() default 0;
+
+ long period();
+
+ TimeUnit unit();
+
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java b/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
index 4718ffc..6b0d1ff 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
@@ -1,5 +1,78 @@
package com.github.kaktushose.nplaybot.scheduler;
+import com.github.kaktushose.nplaybot.Bot;
+import org.reflections.Reflections;
+import org.reflections.scanners.Scanners;
+import org.reflections.util.ClasspathHelper;
+import org.reflections.util.ConfigurationBuilder;
+import org.reflections.util.FilterBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Calendar;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
public class TaskScheduler {
-// TODO add via annotations
+
+ private static final Logger log = LoggerFactory.getLogger(TaskScheduler.class);
+ private static final String BASE_PACKAGE = "com.github.kaktushose.nplaybot";
+ private final Reflections reflections;
+ private final ScheduledExecutorService executor;
+ private final Bot bot;
+
+ public TaskScheduler(Bot bot) {
+ this.bot = bot;
+ executor = Executors.newScheduledThreadPool(4, runnable -> new Thread(runnable, "TaskScheduler"));
+ ConfigurationBuilder config = new ConfigurationBuilder()
+ .setScanners(Scanners.SubTypes, Scanners.MethodsAnnotated)
+ .setUrls(ClasspathHelper.forClass(Bot.class))
+ .filterInputsBy(new FilterBuilder().includePackage(BASE_PACKAGE));
+ reflections = new Reflections(config);
+
+ indexTasks();
+ }
+
+ public void shutdown() {
+ executor.shutdown();
+ try {
+ executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void indexTasks() {
+ var methods = reflections.getMethodsAnnotatedWith(ScheduledTask.class);
+
+ for (var method : methods) {
+ var scheduledTask = method.getAnnotation(ScheduledTask.class);
+
+ var delay = scheduledTask.initialDelay();
+ if (scheduledTask.startAtMidnight()) {
+ delay = TimeUnit.HOURS.toMinutes(24)
+ - (TimeUnit.HOURS.toMinutes(Calendar.getInstance().get(Calendar.HOUR_OF_DAY))
+ + Calendar.getInstance().get(Calendar.MINUTE));
+ }
+
+ if (scheduledTask.repeat()) {
+ executor.scheduleAtFixedRate(execute(method), delay, scheduledTask.period(), scheduledTask.unit());
+ } else {
+ executor.scheduleAtFixedRate(execute(method), delay, scheduledTask.period(), scheduledTask.unit());
+ }
+ }
+ }
+
+ private Runnable execute(Method method) {
+ return () -> {
+ try {
+ method.invoke(method.getDeclaringClass().getConstructors()[0].newInstance(), bot);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ log.error("Exception in scheduled task!", e);
+ }
+ };
+ }
}
From f905c95ce4f39c11351913a28229ad40f606f655 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Sun, 31 Dec 2023 14:38:57 +0100
Subject: [PATCH 29/66] update xp statistics
---
.../kaktushose/nplaybot/rank/RankService.java | 8 ++++++++
.../kaktushose/nplaybot/rank/StatisticsTask.java | 14 ++++++++++++++
2 files changed, 22 insertions(+)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/StatisticsTask.java
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 4c2718e..61264a6 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -264,4 +264,12 @@ public List getLeaderboard() {
}
}
+ public void resetDailyStatistics() {
+ try (Connection connection = dataSource.getConnection()) {
+ connection.prepareStatement("UPDATE users SET start_xp = xp").execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/StatisticsTask.java b/src/main/java/com/github/kaktushose/nplaybot/rank/StatisticsTask.java
new file mode 100644
index 0000000..ae9f921
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/StatisticsTask.java
@@ -0,0 +1,14 @@
+package com.github.kaktushose.nplaybot.rank;
+
+import com.github.kaktushose.nplaybot.Bot;
+import com.github.kaktushose.nplaybot.scheduler.ScheduledTask;
+
+import java.util.concurrent.TimeUnit;
+
+public class StatisticsTask {
+
+ @ScheduledTask(period = 24, unit = TimeUnit.HOURS, startAtMidnight = true)
+ public void accept(Bot bot) {
+ bot.getDatabase().getRankService().resetDailyStatistics();
+ }
+}
From a63b6b6b252a48fe6da1256e4282a90693ec0e4e Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Sun, 31 Dec 2023 14:43:51 +0100
Subject: [PATCH 30/66] update message count on valid message
---
.../java/com/github/kaktushose/nplaybot/rank/RankService.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 61264a6..1bb9fed 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -142,7 +142,8 @@ public void updateValidMessage(UserSnowflake user) {
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
UPDATE users
- SET last_valid_message = ?
+ SET last_valid_message = ?,
+ message_count = message_count + 1
WHERE user_id = ?
"""
);
From aa0e5b12aa3b39f2b60a380cf8d378a31b6c68ac Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Sun, 31 Dec 2023 15:43:56 +0100
Subject: [PATCH 31/66] implement rank statistics
---
.../nplaybot/rank/RankListener.java | 3 +
.../kaktushose/nplaybot/rank/RankService.java | 8 +++
.../migration/V1.0.0__setup_rank_system.sql | 64 +++++++++++++++++--
3 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
index a1d1f95..8988a33 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
@@ -31,6 +31,9 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
if (!event.isFromGuild()) {
return;
}
+
+ rankService.increaseTotalMessageCount();
+
if (!rankService.isValidMessage(message)) {
return;
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 1bb9fed..6cbe933 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -273,4 +273,12 @@ public void resetDailyStatistics() {
}
}
+ public void increaseTotalMessageCount() {
+ try (Connection connection = dataSource.getConnection()) {
+ connection.prepareStatement("SELECT * FROM increase_total_message_count()").execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
}
diff --git a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
index 8c6f63f..d137593 100644
--- a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
+++ b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
@@ -37,11 +37,11 @@ CREATE TABLE xp_chances (
);
CREATE TABLE rank_statistics (
- timestamp BIGINT NOT NULL PRIMARY KEY,
- total_message_count INT NOT NULL,
- valid_message_count INT NOT NULL,
- total_xp_gain INT NOT NULL,
- total_rank_ups INT NOT NULL
+ date date NOT NULL PRIMARY KEY,
+ total_message_count INT NOT NULL DEFAULT 0,
+ valid_message_count INT NOT NULL DEFAULT 0,
+ total_xp_gain INT NOT NULL DEFAULT 0,
+ total_rank_ups INT NOT NULL DEFAULT 0
);
CREATE FUNCTION update_rank_trigger()
@@ -124,3 +124,57 @@ BEGIN
RETURN NEXT;
END;
$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION increase_valid_message_statistics()
+RETURNS TRIGGER AS
+$$
+BEGIN
+ INSERT INTO rank_statistics (DATE, valid_message_count) VALUES (CURRENT_DATE, NEW.message_count - OLD.message_count)
+ ON CONFLICT (DATE) DO UPDATE SET valid_message_count = rank_statistics.valid_message_count + (NEW.message_count - OLD.message_count);
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE TRIGGER valid_message_trigger
+BEFORE UPDATE OF message_count ON users
+FOR EACH ROW
+EXECUTE FUNCTION increase_valid_message_statistics();
+
+CREATE FUNCTION increase_total_xp_gain()
+RETURNS TRIGGER AS
+$$
+BEGIN
+ INSERT INTO rank_statistics (DATE, total_xp_gain) VALUES (CURRENT_DATE, NEW.xp - OLD.xp)
+ ON CONFLICT (DATE) DO UPDATE SET total_xp_gain = rank_statistics.total_xp_gain + (NEW.xp - OLD.xp);
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE TRIGGER xp_gain_trigger
+BEFORE UPDATE OF xp ON users
+FOR EACH ROW
+EXECUTE FUNCTION increase_total_xp_gain();
+
+CREATE FUNCTION increase_total_rank_ups()
+RETURNS TRIGGER AS
+$$
+BEGIN
+ INSERT INTO rank_statistics (DATE, total_rank_ups) VALUES (CURRENT_DATE, NEW.rank_id - OLD.rank_id)
+ ON CONFLICT (DATE) DO UPDATE SET total_rank_ups = rank_statistics.total_rank_ups + (NEW.rank_id - OLD.rank_id);
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE TRIGGER rank_up_trigger
+AFTER UPDATE OF rank_id ON users
+FOR EACH ROW
+EXECUTE FUNCTION increase_total_rank_ups();
+
+CREATE FUNCTION increase_total_message_count()
+RETURNS VOID AS
+$$
+BEGIN
+ INSERT INTO rank_statistics (DATE, total_message_count) VALUES (CURRENT_DATE, 1)
+ ON CONFLICT (DATE) DO UPDATE SET total_message_count = rank_statistics.total_message_count + 1;
+END;
+$$ LANGUAGE plpgsql;
From 2b26edf884b394526e8a8b263561ee70c2724e93 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Thu, 4 Jan 2024 15:48:17 +0100
Subject: [PATCH 32/66] add more logging
---
.../github/kaktushose/nplaybot/Database.java | 4 +-
.../nplaybot/rank/JoinLeaveListener.java | 2 +-
.../nplaybot/rank/RankListener.java | 12 ++++++
.../kaktushose/nplaybot/rank/RankService.java | 38 +++++++++++++++++--
.../rank/commands/ModifyXpCommands.java | 7 ++++
.../rank/leaderboard/LeaderboardCommand.java | 13 +++++++
.../nplaybot/rank/model/XpChangeResult.java | 10 +++++
.../nplaybot/scheduler/TaskScheduler.java | 8 ++--
8 files changed, 83 insertions(+), 11 deletions(-)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Database.java b/src/main/java/com/github/kaktushose/nplaybot/Database.java
index 0ff33bb..26333d3 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Database.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Database.java
@@ -26,9 +26,7 @@ public Database() {
}
public void closeDataSource() {
- if (dataSource != null) {
- dataSource.close();
- }
+ dataSource.close();
}
public SettingsService getSettingsService() {
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/JoinLeaveListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/JoinLeaveListener.java
index c2aeaec..548227f 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/JoinLeaveListener.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/JoinLeaveListener.java
@@ -15,7 +15,7 @@ public JoinLeaveListener(RankService rankService) {
@Override
public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) {
- rankService.addUser(event.getUser());
+ rankService.createUser(event.getUser());
}
@Override
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
index 8988a33..83ed176 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
@@ -7,9 +7,12 @@
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class RankListener extends ListenerAdapter {
+ private static final Logger log = LoggerFactory.getLogger(RankListener.class);
private final RankService rankService;
private final SettingsService settingsService;
private final EmbedCache embedCache;
@@ -22,29 +25,38 @@ public RankListener(Database database, EmbedCache embedCache) {
@Override
public void onMessageReceived(@NotNull MessageReceivedEvent event) {
+ log.debug("Received message event");
var author = event.getAuthor();
var message = event.getMessage();
if (author.isBot()) {
+ log.trace("Author is bot");
return;
}
if (!event.isFromGuild()) {
+ log.trace("Event is not from guild");
return;
}
rankService.increaseTotalMessageCount();
if (!rankService.isValidMessage(message)) {
+ log.trace("Message doesn't meet rank criteria");
return;
}
rankService.updateValidMessage(author);
var result = rankService.addRandomXp(author);
+
+ log.debug("Checking for rank up: {}", author);
rankService.updateRankRoles(event.getMember(), event.getGuild(), result);
if (!result.rankChanged()) {
+ log.debug("Rank hasn't changed");
return;
}
+ log.debug("Applying changes. New rank: {}", result.currentRank());
+
var embed = result.nextRank().isPresent() ? "rankIncrease" : "rankIncreaseMax";
var messageData = new MessageCreateBuilder().addContent(author.getAsMention())
.addEmbeds(embedCache.getEmbed(embed).injectValues(result.getEmbedValues(author)).toMessageEmbed())
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 6cbe933..fe0647c 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -8,6 +8,8 @@
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.UserSnowflake;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.sql.Connection;
@@ -19,13 +21,15 @@
public class RankService {
+ private static final Logger log = LoggerFactory.getLogger(RankListener.class);
private final DataSource dataSource;
public RankService(DataSource dataSource) {
this.dataSource = dataSource;
}
- public void addUser(UserSnowflake user) {
+ public void createUser(UserSnowflake user) {
+ log.debug("Inserting user: {}", user);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("INSERT INTO users VALUES(?) ON CONFLICT DO NOTHING");
statement.setLong(1, user.getIdLong());
@@ -36,6 +40,7 @@ public void addUser(UserSnowflake user) {
}
public void removeUser(UserSnowflake user) {
+ log.debug("Deleting user: {}", user);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("DELETE FROM users WHERE user_id = ?");
statement.setLong(1, user.getIdLong());
@@ -46,10 +51,11 @@ public void removeUser(UserSnowflake user) {
}
public void indexMembers(Guild guild) {
- guild.loadMembers(member -> addUser(member.getUser()));
+ guild.loadMembers(member -> createUser(member.getUser()));
}
private Optional getRankInfo(int rankId) {
+ log.debug("Querying rank info for rank: {}", rankId);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
SELECT role_id, color, bound
@@ -75,6 +81,7 @@ private Optional getRankInfo(int rankId) {
}
public UserInfo getUserInfo(UserSnowflake user) {
+ log.debug("Querying user info for user: {}", user);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
SELECT xp, rank_id, message_count, start_xp
@@ -103,6 +110,7 @@ public UserInfo getUserInfo(UserSnowflake user) {
}
public boolean isValidMessage(Message message) {
+ log.debug("Checking message: {}", message);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
SELECT rank_settings.*, users.last_valid_message
@@ -121,10 +129,12 @@ public boolean isValidMessage(Message message) {
var validChannels = Arrays.asList((Long[]) result.getArray("valid_channels").getArray());
if (System.currentTimeMillis() - lastMessage < messageCooldown) {
+ log.trace("User still has cooldown ({} < {})", System.currentTimeMillis() - lastMessage, messageCooldown);
return false;
}
if (message.getContentDisplay().length() < minimumLength) {
+ log.trace("Message is too short (Length: {}, Required: {}", message.getContentDisplay().length(), minimumLength);
return false;
}
@@ -132,13 +142,22 @@ public boolean isValidMessage(Message message) {
if (message.getChannelType().isThread()) {
channelId = message.getChannel().asThreadChannel().getParentChannel().getIdLong();
}
- return validChannels.contains(channelId);
+ var valid = validChannels.contains(channelId);
+
+ if (valid) {
+ log.debug("Message is valid");
+ } else {
+ log.trace("Invalid message channel");
+ }
+
+ return valid;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void updateValidMessage(UserSnowflake user) {
+ log.debug("Setting last_valid_message for user {} to {}", user, System.currentTimeMillis());
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
UPDATE users
@@ -157,12 +176,14 @@ public void updateValidMessage(UserSnowflake user) {
}
public XpChangeResult addRandomXp(UserSnowflake user) {
+ log.debug("Adding random xp to user: {}", user);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("SELECT * FROM add_random_xp(?)");
statement.setLong(1, user.getIdLong());
var result = statement.executeQuery();
result.next();
+ log.debug("New xp: {}", result.getInt("current_xp"));
return new XpChangeResult(
result.getBoolean("rank_changed"),
getRankInfo(result.getInt("current_rank")).orElseThrow(),
@@ -175,6 +196,7 @@ public XpChangeResult addRandomXp(UserSnowflake user) {
}
public XpChangeResult addXp(UserSnowflake user, int amount) {
+ log.debug("Adding {} xp to {}", amount, user);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("SELECT * FROM add_xp(?, ?)");
statement.setLong(1, user.getIdLong());
@@ -194,6 +216,7 @@ public XpChangeResult addXp(UserSnowflake user, int amount) {
}
public XpChangeResult setXp(UserSnowflake user, int value) {
+ log.debug("Setting xp of user {} to {}", user, value);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("SELECT * FROM set_xp(?, ?)");
statement.setLong(1, user.getIdLong());
@@ -218,10 +241,12 @@ public void updateRankRoles(Member member, Guild guild, XpChangeResult result) {
.map(guild::getRoleById)
.filter(it -> it != validRole)
.toList();
+ log.debug("Updating roles for {}. Valid role: {}, invalid Roles {}", member, validRole, invalidRoles);
guild.modifyMemberRoles(member, List.of(validRole), invalidRoles).queue();
}
public List getRankRoleIds() {
+ log.debug("Querying all role ids");
try (Connection connection = dataSource.getConnection()) {
var result = connection.prepareStatement("SELECT role_id FROM ranks").executeQuery();
var roleIds = new ArrayList();
@@ -235,6 +260,7 @@ public List getRankRoleIds() {
}
public List getLeaderboard() {
+ log.debug("Querying leaderboard");
try (Connection connection = dataSource.getConnection()) {
var result = connection.prepareStatement("""
SELECT users.xp, users.user_id, ranks.role_id
@@ -247,7 +273,9 @@ public List getLeaderboard() {
List rows = new ArrayList<>();
int rowCount = 1;
while (result.next()) {
+ log.trace("Adding row {}", rowCount);
if (rowCount == 11) {
+ log.trace("Page is full, starting new page");
pages.add(new LeaderboardPage(rows));
rows = new ArrayList<>();
rowCount = 1;
@@ -259,6 +287,7 @@ public List getLeaderboard() {
));
rowCount++;
}
+ log.debug("Result of leaderboard query: {} pages", pages.size());
return pages;
} catch (SQLException e) {
throw new RuntimeException(e);
@@ -266,6 +295,7 @@ public List getLeaderboard() {
}
public void resetDailyStatistics() {
+ log.debug("Resetting start_xp for all users");
try (Connection connection = dataSource.getConnection()) {
connection.prepareStatement("UPDATE users SET start_xp = xp").execute();
} catch (SQLException e) {
@@ -274,11 +304,11 @@ public void resetDailyStatistics() {
}
public void increaseTotalMessageCount() {
+ log.debug("Increasing total message count by one");
try (Connection connection = dataSource.getConnection()) {
connection.prepareStatement("SELECT * FROM increase_total_message_count()").execute();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
-
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java
index 705d5ea..70474cc 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java
@@ -13,10 +13,14 @@
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@Interaction(ephemeral = true)
public class ModifyXpCommands {
+ private static final Logger log = LoggerFactory.getLogger(ModifyXpCommands.class);
+
@Inject
private Database database;
@Inject
@@ -47,11 +51,14 @@ public void onSetXp(CommandEvent event, Member target, @Min(0) @Max(Integer.MAX_
}
private void checkRankUpdate(XpChangeResult result, Member member, Guild guild) {
+ log.debug("Checking for rank up: {}", member);
database.getRankService().updateRankRoles(member, guild, result);
if (!result.rankChanged()) {
+ log.debug("Rank hasn't changed");
return;
}
+ log.debug("Applying changes. New rank: {}", result.currentRank());
var embed = result.nextRank().isPresent() ? "rankIncrease" : "rankIncreaseMax";
var messageData = new MessageCreateBuilder().addContent(member.getAsMention())
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
index cf0f407..25f56d5 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
@@ -12,6 +12,8 @@
import com.github.kaktushose.jda.commands.dispatching.reply.components.Component;
import com.github.kaktushose.nplaybot.Database;
import net.dv8tion.jda.api.entities.Guild;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.List;
@@ -19,6 +21,8 @@
@Interaction
public class LeaderboardCommand {
+ private static final Logger log = LoggerFactory.getLogger(LeaderboardCommand.class);
+
@Inject
private Database database;
@Inject
@@ -41,6 +45,7 @@ public void onCommand(CommandEvent event) {
@Button(emoji = "⏪")
public void onStart(ComponentEvent event) {
index = 1;
+ log.trace("Leaderboard#onStart pressed, new index: {}", index);
reply(event);
}
@@ -49,6 +54,7 @@ public void onBackward(ComponentEvent event) {
if (index > minIndex) {
index--;
}
+ log.trace("Leaderboard#onBackward pressed, new index: {}", index);
reply(event);
}
@@ -57,16 +63,19 @@ public void onForward(ComponentEvent event) {
if (index < maxIndex) {
index++;
}
+ log.trace("Leaderboard#onForward pressed, new index: {}", index);
reply(event);
}
@Button(emoji = "⏩")
public void onEnd(ComponentEvent event) {
index = maxIndex;
+ log.trace("Leaderboard#onEnd pressed, new index: {}", index);
reply(event);
}
private void reply(Replyable event) {
+ log.debug("Sending new leaderboard with index {}/{}", index, maxIndex);
event.with(getButtons()).reply(
embedCache.getEmbed("leaderboard").injectValue("leaderboard", leaderboard.get(index - 1).getPage(guild))
.toEmbedBuilder()
@@ -75,18 +84,22 @@ private void reply(Replyable event) {
}
private Component[] getButtons() {
+ log.trace("Selecting buttons for index: {}, minIndex: {}, maxIndex: {}", index, minIndex, maxIndex);
if (index == minIndex) {
+ log.trace("Enabling bof buttons");
return List.of(
Buttons.disabled("onStart", "onBackward"),
Buttons.enabled("onForward", "onEnd")
).toArray(new Component[0]);
}
if (index == maxIndex) {
+ log.trace("Enabling eof buttons");
return List.of(
Buttons.enabled("onStart", "onBackward"),
Buttons.disabled("onForward", "onEnd")
).toArray(new Component[0]);
}
+ log.trace("Enabling all buttons");
return List.of(
Buttons.enabled("onStart", "onBackward"),
Buttons.enabled("onForward", "onEnd")
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java
index 0ad257e..9b1e7d4 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/XpChangeResult.java
@@ -20,4 +20,14 @@ public Map getEmbedValues(UserSnowflake user) {
});
return result;
}
+
+ @Override
+ public String toString() {
+ return "XpChangeResult{" +
+ "rankChanged=" + rankChanged +
+ ", currentRank=" + currentRank +
+ ", nextRank=" + nextRank +
+ ", currentXp=" + currentXp +
+ '}';
+ }
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java b/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
index 6b0d1ff..9d446c6 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
@@ -47,7 +47,7 @@ public void shutdown() {
private void indexTasks() {
var methods = reflections.getMethodsAnnotatedWith(ScheduledTask.class);
-
+ log.debug("Indexing tasks:");
for (var method : methods) {
var scheduledTask = method.getAnnotation(ScheduledTask.class);
@@ -57,9 +57,10 @@ private void indexTasks() {
- (TimeUnit.HOURS.toMinutes(Calendar.getInstance().get(Calendar.HOUR_OF_DAY))
+ Calendar.getInstance().get(Calendar.MINUTE));
}
-
+ // TODO dealy and period have to be same unit
if (scheduledTask.repeat()) {
- executor.scheduleAtFixedRate(execute(method), delay, scheduledTask.period(), scheduledTask.unit());
+ log.debug("Scheduling repeating task {}.{}. Starts in {} minutes. Repeats every {} minutes");
+ executor.scheduleAtFixedRate(execute(method), delay, scheduledTask.period(), scheduledTask.unit();
} else {
executor.scheduleAtFixedRate(execute(method), delay, scheduledTask.period(), scheduledTask.unit());
}
@@ -69,6 +70,7 @@ private void indexTasks() {
private Runnable execute(Method method) {
return () -> {
try {
+ log.debug("Invoking task: {}.{}", method.getDeclaringClass().getSimpleName(), method.getName());
method.invoke(method.getDeclaringClass().getConstructors()[0].newInstance(), bot);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
log.error("Exception in scheduled task!", e);
From 01b2763ef0d6349a88277733c1b0153ea3a1dd3e Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Thu, 4 Jan 2024 15:57:24 +0100
Subject: [PATCH 33/66] fix time unit bug in TaskScheduler
---
.../nplaybot/scheduler/TaskScheduler.java | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java b/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
index 9d446c6..70f2ddd 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/scheduler/TaskScheduler.java
@@ -51,18 +51,22 @@ private void indexTasks() {
for (var method : methods) {
var scheduledTask = method.getAnnotation(ScheduledTask.class);
- var delay = scheduledTask.initialDelay();
+ var delay = scheduledTask.unit().toMillis(scheduledTask.initialDelay());
+ var period = scheduledTask.unit().toMillis(scheduledTask.period());
if (scheduledTask.startAtMidnight()) {
delay = TimeUnit.HOURS.toMinutes(24)
- (TimeUnit.HOURS.toMinutes(Calendar.getInstance().get(Calendar.HOUR_OF_DAY))
+ Calendar.getInstance().get(Calendar.MINUTE));
+ delay = TimeUnit.MINUTES.toMillis(delay);
}
- // TODO dealy and period have to be same unit
+
if (scheduledTask.repeat()) {
- log.debug("Scheduling repeating task {}.{}. Starts in {} minutes. Repeats every {} minutes");
- executor.scheduleAtFixedRate(execute(method), delay, scheduledTask.period(), scheduledTask.unit();
+ log.debug("Scheduling repeating task {}.{}. Starts in {} ms. Repeats every {} ms",
+ method.getDeclaringClass().getSimpleName(), method.getName(), delay, period);
+ executor.scheduleAtFixedRate(execute(method), delay, period, scheduledTask.unit());
} else {
- executor.scheduleAtFixedRate(execute(method), delay, scheduledTask.period(), scheduledTask.unit());
+ log.debug("Scheduling task {}.{}. Starts in {} ms", method.getDeclaringClass().getSimpleName(), method.getName(), period);
+ executor.schedule(execute(method), delay, scheduledTask.unit());
}
}
}
From ee3a12f636f7e9ca3fcfe63746811a241cdbd00d Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Thu, 4 Jan 2024 16:36:51 +0100
Subject: [PATCH 34/66] implement daily messages
---
embeds.json | 5 ++
.../com/github/kaktushose/nplaybot/Bot.java | 4 ++
.../kaktushose/nplaybot/rank/RankService.java | 56 +++++++++++++++----
.../rank/commands/SwitchDailyCommand.java | 4 --
.../nplaybot/rank/daily/DailyMessageTask.java | 25 +++++++++
.../rank/daily/SwitchDailyMessageCommand.java | 24 ++++++++
.../nplaybot/rank/model/RankInfo.java | 2 +-
.../nplaybot/rank/model/UserInfo.java | 18 ++++++
8 files changed, 123 insertions(+), 15 deletions(-)
delete mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/commands/SwitchDailyCommand.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/daily/DailyMessageTask.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/daily/SwitchDailyMessageCommand.java
diff --git a/embeds.json b/embeds.json
index aec9acf..2055809 100644
--- a/embeds.json
+++ b/embeds.json
@@ -104,5 +104,10 @@
"title": "Leaderboard",
"description": "{leaderboard}",
"color": "#67c94f"
+ },
+ "switchDaily" : {
+ "title": "Erfolg",
+ "description": "Die tägliche Kontoinformation wurde {switch}",
+ "color": "#67c94f"
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 2da7e35..8196d27 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -74,6 +74,10 @@ public void shutdown() {
database.closeDataSource();
}
+ public JDA getJda() {
+ return jda;
+ }
+
@Produces(skipIndexing = true)
public Database getDatabase() {
return database;
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index fe0647c..60d251b 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -4,20 +4,14 @@
import com.github.kaktushose.nplaybot.rank.model.RankInfo;
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
-import net.dv8tion.jda.api.entities.Guild;
-import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.entities.Message;
-import net.dv8tion.jda.api.entities.UserSnowflake;
+import net.dv8tion.jda.api.entities.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
public class RankService {
@@ -58,7 +52,7 @@ private Optional getRankInfo(int rankId) {
log.debug("Querying rank info for rank: {}", rankId);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
- SELECT role_id, color, bound
+ SELECT role_id, name, color, bound
FROM ranks
WHERE rank_id = ?
"""
@@ -70,6 +64,7 @@ private Optional getRankInfo(int rankId) {
if (result.next()) {
return Optional.of(new RankInfo(
result.getLong("role_id"),
+ result.getString("name"),
result.getString("color"),
result.getInt("bound")
));
@@ -134,7 +129,7 @@ public boolean isValidMessage(Message message) {
}
if (message.getContentDisplay().length() < minimumLength) {
- log.trace("Message is too short (Length: {}, Required: {}", message.getContentDisplay().length(), minimumLength);
+ log.trace("Message is too short (Length: {}, Required: {}", message.getContentDisplay().length(), minimumLength);
return false;
}
@@ -311,4 +306,45 @@ public void increaseTotalMessageCount() {
throw new RuntimeException(e);
}
}
+
+ public void switchDaily(UserSnowflake user, boolean enabled) {
+ log.debug("Setting daily message for user {} to {}", user, enabled);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("UPDATE users SET daily_message = ? where user_id = ?");
+ statement.setBoolean(1, enabled);
+ statement.setLong(2, user.getIdLong());
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Map getDailyRankInfos() {
+ log.debug("Querying daily rank infos");
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT user_id, xp, rank_id, message_count, start_xp
+ FROM users
+ WHERE daily_message = true
+ """
+ );
+ var result = statement.executeQuery();
+ var users = new HashMap();
+ while (result.next()) {
+ var currentRank = getRankInfo(result.getInt("rank_id")).orElseThrow();
+ var nextRank = getRankInfo(result.getInt("rank_id") + 1);
+
+ users.put(result.getLong("user_id"), new UserInfo(
+ result.getInt("xp"),
+ currentRank,
+ nextRank,
+ result.getInt("message_count"),
+ result.getInt("xp") - result.getInt("start_xp")
+ ));
+ }
+ return users;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SwitchDailyCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SwitchDailyCommand.java
deleted file mode 100644
index a1eca88..0000000
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/SwitchDailyCommand.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.github.kaktushose.nplaybot.rank.commands;
-
-public class SwitchDailyCommand {
-}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/daily/DailyMessageTask.java b/src/main/java/com/github/kaktushose/nplaybot/rank/daily/DailyMessageTask.java
new file mode 100644
index 0000000..b6408ee
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/daily/DailyMessageTask.java
@@ -0,0 +1,25 @@
+package com.github.kaktushose.nplaybot.rank.daily;
+
+import com.github.kaktushose.nplaybot.Bot;
+import com.github.kaktushose.nplaybot.scheduler.ScheduledTask;
+import net.dv8tion.jda.api.entities.User;
+
+import java.util.concurrent.TimeUnit;
+
+public class DailyMessageTask {
+
+ @ScheduledTask(period = 24, unit = TimeUnit.HOURS, startAtMidnight = true)
+ public void onSendDailyMessages(Bot bot) {
+ bot.getDatabase().getRankService().getDailyRankInfos().forEach((userId, userInfo) ->
+ bot.getJda().retrieveUserById(userId)
+ .flatMap(User::openPrivateChannel)
+ .flatMap(channel ->
+ channel.sendMessage(
+ bot.getEmbedCache().getEmbed(userInfo.nextRank().isPresent() ? "rankInfo" : "rankInfoMax")
+ .injectValues(userInfo.getEmbedValues(channel.getUser())).toMessageCreateData()
+ )
+ ).queue()
+ );
+ }
+
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/daily/SwitchDailyMessageCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/daily/SwitchDailyMessageCommand.java
new file mode 100644
index 0000000..8301a57
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/daily/SwitchDailyMessageCommand.java
@@ -0,0 +1,24 @@
+package com.github.kaktushose.nplaybot.rank.daily;
+
+import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.Param;
+import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.nplaybot.Database;
+
+@Interaction
+public class SwitchDailyMessageCommand {
+
+ @Inject
+ private EmbedCache embedCache;
+ @Inject
+ private Database database;
+
+ @SlashCommand(value = "täglich", desc = "Ändert die Einstellungen für die tägliche Kontoinformation")
+ public void onCommand(CommandEvent event, @Param(value = "Ob du eine tägliche Nachricht erhalten möchtest oder nicht", name = "aktivieren") boolean enabled) {
+ database.getRankService().switchDaily(event.getUser(), enabled);
+ event.reply(embedCache.getEmbed("switchDaily").injectValue("switch", enabled ? "aktiviert" : "deaktiviert"));
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/RankInfo.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/RankInfo.java
index 01317d6..d0ed97d 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/model/RankInfo.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/RankInfo.java
@@ -1,4 +1,4 @@
package com.github.kaktushose.nplaybot.rank.model;
-public record RankInfo(long roleId, String color, int xpBound) {
+public record RankInfo(long roleId, String name, String color, int xpBound) {
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
index 1ef364b..af6e222 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
@@ -1,6 +1,7 @@
package com.github.kaktushose.nplaybot.rank.model;
import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
import java.util.HashMap;
import java.util.Map;
@@ -24,4 +25,21 @@ public Map getEmbedValues(Member member) {
});
return result;
}
+
+ public Map getEmbedValues(User user) {
+ var result = new HashMap() {{
+ put("user", String.format("<@%d>", user.getIdLong()));
+ put("color", currentRank.color());
+ put("avatarUrl", user.getEffectiveAvatarUrl());
+ put("currentRank", currentRank.name());
+ put("currentXp", currentXp);
+ put("xpGain", xpGain);
+ put("messageCount", messageCount);
+ }};
+ nextRank.ifPresent(rank -> {
+ result.put("nextRank", rank.name());
+ result.put("missingXp", rank.xpBound() - currentXp);
+ });
+ return result;
+ }
}
From 1a859bf6a60a5cd688d3dc82fffee459481e0aa6 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Sun, 7 Jan 2024 15:20:26 +0100
Subject: [PATCH 35/66] implement xp loot drops
---
.env.example | 1 -
.gitignore | 1 -
embeds.json | 11 +-
.../nplaybot/rank/RankListener.java | 89 ++++++++-
.../kaktushose/nplaybot/rank/RankService.java | 73 +++++--
.../migration/V1.0.0__setup_rank_system.sql | 20 +-
wait-for-it.sh | 183 ++++++++++++++++++
7 files changed, 346 insertions(+), 32 deletions(-)
create mode 100755 wait-for-it.sh
diff --git a/.env.example b/.env.example
index a4573c8..02112a6 100644
--- a/.env.example
+++ b/.env.example
@@ -3,4 +3,3 @@ POSTGRES_USER=user
POSTGRES_PASSWORD=password
POSTGRES_URL=jdbc:postgresql://postgres:5432/database
GF_SECURITY_ADMIN_PASSWORD=password
-BOT_GUILD=0123456789
diff --git a/.gitignore b/.gitignore
index 0306ffc..c0611b1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,4 +35,3 @@ buildNumber.properties
*.env
/data
/logs
-wait-for-it.sh
diff --git a/embeds.json b/embeds.json
index 2055809..2dc865e 100644
--- a/embeds.json
+++ b/embeds.json
@@ -90,12 +90,12 @@
"description": "Der EmbedCache wurde aktualisiert",
"color": "#67c94f"
},
- "setXpResult" : {
+ "setXpResult": {
"title": "Erfolg",
"description": "Die XP von {user} wurden auf {xp} XP gesetzt",
"color": "#67c94f"
},
- "addXpResult" : {
+ "addXpResult": {
"title": "Erfolg",
"description": "{user} wurden {xp} XP hinzugefügt",
"color": "#67c94f"
@@ -105,9 +105,14 @@
"description": "{leaderboard}",
"color": "#67c94f"
},
- "switchDaily" : {
+ "switchDaily": {
"title": "Erfolg",
"description": "Die tägliche Kontoinformation wurde {switch}",
"color": "#67c94f"
+ },
+ "xpLootDropClaimed": {
+ "title": "Glückwunsch :tada:",
+ "description": "{user} hat {xp} XP :star2: gefunden!",
+ "color": "#67c94f"
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
index 83ed176..e4d6020 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
@@ -2,32 +2,43 @@
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
import com.github.kaktushose.nplaybot.settings.SettingsService;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
public class RankListener extends ListenerAdapter {
private static final Logger log = LoggerFactory.getLogger(RankListener.class);
private final RankService rankService;
private final SettingsService settingsService;
private final EmbedCache embedCache;
+ private final Map xpLootDrops;
public RankListener(Database database, EmbedCache embedCache) {
this.rankService = database.getRankService();
this.settingsService = database.getSettingsService();
this.embedCache = embedCache;
+ xpLootDrops = new HashMap<>();
}
@Override
public void onMessageReceived(@NotNull MessageReceivedEvent event) {
log.debug("Received message event");
var author = event.getAuthor();
- var message = event.getMessage();
if (author.isBot()) {
log.trace("Author is bot");
@@ -40,16 +51,30 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
rankService.increaseTotalMessageCount();
- if (!rankService.isValidMessage(message)) {
- log.trace("Message doesn't meet rank criteria");
+ if (!rankService.isValidChannel(event.getChannel(), event.getGuild())) {
return;
}
- rankService.updateValidMessage(author);
- var result = rankService.addRandomXp(author);
+ onXpLootDrop(event);
+
+ if (!rankService.isValidMessage(event.getMessage())) {
+ log.debug("Message doesn't meet rank criteria");
+ return;
+ }
+
+ onAddRegularXp(event);
+ }
+
+ private void onAddRegularXp(MessageReceivedEvent event) {
+ rankService.updateValidMessage(event.getAuthor());
+ var result = rankService.addRandomXp(event.getAuthor());
- log.debug("Checking for rank up: {}", author);
- rankService.updateRankRoles(event.getMember(), event.getGuild(), result);
+ onXpChange(result, event.getMember(), event.getGuild());
+ }
+
+ private void onXpChange(XpChangeResult result, Member member, Guild guild) {
+ log.debug("Checking for rank up: {}", member);
+ rankService.updateRankRoles(member, guild, result);
if (!result.rankChanged()) {
log.debug("Rank hasn't changed");
@@ -58,9 +83,53 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
log.debug("Applying changes. New rank: {}", result.currentRank());
var embed = result.nextRank().isPresent() ? "rankIncrease" : "rankIncreaseMax";
- var messageData = new MessageCreateBuilder().addContent(author.getAsMention())
- .addEmbeds(embedCache.getEmbed(embed).injectValues(result.getEmbedValues(author)).toMessageEmbed())
+ var messageData = new MessageCreateBuilder().addContent(member.getAsMention())
+ .addEmbeds(embedCache.getEmbed(embed).injectValues(result.getEmbedValues(member)).toMessageEmbed())
.build();
- settingsService.getBotChannel(event.getGuild()).sendMessage(messageData).queue();
+ settingsService.getBotChannel(guild).sendMessage(messageData).queue();
+ }
+
+ private void onXpLootDrop(MessageReceivedEvent event) {
+ var xp = rankService.getXpLootDrop(event.getMessage());
+
+ if (xp < 1) {
+ log.debug("No xp loot drop for this message");
+ return;
+ }
+
+ xpLootDrops.put(event.getMessageIdLong(), xp);
+ event.getMessage().addReaction(Emoji.fromUnicode("\uD83C\uDF1F")).queue();
+ }
+
+ @Override
+ public void onMessageReactionAdd(@NotNull MessageReactionAddEvent event) {
+ if (event.getUser().isBot()) {
+ return;
+ }
+
+ var messageId = event.getMessageIdLong();
+ if (!xpLootDrops.containsKey(messageId)) {
+ return;
+ }
+ if (!event.getEmoji().equals(Emoji.fromUnicode("\uD83C\uDF1F"))) {
+ return;
+ }
+
+ log.debug("Xp loot drop got claimed by {}", event.getMember());
+
+ var xp = xpLootDrops.get(messageId);
+ var result = rankService.addXp(event.getMember(), xp);
+ onXpChange(result, event.getMember(), event.getGuild());
+ xpLootDrops.remove(messageId);
+
+ event.retrieveMessage().queue(message -> {
+ message.reply(
+ embedCache.getEmbed("xpLootDropClaimed")
+ .injectValue("user", event.getMember().getAsMention())
+ .injectValue("xp", xp)
+ .toMessageCreateData()
+ ).queue(it -> it.delete().queueAfter(10, TimeUnit.SECONDS));
+ message.clearReactions().queue();
+ });
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 60d251b..194ee0c 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -5,6 +5,10 @@
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
import net.dv8tion.jda.api.entities.*;
+import net.dv8tion.jda.api.entities.channel.Channel;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
+import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -121,31 +125,19 @@ public boolean isValidMessage(Message message) {
var lastMessage = result.getLong("last_valid_message");
var messageCooldown = result.getInt("message_cooldown");
var minimumLength = result.getInt("min_message_length");
- var validChannels = Arrays.asList((Long[]) result.getArray("valid_channels").getArray());
if (System.currentTimeMillis() - lastMessage < messageCooldown) {
- log.trace("User still has cooldown ({} < {})", System.currentTimeMillis() - lastMessage, messageCooldown);
+ log.debug("User still has cooldown ({} < {})", System.currentTimeMillis() - lastMessage, messageCooldown);
return false;
}
if (message.getContentDisplay().length() < minimumLength) {
- log.trace("Message is too short (Length: {}, Required: {}", message.getContentDisplay().length(), minimumLength);
+ log.debug("Message is too short (Length: {}, Required: {}", message.getContentDisplay().length(), minimumLength);
return false;
}
- var channelId = message.getChannelIdLong();
- if (message.getChannelType().isThread()) {
- channelId = message.getChannel().asThreadChannel().getParentChannel().getIdLong();
- }
- var valid = validChannels.contains(channelId);
-
- if (valid) {
- log.debug("Message is valid");
- } else {
- log.trace("Invalid message channel");
- }
-
- return valid;
+ log.debug("Message is valid");
+ return true;
} catch (SQLException e) {
throw new RuntimeException(e);
}
@@ -347,4 +339,53 @@ public Map getDailyRankInfos() {
throw new RuntimeException(e);
}
}
+
+ public int getXpLootDrop(Message message) {
+ log.debug("Querying xp loot drop for message {}", message);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("SELECT * FROM get_xp_loot_drop(?)");
+ statement.setLong(1, message.getGuildIdLong());
+
+ var result = statement.executeQuery();
+ result.next();
+ var xp = result.getInt(1);
+ log.debug("Xp loot drop: {} xp", xp);
+ return xp;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean isValidChannel(MessageChannelUnion channel, Guild guild) {
+ log.debug("Checking channel: {}", channel);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT rank_settings.valid_channels
+ FROM rank_settings
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, guild.getIdLong());
+
+ var result = statement.executeQuery();
+ result.next();
+ var validChannels = Arrays.asList((Long[]) result.getArray("valid_channels").getArray());
+
+ var channelId = channel.getIdLong();
+ if (channel.getType().isThread()) {
+ channelId = channel.asThreadChannel().getParentChannel().getIdLong();
+ }
+ var valid = validChannels.contains(channelId);
+
+ if (valid) {
+ log.debug("Channel is valid");
+ } else {
+ log.debug("Invalid message channel");
+ }
+
+ return valid;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
index d137593..458d1cc 100644
--- a/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
+++ b/src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
@@ -9,7 +9,8 @@ CREATE TABLE rank_settings (
guild_id BIGINT NOT NULL PRIMARY KEY,
message_cooldown INT NOT NULL,
min_message_length INT NOT NULL,
- valid_channels BIGINT[] NOT NULL
+ valid_channels BIGINT[] NOT NULL,
+ xp_loot_chance REAL NOT NULL
);
CREATE TABLE ranks (
@@ -178,3 +179,20 @@ BEGIN
ON CONFLICT (DATE) DO UPDATE SET total_message_count = rank_statistics.total_message_count + 1;
END;
$$ LANGUAGE plpgsql;
+
+CREATE FUNCTION get_xp_loot_drop(id BIGINT)
+RETURNS TABLE (xp INT) AS
+$$
+DECLARE
+ chance INT;
+ drop_chance REAL;
+BEGIN
+ SELECT rank_settings.xp_loot_chance INTO drop_chance FROM rank_settings WHERE guild_id = id;
+ chance := floor(random() * 100) + 1;
+ IF ROUND(drop_chance) >= chance THEN
+ RETURN QUERY SELECT get_random_xp FROM get_random_xp();
+ ELSE
+ RETURN QUERY SELECT 0;
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
diff --git a/wait-for-it.sh b/wait-for-it.sh
new file mode 100755
index 0000000..64019e8
--- /dev/null
+++ b/wait-for-it.sh
@@ -0,0 +1,183 @@
+#!/usr/bin/env bash
+# https://github.com/vishnubob/wait-for-it
+# Use this script to test if a given TCP host/port are available
+
+WAITFORIT_cmdname=${0##*/}
+
+echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
+
+usage()
+{
+ cat << USAGE >&2
+Usage:
+ $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
+ -h HOST | --host=HOST Host or IP under test
+ -p PORT | --port=PORT TCP port under test
+ Alternatively, you specify the host and port as host:port
+ -s | --strict Only execute subcommand if the test succeeds
+ -q | --quiet Don't output any status messages
+ -t TIMEOUT | --timeout=TIMEOUT
+ Timeout in seconds, zero for no timeout
+ -- COMMAND ARGS Execute command with args after the test finishes
+USAGE
+ exit 1
+}
+
+wait_for()
+{
+ if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
+ echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
+ else
+ echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
+ fi
+ WAITFORIT_start_ts=$(date +%s)
+ while :
+ do
+ if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
+ nc -z $WAITFORIT_HOST $WAITFORIT_PORT
+ WAITFORIT_result=$?
+ else
+ (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
+ WAITFORIT_result=$?
+ fi
+ if [[ $WAITFORIT_result -eq 0 ]]; then
+ WAITFORIT_end_ts=$(date +%s)
+ echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
+ break
+ fi
+ sleep 1
+ done
+ return $WAITFORIT_result
+}
+
+wait_for_wrapper()
+{
+ # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
+ if [[ $WAITFORIT_QUIET -eq 1 ]]; then
+ timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
+ else
+ timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
+ fi
+ WAITFORIT_PID=$!
+ trap "kill -INT -$WAITFORIT_PID" INT
+ wait $WAITFORIT_PID
+ WAITFORIT_RESULT=$?
+ if [[ $WAITFORIT_RESULT -ne 0 ]]; then
+ echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
+ fi
+ return $WAITFORIT_RESULT
+}
+
+# process arguments
+while [[ $# -gt 0 ]]
+do
+ case "$1" in
+ *:* )
+ WAITFORIT_hostport=(${1//:/ })
+ WAITFORIT_HOST=${WAITFORIT_hostport[0]}
+ WAITFORIT_PORT=${WAITFORIT_hostport[1]}
+ shift 1
+ ;;
+ --child)
+ WAITFORIT_CHILD=1
+ shift 1
+ ;;
+ -q | --quiet)
+ WAITFORIT_QUIET=1
+ shift 1
+ ;;
+ -s | --strict)
+ WAITFORIT_STRICT=1
+ shift 1
+ ;;
+ -h)
+ WAITFORIT_HOST="$2"
+ if [[ $WAITFORIT_HOST == "" ]]; then break; fi
+ shift 2
+ ;;
+ --host=*)
+ WAITFORIT_HOST="${1#*=}"
+ shift 1
+ ;;
+ -p)
+ WAITFORIT_PORT="$2"
+ if [[ $WAITFORIT_PORT == "" ]]; then break; fi
+ shift 2
+ ;;
+ --port=*)
+ WAITFORIT_PORT="${1#*=}"
+ shift 1
+ ;;
+ -t)
+ WAITFORIT_TIMEOUT="$2"
+ if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
+ shift 2
+ ;;
+ --timeout=*)
+ WAITFORIT_TIMEOUT="${1#*=}"
+ shift 1
+ ;;
+ --)
+ shift
+ WAITFORIT_CLI=("$@")
+ break
+ ;;
+ --help)
+ usage
+ ;;
+ *)
+ echoerr "Unknown argument: $1"
+ usage
+ ;;
+ esac
+done
+
+if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
+ echoerr "Error: you need to provide a host and port to test."
+ usage
+fi
+
+WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
+WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
+WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
+WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
+
+# Check to see if timeout is from busybox?
+WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
+WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
+
+WAITFORIT_BUSYTIMEFLAG=""
+if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
+ WAITFORIT_ISBUSY=1
+ # Check if busybox timeout uses -t flag
+ # (recent Alpine versions don't support -t anymore)
+ if timeout &>/dev/stdout | grep -q -e '-t '; then
+ WAITFORIT_BUSYTIMEFLAG="-t"
+ fi
+else
+ WAITFORIT_ISBUSY=0
+fi
+
+if [[ $WAITFORIT_CHILD -gt 0 ]]; then
+ wait_for
+ WAITFORIT_RESULT=$?
+ exit $WAITFORIT_RESULT
+else
+ if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
+ wait_for_wrapper
+ WAITFORIT_RESULT=$?
+ else
+ wait_for
+ WAITFORIT_RESULT=$?
+ fi
+fi
+
+if [[ $WAITFORIT_CLI != "" ]]; then
+ if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
+ echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
+ exit $WAITFORIT_RESULT
+ fi
+ exec "${WAITFORIT_CLI[@]}"
+else
+ exit $WAITFORIT_RESULT
+fi
From fa6fc9583d99783ad8db18ed7208c63dc1210039 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Sun, 7 Jan 2024 15:37:30 +0100
Subject: [PATCH 36/66] add embeds.json to docker build
---
.env.example | 1 +
Dockerfile | 1 +
docker-compose.yml | 3 +--
3 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/.env.example b/.env.example
index 02112a6..a4573c8 100644
--- a/.env.example
+++ b/.env.example
@@ -3,3 +3,4 @@ POSTGRES_USER=user
POSTGRES_PASSWORD=password
POSTGRES_URL=jdbc:postgresql://postgres:5432/database
GF_SECURITY_ADMIN_PASSWORD=password
+BOT_GUILD=0123456789
diff --git a/Dockerfile b/Dockerfile
index ec363af..f07efc2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,6 +16,7 @@ COPY src/main/resources/db/migration ./db/migration
COPY --from=builder /bot/*.sh .
COPY --from=builder /bot/target/NPLAY-Bot.jar ./NPLAY-Bot.jar
+COPY --from=builder /bot/embeds.json .
RUN chmod +x ./wait-for-it.sh ./entrypoint.sh
diff --git a/docker-compose.yml b/docker-compose.yml
index a0a1f9a..4477b44 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -26,8 +26,7 @@ services:
- postgres
bot:
- build:
- context: .
+ image: ghcr.io/kaktushose/levelbot/nplaybot:latest
container_name: nplay-bot
restart: on-failure
environment:
From 9bb999de08956491997c178797a117ebb1182498 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Tue, 23 Apr 2024 19:51:59 +0200
Subject: [PATCH 37/66] implement contest events
---
embeds.json | 10 +
pom.xml | 10 +-
.../com/github/kaktushose/nplaybot/Bot.java | 4 +-
.../github/kaktushose/nplaybot/Database.java | 7 +
.../events/contest/ContestCommands.java | 53 ++++++
.../events/contest/ContestEventService.java | 178 ++++++++++++++++++
.../events/contest/ContestListener.java | 104 ++++++++++
.../nplaybot/rank/RankListener.java | 3 +-
.../kaktushose/nplaybot/rank/RankService.java | 10 +-
.../rank/leaderboard/LeaderboardPage.java | 10 +-
.../nplaybot/settings/SettingsService.java | 5 +
.../migration/V2.0.0__setup_event_system.sql | 10 +
12 files changed, 387 insertions(+), 17 deletions(-)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestCommands.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestEventService.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestListener.java
create mode 100644 src/main/resources/db/migration/V2.0.0__setup_event_system.sql
diff --git a/embeds.json b/embeds.json
index 2dc865e..c190376 100644
--- a/embeds.json
+++ b/embeds.json
@@ -114,5 +114,15 @@
"title": "Glückwunsch :tada:",
"description": "{user} hat {xp} XP :star2: gefunden!",
"color": "#67c94f"
+ },
+ "contestEventStart": {
+ "title": "Okay",
+ "description": "Das Content-Event wurde in {channel} gestartet",
+ "color": "#67c94f"
+ },
+ "contestEventStop": {
+ "title": "Leaderboard",
+ "description": "{leaderboard}",
+ "color": "#67c94f"
}
}
diff --git a/pom.xml b/pom.xml
index 6835783..83f3499 100644
--- a/pom.xml
+++ b/pom.xml
@@ -72,12 +72,12 @@
net.dv8tion
JDA
- 5.0.0-beta.18
+ 5.0.0-beta.22
com.github.Kaktushose
jda-commands
- 3d823b1173
+ 4.0.0-beta.2
com.zaxxer
@@ -87,7 +87,7 @@
org.postgresql
postgresql
- 42.7.0
+ 42.7.3
org.slf4j
@@ -97,12 +97,12 @@
ch.qos.logback
logback-classic
- 1.4.11
+ 1.4.14
ch.qos.logback
logback-core
- 1.4.11
+ 1.4.12
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 8196d27..9cc8730 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -3,6 +3,7 @@
import com.github.kaktushose.jda.commands.JDACommands;
import com.github.kaktushose.jda.commands.annotations.Produces;
import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.nplaybot.events.contest.ContestListener;
import com.github.kaktushose.nplaybot.rank.JoinLeaveListener;
import com.github.kaktushose.nplaybot.rank.RankListener;
import com.github.kaktushose.nplaybot.scheduler.TaskScheduler;
@@ -44,7 +45,8 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
.setStatus(OnlineStatus.IDLE)
.addEventListeners(
new RankListener(database, embedCache),
- new JoinLeaveListener(database.getRankService())
+ new JoinLeaveListener(database.getRankService()),
+ new ContestListener(database.getContestEventService())
)
.build().awaitReady();
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Database.java b/src/main/java/com/github/kaktushose/nplaybot/Database.java
index 26333d3..617fdf4 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Database.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Database.java
@@ -1,5 +1,6 @@
package com.github.kaktushose.nplaybot;
+import com.github.kaktushose.nplaybot.events.contest.ContestEventService;
import com.github.kaktushose.nplaybot.rank.RankService;
import com.github.kaktushose.nplaybot.settings.SettingsService;
import com.zaxxer.hikari.HikariConfig;
@@ -10,6 +11,7 @@ public class Database {
private final HikariDataSource dataSource;
private final SettingsService settingsService;
private final RankService rankService;
+ private final ContestEventService contestEventService;
public Database() {
var config = new HikariConfig();
@@ -23,6 +25,7 @@ public Database() {
settingsService = new SettingsService(dataSource);
rankService = new RankService(dataSource);
+ contestEventService = new ContestEventService(dataSource);
}
public void closeDataSource() {
@@ -36,4 +39,8 @@ public SettingsService getSettingsService() {
public RankService getRankService() {
return rankService;
}
+
+ public ContestEventService getContestEventService() {
+ return contestEventService;
+ }
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestCommands.java b/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestCommands.java
new file mode 100644
index 0000000..bf0a53c
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestCommands.java
@@ -0,0 +1,53 @@
+package com.github.kaktushose.nplaybot.events.contest;
+
+import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.Param;
+import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.nplaybot.Database;
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+
+import java.util.Optional;
+
+@Interaction
+public class ContestCommands {
+
+ @Inject
+ private Database database;
+ @Inject
+ private EmbedCache embedCache;
+
+ @SlashCommand(value = "contest event start", desc = "Startet ein Contest-Event", enabledFor = Permission.BAN_MEMBERS, isGuildOnly = true)
+ public void onContestEventStart(CommandEvent event,
+ @Param("Der Textkanal, in dem das Contest-Event stattfinden soll") TextChannel channel,
+ @Param("Der Emoji, mit dem abgestimmt werden soll") String emoji) {
+ database.getContestEventService().startContestEvent(channel, emoji);
+ event.reply(embedCache.getEmbed("contestEventStart").injectValue("channel", channel.getAsMention()));
+ }
+
+ @SlashCommand(value = "contest event stop", desc = "Stoppt das aktuelle Contest-Event und zeigt die Gewinner an", enabledFor = Permission.BAN_MEMBERS, isGuildOnly = true)
+ public void onContestEventStop(CommandEvent event) {
+ var result = database.getContestEventService().stopContestEvent(event.getGuild());
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < result.size(); i++) {
+ var row = result.get(i);
+ builder.append(String.format("%d. %s (%d Votes)\n", i, resolveName(event.getGuild(), row.userId()), row.votes()));
+ }
+ event.reply(embedCache.getEmbed("contestEventStop").injectValue("leaderboard", builder.toString()));
+ }
+
+
+ private String resolveName(Guild guild, long userId) {
+ var member = Optional.ofNullable(guild.getMemberById(userId));
+ if (member.isPresent()) {
+ return member.get().getEffectiveName();
+ }
+ // retrieve member thus it gets loaded to cache
+ guild.retrieveMemberById(userId).queue();
+ return String.format("<@%d>", userId);
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestEventService.java b/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestEventService.java
new file mode 100644
index 0000000..433ddd1
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestEventService.java
@@ -0,0 +1,178 @@
+package com.github.kaktushose.nplaybot.events.contest;
+
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ContestEventService {
+
+ private static final Logger log = LoggerFactory.getLogger(ContestEventService.class);
+ private final DataSource dataSource;
+ public ContestEventService(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public long getContestEventChannel(Guild guild) {
+ log.debug("Querying contest event channel");
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT contest_channel_id
+ FROM event_settings
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, guild.getIdLong());
+
+ var result = statement.executeQuery();
+ result.next();
+ return result.getLong(1);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String getVoteEmoji(Guild guild) {
+ log.debug("Querying vote emoji");
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT contest_vote_emoji
+ FROM event_settings
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, guild.getIdLong());
+
+ var result = statement.executeQuery();
+ result.next();
+ return result.getString(1);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void startContestEvent(TextChannel channel, String emoji) {
+ log.debug("Starting new contest event in {} with vote emoji {}", channel, emoji);
+ try (Connection connection = dataSource.getConnection()) {
+ log.debug("Truncating old votes");
+ connection.prepareStatement("TRUNCATE TABLE contest_entries;").execute();
+
+ var statement = connection.prepareStatement("""
+ UPDATE event_settings
+ SET contest_channel_id = ?,
+ contest_vote_emoji = ?
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, channel.getIdLong());
+ statement.setString(2, emoji);
+ statement.setLong(3, channel.getGuild().getIdLong());
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public List stopContestEvent(Guild guild) {
+ log.debug("Stopping current contest event");
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ UPDATE event_settings
+ SET contest_channel_id = -1,
+ contest_vote_emoji = ''
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, guild.getIdLong());
+ statement.execute();
+
+ log.debug("Querying top 10 entries");
+ statement = connection.prepareStatement("""
+ SELECT user_id, votes
+ FROM contest_entries
+ ORDER BY votes DESC LIMIT 10
+ """
+ );
+ List users = new ArrayList<>();
+ var result = statement.executeQuery();
+ while (result.next()) {
+ users.add(new ContestLeaderboardRow(result.getInt("votes"), result.getLong("user_id")));
+ }
+ return users;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean createContestEntry(Message message) {
+ log.debug("Inserting contest entry: {}", message);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("INSERT INTO contest_entries VALUES(?, 0, ?) ON CONFLICT DO NOTHING");
+ statement.setLong(1, message.getAuthor().getIdLong());
+ statement.setLong(2, message.getIdLong());
+ return statement.executeUpdate() > 0;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void deleteContestEntry(long messageId) {
+ log.debug("Deleting contest entry: {}", messageId);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("DELETE FROM contest_entries WHERE message_id = ?");
+ statement.setLong(1, messageId);
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Increases the vote count for a contest entry.
+ *
+ * @param messageId the message id representing the contest entry
+ * @param userId the id of the user that voted for the entry
+ */
+ public void increaseVoteCount(long messageId, long userId) {
+ log.debug("Increasing total votes for {} by one", messageId);
+ try (Connection connection = dataSource.getConnection()) {
+ // this AND clause prevents a self vote of the message author
+ var statement = connection.prepareStatement("UPDATE contest_entries SET votes = votes + 1 where message_id = ? AND user_id != ?");
+ statement.setLong(1, messageId);
+ statement.setLong(2, userId);
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Decreases the vote count for a contest entry.
+ *
+ * @param messageId the message id representing the contest entry
+ * @param userId the id of the user that removed his vote for the entry
+ */
+ public void decreaseVoteCount(long messageId, long userId) {
+ log.debug("Decreasing total votes for {} by one", messageId);
+ try (Connection connection = dataSource.getConnection()) {
+ // this AND clause prevents a self vote of the message author
+ var statement = connection.prepareStatement("UPDATE contest_entries SET votes = votes - 1 where message_id = ? AND user_id != ?");
+ statement.setLong(1, messageId);
+ statement.setLong(2, userId);
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public record ContestLeaderboardRow(int votes, long userId) {
+ }
+
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestListener.java b/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestListener.java
new file mode 100644
index 0000000..6713bc5
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestListener.java
@@ -0,0 +1,104 @@
+package com.github.kaktushose.nplaybot.events.contest;
+
+import net.dv8tion.jda.api.entities.emoji.Emoji;
+import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
+import net.dv8tion.jda.api.events.message.react.MessageReactionRemoveAllEvent;
+import net.dv8tion.jda.api.events.message.react.MessageReactionRemoveEmojiEvent;
+import net.dv8tion.jda.api.events.message.react.MessageReactionRemoveEvent;
+import net.dv8tion.jda.api.hooks.ListenerAdapter;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ContestListener extends ListenerAdapter {
+
+ private static final Logger log = LoggerFactory.getLogger(ContestListener.class);
+ private final ContestEventService eventService;
+
+ public ContestListener(ContestEventService eventService) {
+ this.eventService = eventService;
+ }
+
+ @Override
+ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
+ if (!event.isFromGuild()) {
+ return;
+ }
+ if (event.getChannel().getIdLong() != eventService.getContestEventChannel(event.getGuild())) {
+ return;
+ }
+ if (event.getAuthor().isBot()) {
+ return;
+ }
+
+ if (eventService.createContestEntry(event.getMessage())) {
+ log.debug("Created new contest entry: {}", event.getMessage());
+ event.getMessage().addReaction(Emoji.fromFormatted(eventService.getVoteEmoji(event.getGuild()))).queue();
+ } else {
+ log.debug("User already has a contest entry, deleting message");
+ event.getMessage().delete().queue();
+ }
+ }
+
+ @Override
+ public void onMessageDelete(@NotNull MessageDeleteEvent event) {
+ eventService.deleteContestEntry(event.getMessageIdLong());
+ }
+
+ @Override
+ public void onMessageReactionAdd(@NotNull MessageReactionAddEvent event) {
+ if (event.getChannel().getIdLong() != eventService.getContestEventChannel(event.getGuild())) {
+ return;
+ }
+ if (event.getUser().isBot()) {
+ return;
+ }
+ if (event.getUser().getIdLong() == event.getMessageAuthorIdLong()) {
+ log.debug("Removing self vote from contest entry");
+ event.retrieveMessage().flatMap(message -> message.removeReaction(event.getEmoji(), event.getUser())).queue();
+ return;
+ }
+ if (!event.getEmoji().equals(Emoji.fromFormatted(eventService.getVoteEmoji(event.getGuild())))) {
+ log.debug("Removing invalid emoji from contest entry");
+ event.retrieveMessage().flatMap(message -> message.removeReaction(event.getEmoji(), event.getUser())).queue();
+ return;
+ }
+ eventService.increaseVoteCount(event.getMessageIdLong(), event.getUserIdLong());
+ }
+
+ @Override
+ public void onMessageReactionRemove(@NotNull MessageReactionRemoveEvent event) {
+ if (event.getChannel().getIdLong() != eventService.getContestEventChannel(event.getGuild())) {
+ return;
+ }
+ if (event.getUser().isBot()) {
+ return;
+ }
+ if (!event.getEmoji().equals(Emoji.fromFormatted(eventService.getVoteEmoji(event.getGuild())))) {
+ return;
+ }
+ eventService.decreaseVoteCount(event.getMessageIdLong(), event.getUserIdLong());
+ }
+
+ @Override
+ public void onMessageReactionRemoveEmoji(@NotNull MessageReactionRemoveEmojiEvent event) {
+ if (!event.getEmoji().equals(Emoji.fromFormatted(eventService.getVoteEmoji(event.getGuild())))) {
+ return;
+ }
+ log.debug("Detected removal of all vote emojis. Adding initial emoji again");
+ event.getChannel().retrieveMessageById(event.getMessageId()).flatMap(message ->
+ message.addReaction(Emoji.fromFormatted(eventService.getVoteEmoji(event.getGuild())))
+ ).queue();
+
+ }
+
+ @Override
+ public void onMessageReactionRemoveAll(@NotNull MessageReactionRemoveAllEvent event) {
+ log.debug("Detected removal of all vote emojis. Adding initial emoji again");
+ event.getChannel().retrieveMessageById(event.getMessageId()).flatMap(message ->
+ message.addReaction(Emoji.fromFormatted(eventService.getVoteEmoji(event.getGuild())))
+ ).queue();
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
index e4d6020..c1766c1 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
@@ -6,7 +6,6 @@
import com.github.kaktushose.nplaybot.settings.SettingsService;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
@@ -128,7 +127,7 @@ public void onMessageReactionAdd(@NotNull MessageReactionAddEvent event) {
.injectValue("user", event.getMember().getAsMention())
.injectValue("xp", xp)
.toMessageCreateData()
- ).queue(it -> it.delete().queueAfter(10, TimeUnit.SECONDS));
+ ).mentionRepliedUser(false).queue(it -> it.delete().queueAfter(10, TimeUnit.SECONDS));
message.clearReactions().queue();
});
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 194ee0c..770c75f 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -4,10 +4,10 @@
import com.github.kaktushose.nplaybot.rank.model.RankInfo;
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
-import net.dv8tion.jda.api.entities.*;
-import net.dv8tion.jda.api.entities.channel.Channel;
-import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
-import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.UserSnowflake;
import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -19,7 +19,7 @@
public class RankService {
- private static final Logger log = LoggerFactory.getLogger(RankListener.class);
+ private static final Logger log = LoggerFactory.getLogger(RankService.class);
private final DataSource dataSource;
public RankService(DataSource dataSource) {
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java
index 0c64b3b..c8c1376 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java
@@ -1,14 +1,13 @@
package com.github.kaktushose.nplaybot.rank.leaderboard;
import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.exceptions.ErrorHandler;
+import net.dv8tion.jda.api.requests.ErrorResponse;
import java.util.List;
import java.util.Optional;
public record LeaderboardPage(List rows) {
- public record LeaderboardRow(int xp, long userId, long roleId) {
- }
-
public String getPage(Guild guild) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < rows.size(); i++) {
@@ -28,8 +27,11 @@ private String resolveName(Guild guild, long userId) {
return member.get().getEffectiveName();
}
// retrieve member thus it gets loaded to cache
- guild.retrieveMemberById(userId).queue();
+ guild.retrieveMemberById(userId).queue(null, new ErrorHandler().ignore(ErrorResponse.UNKNOWN_MEMBER));
return String.format("<@%d>", userId);
}
+ public record LeaderboardRow(int xp, long userId, long roleId) {
+ }
+
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java b/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java
index 72debcf..c21c572 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/settings/SettingsService.java
@@ -2,6 +2,8 @@
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.sql.Connection;
@@ -9,6 +11,7 @@
public class SettingsService {
+ private static final Logger log = LoggerFactory.getLogger(SettingsService.class);
private final DataSource dataSource;
public SettingsService(DataSource dataSource) {
@@ -16,6 +19,7 @@ public SettingsService(DataSource dataSource) {
}
public String getBotToken(long guildId) {
+ log.debug("Querying bot token");
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
SELECT bot_token
@@ -34,6 +38,7 @@ public String getBotToken(long guildId) {
}
public TextChannel getBotChannel(Guild guild) {
+ log.debug("Querying bot channel");
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
SELECT bot_channel_id
diff --git a/src/main/resources/db/migration/V2.0.0__setup_event_system.sql b/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
new file mode 100644
index 0000000..fdae2f8
--- /dev/null
+++ b/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
@@ -0,0 +1,10 @@
+CREATE TABLE event_settings (
+ guild_id BIGINT NOT NULL PRIMARY KEY,
+ contest_channel_id BIGINT NOT NULL DEFAULT 0,
+ contest_vote_emoji VARCHAR
+);
+CREATE TABLE contest_entries (
+ user_id BIGINT NOT NULL PRIMARY KEY,
+ votes INT NOT NULL DEFAULT 0,
+ message_id BIGINT NOT NULL
+);
From 31f58a6aa5403b36c39fe7134e4187e5e2d12f55 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Wed, 24 Apr 2024 17:42:10 +0200
Subject: [PATCH 38/66] implement rank config commands
---
embeds.json | 11 ++
.../kaktushose/nplaybot/rank/RankService.java | 116 ++++++++++++++++++
.../rank/commands/RankConfigCommands.java | 73 +++++++++++
.../nplaybot/rank/model/RankConfig.java | 4 +
4 files changed, 204 insertions(+)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/rank/model/RankConfig.java
diff --git a/embeds.json b/embeds.json
index c190376..6b8b5e3 100644
--- a/embeds.json
+++ b/embeds.json
@@ -124,5 +124,16 @@
"title": "Leaderboard",
"description": "{leaderboard}",
"color": "#67c94f"
+ },
+ "rankConfig": {
+ "title": "Rank Configuration",
+ "description": "Cooldown: `{cooldown}ms`\nNachrichtenlänge: `{minLength} Buchstaben`\nXP Loot Wahrscheinlichkeit: `{lootChance}%`\n",
+ "color": "#67c94f"
+
+ },
+ "validChannels": {
+ "title": "Gewertete Textkanäle",
+ "description": "{channels}",
+ "color": "#67c94f"
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index 770c75f..ae5563c 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -1,6 +1,7 @@
package com.github.kaktushose.nplaybot.rank;
import com.github.kaktushose.nplaybot.rank.leaderboard.LeaderboardPage;
+import com.github.kaktushose.nplaybot.rank.model.RankConfig;
import com.github.kaktushose.nplaybot.rank.model.RankInfo;
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
@@ -108,6 +109,121 @@ public UserInfo getUserInfo(UserSnowflake user) {
}
}
+ public RankConfig getRankConfig(Guild guild) {
+ log.debug("Querying rank config for guild: {}", guild);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT message_cooldown, min_message_length, xp_loot_chance
+ FROM rank_settings
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, guild.getIdLong());
+
+ var result = statement.executeQuery();
+ result.next();
+
+ return new RankConfig(
+ result.getInt("message_cooldown"),
+ result.getInt("min_message_length"),
+ result.getDouble("xp_loot_chance")
+ );
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void updateCooldown(Guild guild, int cooldown) {
+ log.debug("Updating cooldown for guild: {}", guild);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ UPDATE rank_settings
+ SET message_cooldown = ?
+ WHERE guild_id = ?
+ """
+ );
+ statement.setInt(1, cooldown);
+ statement.setLong(2, guild.getIdLong());
+
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void updateMinMessageLength(Guild guild, int length) {
+ log.debug("Updating minimum message length for guild: {}", guild);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ UPDATE rank_settings
+ SET min_message_length = ?
+ WHERE guild_id = ?
+ """
+ );
+ statement.setInt(1, length);
+ statement.setLong(2, guild.getIdLong());
+
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void updateXpLootChance(Guild guild, double chance) {
+ log.debug("Updating xp loot chance for guild: {}", guild);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ UPDATE rank_settings
+ SET xp_loot_chance = ?
+ WHERE guild_id = ?
+ """
+ );
+ statement.setDouble(1, chance);
+ statement.setLong(2, guild.getIdLong());
+
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Set getValidChannels(Guild guild) {
+ log.debug("Querying valid channels for guild {}", guild);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT valid_channels
+ FROM rank_settings
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, guild.getIdLong());
+
+ var result = statement.executeQuery();
+ result.next();
+ return new HashSet<>(Arrays.asList((Long[]) result.getArray("valid_channels").getArray()));
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void updateValidChannels(Guild guild, Set validChannels) {
+ log.debug("Querying valid channels for guild {}", guild);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ UPDATE rank_settings
+ SET valid_channels = ?
+ WHERE guild_id = ?
+ """
+ );
+ statement.setArray(1, connection.createArrayOf("BIGINT", validChannels.toArray()));
+ statement.setLong(2, guild.getIdLong());
+
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
public boolean isValidMessage(Message message) {
log.debug("Checking message: {}", message);
try (Connection connection = dataSource.getConnection()) {
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java
new file mode 100644
index 0000000..b59933d
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java
@@ -0,0 +1,73 @@
+package com.github.kaktushose.nplaybot.rank.commands;
+
+import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.constraints.Max;
+import com.github.kaktushose.jda.commands.annotations.constraints.Min;
+import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.Param;
+import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.nplaybot.Database;
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+
+@Interaction
+public class RankConfigCommands {
+
+ @Inject
+ private Database database;
+ @Inject
+ private EmbedCache embedCache;
+
+ @SlashCommand(value = "rank config", desc = "Zeigt die Einstellungen für das Rank System an", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onGetRankConfig(CommandEvent event) {
+ event.reply(embedCache.getEmbed("rankConfig").injectFields(database.getRankService().getRankConfig(event.getGuild())));
+ }
+
+ @SlashCommand(value = "set cooldown", desc = "Legt den Cooldown für gewertete Nachrichten fest", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onSetCooldown(CommandEvent event, @Param("Die Dauer in Millisekunden") @Min(0) @Max(Integer.MAX_VALUE) int cooldown) {
+ database.getRankService().updateCooldown(event.getGuild(), cooldown);
+ event.reply(embedCache.getEmbed("rankConfig").injectFields(database.getRankService().getRankConfig(event.getGuild())));
+ }
+
+ @SlashCommand(value = "set message length", desc = "Legt die Mindestlänge für gewertete Nachrichten fest", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onSetMinMessageLength(CommandEvent event, @Param("Die Mindestanzahl an Buchstaben pro Nachricht") @Min(0) @Max(Integer.MAX_VALUE) int length) {
+ database.getRankService().updateMinMessageLength(event.getGuild(), length);
+ event.reply(embedCache.getEmbed("rankConfig").injectFields(database.getRankService().getRankConfig(event.getGuild())));
+ }
+
+ @SlashCommand(value = "set loot chance", desc = "Legt die Wahrscheinlichkeit für zufällige XP-Loot-Drops fest", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onSetXpLootDropChance(CommandEvent event, @Param("Die Wahrscheinlichkeit in Prozent") @Min(1) @Max(100) double chance) {
+ database.getRankService().updateXpLootChance(event.getGuild(), chance);
+ event.reply(embedCache.getEmbed("rankConfig").injectFields(database.getRankService().getRankConfig(event.getGuild())));
+ }
+
+ @SlashCommand(value = "valid channels list", desc = "Zeigt die Textkanäle an, in denen Nachrichten gewertet werden", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onValidChannelsList(CommandEvent event) {
+ var channels = database.getRankService().getValidChannels(event.getGuild());
+ StringBuilder result = new StringBuilder();
+ channels.forEach(it -> result.append(String.format("<#%d>", it)).append("\n"));
+ event.reply(embedCache.getEmbed("validChannels").injectValue("channels", result));
+ }
+
+ @SlashCommand(value = "valid channels add", desc = "Fügt einen Textkanal zu der Liste der gewerteten Kanäle hinzu", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onValidChannelsAdd(CommandEvent event, @Param("Der Kanal der gewertet werden soll") TextChannel channel) {
+ var channels = database.getRankService().getValidChannels(event.getGuild());
+ channels.add(channel.getIdLong());
+ database.getRankService().updateValidChannels(event.getGuild(), channels);
+ StringBuilder result = new StringBuilder();
+ channels.forEach(it -> result.append(String.format("<#%d>", it)).append("\n"));
+ event.reply(embedCache.getEmbed("validChannels").injectValue("channels", result));
+ }
+
+ @SlashCommand(value = "valid channels remove", desc = "Entfernt einen Textkanal von der Liste der gewerteten Kanäle", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onValidChannelsRemove(CommandEvent event, @Param("Der Kanal der nicht mehr gewertet werden soll") TextChannel channel) {
+ var channels = database.getRankService().getValidChannels(event.getGuild());
+ channels.remove(channel.getIdLong());
+ database.getRankService().updateValidChannels(event.getGuild(), channels);
+ StringBuilder result = new StringBuilder();
+ channels.forEach(it -> result.append(String.format("<#%d>", it)).append("\n"));
+ event.reply(embedCache.getEmbed("validChannels").injectValue("channels", result));
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/RankConfig.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/RankConfig.java
new file mode 100644
index 0000000..020668c
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/RankConfig.java
@@ -0,0 +1,4 @@
+package com.github.kaktushose.nplaybot.rank.model;
+
+public record RankConfig(int cooldown, int minLength, double lootChance) {
+}
From 97ddbc8773e46143e62cad18e27a78a7f6c5c3a1 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Wed, 24 Apr 2024 17:49:59 +0200
Subject: [PATCH 39/66] remove old files
---
src/main/resources/jdac.properties | 2 --
1 file changed, 2 deletions(-)
delete mode 100644 src/main/resources/jdac.properties
diff --git a/src/main/resources/jdac.properties b/src/main/resources/jdac.properties
deleted file mode 100644
index 90de9ec..0000000
--- a/src/main/resources/jdac.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-prefix=!
-helpLabels=hilfe, help
From 86b34118c9b37fe5dc77a976d362d0f38e03f2ce Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Wed, 24 Apr 2024 21:38:35 +0200
Subject: [PATCH 40/66] implement permissions system
---
embeds.json | 10 +++
.../com/github/kaktushose/nplaybot/Bot.java | 2 +
.../github/kaktushose/nplaybot/Database.java | 7 ++
.../events/contest/ContestCommands.java | 3 +
.../internal/MaintenanceCommands.java | 3 +
.../nplaybot/permissions/BotPermissions.java | 61 +++++++++++++
.../CustomPermissionsProvider.java | 27 ++++++
.../permissions/PermissionCommands.java | 86 +++++++++++++++++++
.../permissions/PermissionsService.java | 83 ++++++++++++++++++
.../rank/commands/ModifyXpCommands.java | 3 +
.../rank/commands/RankConfigCommands.java | 5 +-
.../rank/commands/RankInfoCommand.java | 3 +
.../rank/leaderboard/LeaderboardCommand.java | 7 +-
.../migration/V2.0.0__setup_event_system.sql | 1 +
14 files changed, 297 insertions(+), 4 deletions(-)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/permissions/BotPermissions.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/permissions/CustomPermissionsProvider.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionCommands.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionsService.java
diff --git a/embeds.json b/embeds.json
index 6b8b5e3..e4d4915 100644
--- a/embeds.json
+++ b/embeds.json
@@ -135,5 +135,15 @@
"title": "Gewertete Textkanäle",
"description": "{channels}",
"color": "#67c94f"
+ },
+ "userPermissions": {
+ "title": "Berechtigungen von {user}",
+ "description": "{permissions}",
+ "color": "#67c94f"
+ },
+ "permissionsBulkEdit": {
+ "title": "Erfolg",
+ "description": "Die Berechtigungen wurden angepasst",
+ "color": "#67c94f"
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index 9cc8730..dbacc56 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -4,6 +4,7 @@
import com.github.kaktushose.jda.commands.annotations.Produces;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.nplaybot.events.contest.ContestListener;
+import com.github.kaktushose.nplaybot.permissions.CustomPermissionsProvider;
import com.github.kaktushose.nplaybot.rank.JoinLeaveListener;
import com.github.kaktushose.nplaybot.rank.RankListener;
import com.github.kaktushose.nplaybot.scheduler.TaskScheduler;
@@ -54,6 +55,7 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
jdaCommands = JDACommands.start(jda, Bot.class, "com.github.kaktushose.nplaybot");
jdaCommands.getDependencyInjector().registerProvider(this);
+ jdaCommands.getImplementationRegistry().setPermissionsProvider(new CustomPermissionsProvider(database));
taskScheduler = new TaskScheduler(this);
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Database.java b/src/main/java/com/github/kaktushose/nplaybot/Database.java
index 617fdf4..422ea04 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Database.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Database.java
@@ -1,6 +1,7 @@
package com.github.kaktushose.nplaybot;
import com.github.kaktushose.nplaybot.events.contest.ContestEventService;
+import com.github.kaktushose.nplaybot.permissions.PermissionsService;
import com.github.kaktushose.nplaybot.rank.RankService;
import com.github.kaktushose.nplaybot.settings.SettingsService;
import com.zaxxer.hikari.HikariConfig;
@@ -12,6 +13,7 @@ public class Database {
private final SettingsService settingsService;
private final RankService rankService;
private final ContestEventService contestEventService;
+ private final PermissionsService permissionsService;
public Database() {
var config = new HikariConfig();
@@ -26,6 +28,7 @@ public Database() {
settingsService = new SettingsService(dataSource);
rankService = new RankService(dataSource);
contestEventService = new ContestEventService(dataSource);
+ permissionsService = new PermissionsService(dataSource);
}
public void closeDataSource() {
@@ -43,4 +46,8 @@ public RankService getRankService() {
public ContestEventService getContestEventService() {
return contestEventService;
}
+
+ public PermissionsService getPermissionsService() {
+ return permissionsService;
+ }
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestCommands.java b/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestCommands.java
index bf0a53c..b9f17dd 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestCommands.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestCommands.java
@@ -3,10 +3,12 @@
import com.github.kaktushose.jda.commands.annotations.Inject;
import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
import com.github.kaktushose.jda.commands.annotations.interactions.Param;
+import com.github.kaktushose.jda.commands.annotations.interactions.Permissions;
import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.permissions.BotPermissions;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
@@ -14,6 +16,7 @@
import java.util.Optional;
@Interaction
+@Permissions(BotPermissions.MANAGE_EVENTS)
public class ContestCommands {
@Inject
diff --git a/src/main/java/com/github/kaktushose/nplaybot/internal/MaintenanceCommands.java b/src/main/java/com/github/kaktushose/nplaybot/internal/MaintenanceCommands.java
index 25fd2dd..f321c07 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/internal/MaintenanceCommands.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/internal/MaintenanceCommands.java
@@ -2,12 +2,15 @@
import com.github.kaktushose.jda.commands.annotations.Inject;
import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.Permissions;
import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.nplaybot.permissions.BotPermissions;
import net.dv8tion.jda.api.Permission;
@Interaction
+@Permissions(BotPermissions.BOT_ADMINISTRATOR)
public class MaintenanceCommands {
@Inject
diff --git a/src/main/java/com/github/kaktushose/nplaybot/permissions/BotPermissions.java b/src/main/java/com/github/kaktushose/nplaybot/permissions/BotPermissions.java
new file mode 100644
index 0000000..825560f
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/permissions/BotPermissions.java
@@ -0,0 +1,61 @@
+package com.github.kaktushose.nplaybot.permissions;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class BotPermissions {
+
+ public static final String USER = "USER";
+ public static final String MODIFY_USER_BALANCE = "MODIFY_USER_BALANCE";
+ public static final String MODIFY_RANK_SETTINGS = "MODIFY_RANK_SETTINGS";
+ public static final String MANAGE_EVENTS = "MANAGE_EVENTS";
+ public static final String MODIFY_USER_PERMISSIONS = "MODIFY_USER_PERMISSIONS";
+ public static final String BOT_ADMINISTRATOR = "BOT_ADMINISTRATOR";
+ public static final String BOT_OWNER = "BOT_OWNER";
+
+ @SuppressWarnings("PointlessBitwiseExpression")
+ private static final Map permissionMapping = new LinkedHashMap<>() {{
+ put(USER, 1 << 0);
+ put(MODIFY_USER_BALANCE, 1 << 1);
+ put(MODIFY_RANK_SETTINGS, 1 << 2);
+ put(MANAGE_EVENTS, 1 << 3);
+ put(MODIFY_USER_PERMISSIONS, 1 << 4);
+ put(BOT_ADMINISTRATOR, 1 << 5);
+ put(BOT_OWNER, 1 << 8);
+ }};
+
+
+ public static int compute(Set permissions) {
+ int computedPermissions = 0;
+ for (String permission : permissions) {
+ computedPermissions = computedPermissions | permissionMapping.getOrDefault(permission, 0);
+ }
+ return computedPermissions;
+ }
+
+ public static boolean hasPermissions(Set permissions, int userPermission) {
+ if (userPermission == permissionMapping.get(BOT_OWNER)) {
+ return true;
+ }
+ return (userPermission & compute(permissions)) != 0;
+ }
+
+ public static int grant(int currentPermissions, String permission) {
+ return currentPermissions |= permissionMapping.getOrDefault(permission, 0);
+ }
+
+ public static int revoke(int currentPermissions, String permission) {
+ return currentPermissions &= ~permissionMapping.getOrDefault(permission, 0);
+ }
+
+ public static String listPermissions(int permissions) {
+ StringBuilder result = new StringBuilder();
+ permissionMapping.forEach((name, value) -> {
+ if (hasPermissions(Set.of(name), permissions)) {
+ result.append(String.format("`%s`", name)).append("\n");
+ }
+ });
+ return result.toString();
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/permissions/CustomPermissionsProvider.java b/src/main/java/com/github/kaktushose/nplaybot/permissions/CustomPermissionsProvider.java
new file mode 100644
index 0000000..8b87e13
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/permissions/CustomPermissionsProvider.java
@@ -0,0 +1,27 @@
+package com.github.kaktushose.nplaybot.permissions;
+
+import com.github.kaktushose.jda.commands.dispatching.interactions.Context;
+import com.github.kaktushose.jda.commands.permissions.PermissionsProvider;
+import com.github.kaktushose.nplaybot.Database;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import org.jetbrains.annotations.NotNull;
+
+public class CustomPermissionsProvider implements PermissionsProvider {
+
+ private final Database database;
+
+ public CustomPermissionsProvider(Database database) {
+ this.database = database;
+ }
+
+ @Override
+ public boolean hasPermission(@NotNull User user, @NotNull Context context) {
+ return database.getPermissionsService().hasPermissions(user, context.getInteractionDefinition().getPermissions());
+ }
+
+ @Override
+ public boolean hasPermission(@NotNull Member member, @NotNull Context context) {
+ return database.getPermissionsService().hasPermissions(member, context.getInteractionDefinition().getPermissions());
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionCommands.java b/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionCommands.java
new file mode 100644
index 0000000..36402ba
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionCommands.java
@@ -0,0 +1,86 @@
+package com.github.kaktushose.nplaybot.permissions;
+
+import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.interactions.*;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.nplaybot.Database;
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.Role;
+
+import static com.github.kaktushose.nplaybot.permissions.BotPermissions.*;
+
+@Interaction
+public class PermissionCommands {
+
+ @Inject
+ private Database database;
+ @Inject
+ private EmbedCache embedCache;
+
+ @SlashCommand(value = "permissions list", desc = "Zeigt die Berechtigungen eines Users an", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @Permissions(USER)
+ public void onPermissionsList(CommandEvent event, @Optional Member member) {
+ var target = member == null ? event.getMember() : member;
+
+ event.reply(embedCache.getEmbed("userPermissions")
+ .injectValue("user", target.getEffectiveName())
+ .injectValue("permissions", BotPermissions.listPermissions(database.getPermissionsService().getPermissions(target)))
+ );
+ }
+
+ @SlashCommand(value = "permissions grant", desc = "Fügt einem Nutzer eine Berechtigung hinzu", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @Permissions(MODIFY_USER_PERMISSIONS)
+ public void onPermissionsGrant(CommandEvent event,
+ Member member,
+ @Param("Die Berechtigung die hinzugefügt werden soll")
+ @Choices({USER, MODIFY_USER_BALANCE, MODIFY_RANK_SETTINGS, MANAGE_EVENTS, MODIFY_USER_PERMISSIONS, BOT_ADMINISTRATOR})
+ String permission) {
+ database.getPermissionsService().grantPermissions(member, permission);
+
+ event.reply(embedCache.getEmbed("userPermissions")
+ .injectValue("user", member.getEffectiveName())
+ .injectValue("permissions", BotPermissions.listPermissions(database.getPermissionsService().getPermissions(member)))
+ );
+ }
+
+ @SlashCommand(value = "permissions revoke", desc = "Entzieht einem Nutzer eine Berechtigung", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @Permissions(MODIFY_USER_PERMISSIONS)
+ public void onPermissionsRevoke(CommandEvent event,
+ Member member,
+ @Param("Die Berechtigung die entzogen werden soll")
+ @Choices({USER, MODIFY_USER_BALANCE, MODIFY_RANK_SETTINGS, MANAGE_EVENTS, MODIFY_USER_PERMISSIONS, BOT_ADMINISTRATOR})
+ String permission) {
+ database.getPermissionsService().revokePermissions(member, permission);
+
+ event.reply(embedCache.getEmbed("userPermissions")
+ .injectValue("user", member.getEffectiveName())
+ .injectValue("permissions", BotPermissions.listPermissions(database.getPermissionsService().getPermissions(member)))
+ );
+ }
+
+ @SlashCommand(value = "permissions bulk grant", desc = "Fügt allen Nutzern mit der angegebenen Rolle eine Berechtigung hinzu", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @Permissions(MODIFY_USER_PERMISSIONS)
+ public void onPermissionsBulkGrant(CommandEvent event,
+ Role role,
+ @Param("Die Berechtigung die hinzugefügt werden soll")
+ @Choices({USER, MODIFY_USER_BALANCE, MODIFY_RANK_SETTINGS, MANAGE_EVENTS, MODIFY_USER_PERMISSIONS, BOT_ADMINISTRATOR})
+ String permission) {
+ event.getGuild().getMembersWithRoles(role).forEach(member -> database.getPermissionsService().grantPermissions(member, permission));
+
+ event.reply(embedCache.getEmbed("permissionsBulkEdit"));
+ }
+
+ @SlashCommand(value = "permissions bulk revoke", desc = "Entzieht allen Nutzern mit der angegebenen Rolle eine Berechtigung", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @Permissions(MODIFY_USER_PERMISSIONS)
+ public void onPermissionsBulkRevoke(CommandEvent event,
+ Role role,
+ @Param("Die Berechtigung die entzogen werden soll")
+ @Choices({USER, MODIFY_USER_BALANCE, MODIFY_RANK_SETTINGS, MANAGE_EVENTS, MODIFY_USER_PERMISSIONS, BOT_ADMINISTRATOR})
+ String permission) {
+ event.getGuild().getMembersWithRoles(role).forEach(member -> database.getPermissionsService().revokePermissions(member, permission));
+
+ event.reply(embedCache.getEmbed("permissionsBulkEdit"));
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionsService.java b/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionsService.java
new file mode 100644
index 0000000..1c855ec
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionsService.java
@@ -0,0 +1,83 @@
+package com.github.kaktushose.nplaybot.permissions;
+
+import net.dv8tion.jda.api.entities.UserSnowflake;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Set;
+
+public class PermissionsService {
+
+ private static final Logger log = LoggerFactory.getLogger(PermissionsService.class);
+ private final DataSource dataSource;
+
+ public PermissionsService(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public int getPermissions(UserSnowflake user) {
+ log.debug("Querying permissions for user {}", user);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT permissions
+ FROM users
+ WHERE user_id = ?
+ """
+ );
+ statement.setLong(1, user.getIdLong());
+
+ var result = statement.executeQuery();
+ result.next();
+ return result.getInt(1);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void grantPermissions(UserSnowflake user, String permission) {
+ log.warn("Granting permission {} for user {}", permission, user);
+ try (Connection connection = dataSource.getConnection()) {
+ PreparedStatement statement = connection.prepareStatement("""
+ UPDATE users
+ SET permissions = ?
+ WHERE user_id = ?
+ """
+ );
+
+ statement.setLong(1, BotPermissions.grant(getPermissions(user), permission));
+ statement.setLong(2, user.getIdLong());
+
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void revokePermissions(UserSnowflake user, String permission) {
+ log.warn("Revoking permission {} for user {}", permission, user);
+ try (Connection connection = dataSource.getConnection()) {
+ PreparedStatement statement = connection.prepareStatement("""
+ UPDATE users
+ SET permissions = ?
+ WHERE user_id = ?
+ """
+ );
+
+ statement.setLong(1, BotPermissions.revoke(getPermissions(user), permission));
+ statement.setLong(2, user.getIdLong());
+
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean hasPermissions(UserSnowflake user, Set permissions) {
+ log.debug("Checking permissions for user {}", user);
+ return BotPermissions.hasPermissions(permissions, getPermissions(user));
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java
index 70474cc..43fc817 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/ModifyXpCommands.java
@@ -4,10 +4,12 @@
import com.github.kaktushose.jda.commands.annotations.constraints.Max;
import com.github.kaktushose.jda.commands.annotations.constraints.Min;
import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.Permissions;
import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.permissions.BotPermissions;
import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
@@ -17,6 +19,7 @@
import org.slf4j.LoggerFactory;
@Interaction(ephemeral = true)
+@Permissions(BotPermissions.MODIFY_USER_BALANCE)
public class ModifyXpCommands {
private static final Logger log = LoggerFactory.getLogger(ModifyXpCommands.class);
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java
index b59933d..0ca05ca 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java
@@ -5,14 +5,17 @@
import com.github.kaktushose.jda.commands.annotations.constraints.Min;
import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
import com.github.kaktushose.jda.commands.annotations.interactions.Param;
+import com.github.kaktushose.jda.commands.annotations.interactions.Permissions;
import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.permissions.BotPermissions;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
@Interaction
+@Permissions(BotPermissions.MODIFY_RANK_SETTINGS)
public class RankConfigCommands {
@Inject
@@ -20,7 +23,7 @@ public class RankConfigCommands {
@Inject
private EmbedCache embedCache;
- @SlashCommand(value = "rank config", desc = "Zeigt die Einstellungen für das Rank System an", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @SlashCommand(value = "get rank config", desc = "Zeigt die Einstellungen für das Rank System an", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
public void onGetRankConfig(CommandEvent event) {
event.reply(embedCache.getEmbed("rankConfig").injectFields(database.getRankService().getRankConfig(event.getGuild())));
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
index 53c6b78..449e0dd 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
@@ -3,14 +3,17 @@
import com.github.kaktushose.jda.commands.annotations.Inject;
import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
import com.github.kaktushose.jda.commands.annotations.interactions.Optional;
+import com.github.kaktushose.jda.commands.annotations.interactions.Permissions;
import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.permissions.BotPermissions;
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import net.dv8tion.jda.api.entities.Member;
@Interaction
+@Permissions(BotPermissions.USER)
public class RankInfoCommand {
@Inject
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
index 25f56d5..b320d37 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
@@ -3,6 +3,7 @@
import com.github.kaktushose.jda.commands.annotations.Inject;
import com.github.kaktushose.jda.commands.annotations.interactions.Button;
import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.Permissions;
import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
@@ -11,6 +12,7 @@
import com.github.kaktushose.jda.commands.dispatching.reply.components.Buttons;
import com.github.kaktushose.jda.commands.dispatching.reply.components.Component;
import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.permissions.BotPermissions;
import net.dv8tion.jda.api.entities.Guild;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -19,16 +21,15 @@
@Interaction
+@Permissions(BotPermissions.USER)
public class LeaderboardCommand {
private static final Logger log = LoggerFactory.getLogger(LeaderboardCommand.class);
-
+ private final int minIndex = 1;
@Inject
private Database database;
@Inject
private EmbedCache embedCache;
-
- private final int minIndex = 1;
private int index = 1;
private int maxIndex;
private List leaderboard;
diff --git a/src/main/resources/db/migration/V2.0.0__setup_event_system.sql b/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
index fdae2f8..8bf9287 100644
--- a/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
+++ b/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
@@ -8,3 +8,4 @@ CREATE TABLE contest_entries (
votes INT NOT NULL DEFAULT 0,
message_id BIGINT NOT NULL
);
+ALTER TABLE users ADD COLUMN permissions INTEGER DEFAULT 1;
From a9b167d19a0192786e7cfd4094a7870e993e1761 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Wed, 24 Apr 2024 21:49:07 +0200
Subject: [PATCH 41/66] add context command for rank info
---
.../nplaybot/rank/commands/RankInfoCommand.java | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
index 449e0dd..33abb34 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
@@ -1,16 +1,15 @@
package com.github.kaktushose.nplaybot.rank.commands;
import com.github.kaktushose.jda.commands.annotations.Inject;
-import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
-import com.github.kaktushose.jda.commands.annotations.interactions.Optional;
-import com.github.kaktushose.jda.commands.annotations.interactions.Permissions;
-import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
+import com.github.kaktushose.jda.commands.annotations.interactions.*;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
import com.github.kaktushose.nplaybot.Database;
import com.github.kaktushose.nplaybot.permissions.BotPermissions;
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.interactions.commands.Command;
@Interaction
@Permissions(BotPermissions.USER)
@@ -22,11 +21,19 @@ public class RankInfoCommand {
private EmbedCache embedCache;
@SlashCommand(value = "rank", isGuildOnly = true, desc = "Zeigt die Kontoinformationen zu einem User an")
- public void onCommand(CommandEvent event, @Optional Member member) {
+ public void onRankInfo(CommandEvent event, @Optional Member member) {
var target = member == null ? event.getMember() : member;
UserInfo userInfo = database.getRankService().getUserInfo(target);
var embed = userInfo.nextRank().isPresent() ? "rankInfo" : "rankInfoMax";
event.reply(embedCache.getEmbed(embed).injectValues(userInfo.getEmbedValues(target)));
}
+
+ @ContextCommand(value = "Kontoinformation abrufen", type = Command.Type.USER, isGuildOnly = true, ephemeral = true)
+ public void onContextRankInfo(CommandEvent event, User user) {
+ UserInfo userInfo = database.getRankService().getUserInfo(user);
+
+ var embed = userInfo.nextRank().isPresent() ? "rankInfo" : "rankInfoMax";
+ event.reply(embedCache.getEmbed(embed).injectValues(userInfo.getEmbedValues(user)));
+ }
}
From dcb26d06394c4dbfee21c91375eb58fadce83cd6 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Sun, 5 May 2024 15:20:32 +0200
Subject: [PATCH 42/66] first pass on collect events
---
embeds.json | 74 ++++++++
pom.xml | 2 +-
.../github/kaktushose/nplaybot/Database.java | 8 +
.../events/collect/CollectEventCommands.java | 42 +++++
.../events/collect/CollectEventService.java | 133 ++++++++++++++
.../events/collect/CollectRewardCommands.java | 169 ++++++++++++++++++
.../migration/V2.0.0__setup_event_system.sql | 22 ++-
7 files changed, 447 insertions(+), 3 deletions(-)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectRewardCommands.java
diff --git a/embeds.json b/embeds.json
index e4d4915..c9e7cd8 100644
--- a/embeds.json
+++ b/embeds.json
@@ -145,5 +145,79 @@
"title": "Erfolg",
"description": "Die Berechtigungen wurden angepasst",
"color": "#67c94f"
+ },
+ "rewardCreateSelectType": {
+ "title": "Belohnung: {name}",
+ "description": "Bitte wähle die Belohnungsart aus, mit der der Nutzer belohnt werden soll",
+ "color": "#67c94f"
+ },
+ "rewardCreateSelectRole": {
+ "title": "Belohnung: {name}",
+ "description": "Bitte wähle die Rolle aus, mit der der Nutzer belohnt werden soll",
+ "color": "#67c94f"
+ },
+ "rewardCreateInvalidXp": {
+ "title": "Belohnung: {name}",
+ "description": "Bitte gib eine Zahl zwischen 1 und 2.147.483.647 an",
+ "color": "#ffc926"
+ },
+ "rewardCreateInvalidEmbed": {
+ "title": "Belohnung: {name}",
+ "description": "Bitte gib ein gültiges Embed im JSON-Format an. [Online Embed Builder](https://glitchii.github.io/embedbuilder/)",
+ "color": "#ffc926"
+ },
+ "rewardCreateSummarize": {
+ "title": "Belohnung: {name}",
+ "description": "Du hast folgende Belohnung konfiguriert",
+ "fields": [
+ {
+ "name": "Typ",
+ "value": "{type}"
+ },
+ {
+ "name": "Grenze",
+ "value": "{threshold}"
+ },
+ {
+ "name": "{type}",
+ "value": "{reward}"
+ }
+ ],
+ "color": "#ffc926"
+ },
+ "rewardCreateConfirm": {
+ "title": "Erfolg",
+ "description": "Die Belohnung {name} wurde erstellt",
+ "color": "#67c94f"
+ },
+ "rewardCreateCancel": {
+ "title": "Okay",
+ "description": "Die Erstellung einer Belohnung wurde abgebrochen",
+ "color": "#67c94f"
+ },
+ "collectEventStart": {
+ "title": "Erfolg",
+ "description": "Das Collect Event `{name}` wurde gestartet",
+ "color": "#67c94f"
+ },
+ "collectEventStartError": {
+ "title": "Fehler",
+ "description": "Es ist aktuell bereits ein Collect Event aktiv. Beende dies zuerst, bevor du ein neues starten kannst!",
+ "color": "#ff0000"
+ },
+ "collectEventStop": {
+ "title": "Erfolg",
+ "description": "Das aktuelle Collect Event wurde beendet",
+ "color": "#67c94f"
+ },
+ "rewardDeleteSelect": {
+ "title": "Belohnungen löschen",
+ "description": "Wähle eine oder mehrere Belohnungen aus, die du löschen möchtest",
+ "color": "#67c94f"
+ },
+ "rewardDelete": {
+ "title": "Erfolg",
+ "description": "Die Belohnung(en) wurden gelöscht",
+ "color": "#67c94f"
}
}
diff --git a/pom.xml b/pom.xml
index 83f3499..5e23208 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,7 +77,7 @@
com.github.Kaktushose
jda-commands
- 4.0.0-beta.2
+ da36e41af0
com.zaxxer
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Database.java b/src/main/java/com/github/kaktushose/nplaybot/Database.java
index 422ea04..b029e03 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Database.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Database.java
@@ -1,11 +1,13 @@
package com.github.kaktushose.nplaybot;
+import com.github.kaktushose.nplaybot.events.collect.CollectEventService;
import com.github.kaktushose.nplaybot.events.contest.ContestEventService;
import com.github.kaktushose.nplaybot.permissions.PermissionsService;
import com.github.kaktushose.nplaybot.rank.RankService;
import com.github.kaktushose.nplaybot.settings.SettingsService;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
+import net.dv8tion.jda.api.entities.Role;
public class Database {
@@ -13,6 +15,7 @@ public class Database {
private final SettingsService settingsService;
private final RankService rankService;
private final ContestEventService contestEventService;
+ private final CollectEventService collectEventService;
private final PermissionsService permissionsService;
public Database() {
@@ -28,6 +31,7 @@ public Database() {
settingsService = new SettingsService(dataSource);
rankService = new RankService(dataSource);
contestEventService = new ContestEventService(dataSource);
+ collectEventService = new CollectEventService(dataSource);
permissionsService = new PermissionsService(dataSource);
}
@@ -47,6 +51,10 @@ public ContestEventService getContestEventService() {
return contestEventService;
}
+ public CollectEventService getCollectEventService() {
+ return collectEventService;
+ }
+
public PermissionsService getPermissionsService() {
return permissionsService;
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java
new file mode 100644
index 0000000..0ce3307
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java
@@ -0,0 +1,42 @@
+package com.github.kaktushose.nplaybot.events.collect;
+
+import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
+import com.github.kaktushose.jda.commands.annotations.interactions.Param;
+import com.github.kaktushose.jda.commands.annotations.interactions.Permissions;
+import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.permissions.BotPermissions;
+import net.dv8tion.jda.api.Permission;
+
+@Interaction
+@Permissions(BotPermissions.MANAGE_EVENTS)
+public class CollectEventCommands {
+
+ @Inject
+ private EmbedCache embedCache;
+ @Inject
+ private Database database;
+
+ @SlashCommand(value = "collect event start", desc = "Startet ein Collect Event", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onCollectEventStart(CommandEvent event,
+ @Param("Der Name des Events") String eventName,
+ @Param("Der Name der Währung die gesammelt werden soll, z.B. \"Schneemänner\"") String currencyName,
+ @Param("Die Emoji-Repräsentation der Währung, die gesammelt werden soll") String emoji) {
+ if (database.getCollectEventService().isActive(event.getGuild())) {
+ event.reply(embedCache.getEmbed("collectEventStartError"));
+ return;
+ }
+ database.getCollectEventService().startCollectEvent(event.getGuild(), eventName, currencyName, emoji);
+ event.reply(embedCache.getEmbed("collectEventStart").injectValue("name", eventName));
+ }
+
+ @SlashCommand(value = "collect event stop", desc = "Stoppt das aktuelle Collect Event", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onCollectEventStop(CommandEvent event) {
+ database.getCollectEventService().stopCollectEvent(event.getGuild());
+ event.reply(embedCache.getEmbed("collectEventStop"));
+ }
+
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java
new file mode 100644
index 0000000..ec95f54
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java
@@ -0,0 +1,133 @@
+package com.github.kaktushose.nplaybot.events.collect;
+
+import com.github.kaktushose.nplaybot.events.contest.ContestEventService;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Role;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CollectEventService {
+
+
+ private static final Logger log = LoggerFactory.getLogger(ContestEventService.class);
+ private final DataSource dataSource;
+ public CollectEventService(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public boolean isActive(Guild guild) {
+ log.debug("Querying collect event active flag for guild {}", guild);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT collect_event_active
+ FROM event_settings
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, guild.getIdLong());
+
+ var result = statement.executeQuery();
+ result.next();
+ return result.getBoolean(1);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void startCollectEvent(Guild guild, String eventName, String currencyName, String emoji) {
+ log.debug("Starting new collect event [{}, {}, {}] for guild {}", eventName, currencyName, emoji, guild);
+ try (Connection connection = dataSource.getConnection()) {
+ connection.prepareStatement("UPDATE users SET collect_points = 0").execute();
+
+ var statement = connection.prepareStatement("""
+ UPDATE event_settings
+ SET collect_event_name = ?,
+ collect_currency_name = ?,
+ collect_currency_emoji = ?,
+ collect_event_active = true
+ WHERE guild_id = ?
+ """
+ );
+
+ statement.setString(1, eventName);
+ statement.setString(2,currencyName);
+ statement.setString(3, emoji);
+ statement.setLong(4, guild.getIdLong());
+
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void stopCollectEvent(Guild guild) {
+ log.debug("Stopping collect event for guild {}", guild);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ UPDATE event_settings
+ SET collect_event_active = false
+ WHERE guild_id = ?
+ """
+ );
+ statement.setLong(1, guild.getIdLong());
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void createCollectReward(String name, int threshold, int xp, Role role, String embed) {
+ log.debug("Creating new collect reward");
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("INSERT INTO collect_rewards(name, threshold, xp, role_id, embed) VALUES (?, ?, ?, ?, CAST (? AS jsonb))");
+ statement.setString(1, name);
+ statement.setInt(2, threshold);
+ statement.setInt(3, xp);
+ statement.setLong(4, role == null ? -1 : role.getIdLong());
+ statement.setObject(5, embed);
+
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public record CollectReward(int rewardId, String name) {
+ }
+ public List getCollectRewards() {
+ log.debug("Querying collect rewards");
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ SELECT reward_id, name
+ FROM collect_rewards
+ """
+ );
+ var result = statement.executeQuery();
+ List rewards = new ArrayList<>();
+ while (result.next()) {
+ rewards.add(new CollectReward(result.getInt("reward_id"), result.getString("name")));
+ }
+ return rewards;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void deleteCollectReward(int rewardId) {
+ log.debug("Deleting reward with id {}", rewardId);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("DELETE FROM collect_rewards WHERE reward_id = ?");
+ statement.setInt(1, rewardId);
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectRewardCommands.java b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectRewardCommands.java
new file mode 100644
index 0000000..f37d462
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectRewardCommands.java
@@ -0,0 +1,169 @@
+package com.github.kaktushose.nplaybot.events.collect;
+
+import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.interactions.*;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.jda.commands.dispatching.interactions.components.ComponentEvent;
+import com.github.kaktushose.jda.commands.dispatching.interactions.modals.ModalEvent;
+import com.github.kaktushose.jda.commands.dispatching.reply.Replyable;
+import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.permissions.BotPermissions;
+import com.google.gson.*;
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.Mentions;
+import net.dv8tion.jda.api.entities.Role;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+import net.dv8tion.jda.api.interactions.components.selections.SelectMenu;
+import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
+
+import java.util.List;
+import java.util.Optional;
+
+@Interaction
+@Permissions(BotPermissions.MANAGE_EVENTS)
+public class CollectRewardCommands {
+
+ @Inject
+ private EmbedCache embedCache;
+ @Inject
+ private Database database;
+ private static final Gson gson = new Gson();
+ private static final String ROLE_REWARD = "Rolle";
+ private static final String XP_REWARD = "XP";
+ private String name;
+ private String rewardType;
+ private Role role;
+ private int xp;
+ private int threshold;
+ private String embed;
+
+ @SlashCommand(value = "collect reward create", desc = "Erstellt eine Belohnung für das Collect Event", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onRewardCreate(CommandEvent event, @Param("Der interne Name dieser Belohnung") String name, @Param("Der Wert, ab wann die Belohnung vergeben werden soll") int threshold) {
+ this.name = name;
+ this.threshold = threshold;
+ event.withSelectMenus("onSelectType").reply(embedCache.getEmbed("rewardCreateSelectType").injectValue("name", name));
+ }
+
+ @StringSelectMenu("Wähle eine Belohnungsart aus")
+ @SelectOption(label = "Rolle", value = ROLE_REWARD)
+ @SelectOption(label = "XP", value = XP_REWARD)
+ public void onSelectType(ComponentEvent event, List selection) {
+ rewardType = selection.get(0);
+ if (ROLE_REWARD.equals(rewardType)) {
+ event.withSelectMenus("onSelectRole").reply(embedCache.getEmbed("rewardCreateSelectRole").injectValue("name", name));
+ } else if (XP_REWARD.equals(rewardType)) {
+ event.replyModal("onSelectXp");
+ } else {
+ throw new IllegalArgumentException(String.format("%s ist keine gültige Auswahl!", rewardType));
+ }
+ }
+
+ @EntitySelectMenu(value = net.dv8tion.jda.api.interactions.components.selections.EntitySelectMenu.SelectTarget.ROLE, placeholder = "Wähle eine Rolle aus")
+ public void onSelectRole(ComponentEvent event, Mentions mentions) {
+ role = mentions.getRoles().get(0);
+ event.replyModal("onSelectEmbed");
+ }
+
+ @Modal("Embed angeben")
+ public void onSelectEmbed(ModalEvent event, @TextInput(value = "Das Embed im JSON-Format", label = "Embed") String embed) {
+ parseJson(embed).ifPresentOrElse(it -> {
+ this.embed = it;
+ finishSetup(event);
+ }, () -> event.withButtons("onRetryEmbedInput").reply(embedCache.getEmbed("rewardCreateInvalidEmbed").injectValue("name", name)));
+ }
+
+ @Button("neue Eingabe")
+ public void onRetryEmbedInput(ComponentEvent event) {
+ event.replyModal("onSelectEmbed");
+ }
+
+ @Modal("XP-Belohnung")
+ public void onSelectXp(ModalEvent event,
+ @TextInput(style = TextInputStyle.SHORT, label = "XP-Menge", value = "Eine Zahl zwischen 1 und 2.147.483.647") String amount,
+ @TextInput(value = "Das Embed im JSON-Format", label = "Embed") String embed) {
+ int xp;
+ try {
+ xp = Integer.parseInt(amount);
+ } catch (NumberFormatException ignored) {
+ event.withButtons("onRetryXpInput").reply(embedCache.getEmbed("rewardCreateInvalidXp").injectValue("name", name));
+ return;
+ }
+ if (xp < 1) {
+ event.withButtons("onRetryXpInput").reply(embedCache.getEmbed("rewardCreateInvalidXp").injectValue("name", name));
+ return;
+ }
+ parseJson(embed).ifPresentOrElse(it -> {
+ this.embed = it;
+ this.xp = xp;
+ finishSetup(event);
+ }, () -> event.withButtons("onRetryXpInput").reply(embedCache.getEmbed("rewardCreateInvalidEmbed").injectValue("name", name)));
+ }
+
+ @Button("neue Eingabe")
+ public void onRetryXpInput(ComponentEvent event) {
+ event.replyModal("onSelectXp");
+ }
+
+ private void finishSetup(Replyable event) {
+ event.withButtons("onConfirm", "onCancel").reply(embedCache.getEmbed("rewardCreateSummarize")
+ .injectValue("name", name)
+ .injectValue("type", rewardType)
+ .injectValue("threshold", threshold)
+ .injectValue("reward", role == null ? String.valueOf(xp) : role.getAsMention())
+ );
+ }
+
+ @Button(value = "Erstellen", style = ButtonStyle.SUCCESS)
+ public void onConfirm(ComponentEvent event) {
+ database.getCollectEventService().createCollectReward(name, threshold, xp, role, embed);
+ event.reply(embedCache.getEmbed("rewardCreateConfirm").injectValue("name", name));
+ event.removeComponents();
+ }
+
+ @Button(value = "Abbrechen", style = ButtonStyle.DANGER)
+ public void onCancel(ComponentEvent event) {
+ event.reply(embedCache.getEmbed("rewardCreateCancel"));
+ event.removeComponents();
+ }
+
+ @SlashCommand(value = "collect reward delete", desc = "Löscht eine oder mehrere Belohnung(en) für das Collect Event", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onRewardDelete(CommandEvent event) {
+ var rewards = database.getCollectEventService().getCollectRewards();
+
+ var menu = ((net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu)
+ event.getJdaCommands().getSelectMenu("CollectRewardCommands.onRewardDeleteSelect")).createCopy();
+ menu.getOptions().clear();
+ menu.setMaxValues(SelectMenu.OPTIONS_MAX_AMOUNT);
+ rewards.forEach(it -> menu.addOption(it.name(), String.valueOf(it.rewardId())));
+ event.getReplyContext().getBuilder().addActionRow(menu.build());
+ event.reply(embedCache.getEmbed("rewardDeleteSelect"));
+ }
+
+ @StringSelectMenu(value = "Wähle eine oder mehrere Belohnungen aus")
+ @SelectOption(label = "dummy option", value = "dummy option")
+ public void onRewardDeleteSelect(ComponentEvent event, List selection) {
+ for (var id : selection) {
+ database.getCollectEventService().deleteCollectReward(Integer.parseInt(id));
+ }
+ event.reply(embedCache.getEmbed("rewardDelete"));
+ }
+
+ private Optional parseJson(String json) {
+ try {
+ JsonObject object = gson.fromJson(json, JsonObject.class);
+ if (object.has("embeds")) {
+ if (!object.get("embeds").isJsonArray()) {
+ return Optional.empty();
+ }
+ object = object.get("embeds").getAsJsonArray().get(0).getAsJsonObject();
+ }
+ if (!(object.has("title") || object.has("description"))) {
+ return Optional.of(object.toString());
+ }
+ return Optional.empty();
+ } catch (JsonSyntaxException ignored) {
+ return Optional.empty();
+ }
+ }
+}
diff --git a/src/main/resources/db/migration/V2.0.0__setup_event_system.sql b/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
index 8bf9287..da377f4 100644
--- a/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
+++ b/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
@@ -1,11 +1,29 @@
CREATE TABLE event_settings (
guild_id BIGINT NOT NULL PRIMARY KEY,
- contest_channel_id BIGINT NOT NULL DEFAULT 0,
- contest_vote_emoji VARCHAR
+ contest_channel_id BIGINT NOT NULL DEFAULT -1,
+ contest_vote_emoji VARCHAR NOT NULL DEFAULT '',
+ collect_event_name VARCHAR NOT NULL DEFAULT '',
+ collect_currency_name VARCHAR NOT NULL DEFAULT '',
+ collect_currency_emoji VARCHAR NOT NULL DEFAULT '',
+ collect_loot_chance REAL NOT NULL,
+ collect_event_active BOOLEAN NOT NULL DEFAULT FALSE
);
+
CREATE TABLE contest_entries (
user_id BIGINT NOT NULL PRIMARY KEY,
votes INT NOT NULL DEFAULT 0,
message_id BIGINT NOT NULL
);
+
ALTER TABLE users ADD COLUMN permissions INTEGER DEFAULT 1;
+
+ALTER TABLE users ADD COLUMN collect_points INTEGER DEFAULT 0;
+
+CREATE TABLE collect_rewards (
+ reward_id SERIAL PRIMARY KEY,
+ name VARCHAR NOT NULL DEFAULT 0,
+ threshold INT NOT NULL,
+ xp INT,
+ role_id BIGINT,
+ embed JSONB NOT NULL
+);
From c0466ec2271492c7119620aa2cf4a20faa5bcb2c Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Sun, 5 May 2024 15:28:33 +0200
Subject: [PATCH 43/66] add config command for collect loot chance
---
embeds.json | 4 ++++
.../events/collect/CollectEventCommands.java | 8 ++++++++
.../events/collect/CollectEventService.java | 18 ++++++++++++++++++
.../rank/commands/RankConfigCommands.java | 2 +-
4 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/embeds.json b/embeds.json
index c9e7cd8..d39885a 100644
--- a/embeds.json
+++ b/embeds.json
@@ -219,5 +219,9 @@
"title": "Erfolg",
"description": "Die Belohnung(en) wurden gelöscht",
"color": "#67c94f"
+ },
+ "collectLootChanceUpdate": {
+ "title": "Erfolg",
+ "description": "Die Wahrscheinlichkeit für zufällige Collect-Loo-Drops wurde auf {value} gesetzt"
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java
index 0ce3307..f703640 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java
@@ -1,6 +1,8 @@
package com.github.kaktushose.nplaybot.events.collect;
import com.github.kaktushose.jda.commands.annotations.Inject;
+import com.github.kaktushose.jda.commands.annotations.constraints.Max;
+import com.github.kaktushose.jda.commands.annotations.constraints.Min;
import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
import com.github.kaktushose.jda.commands.annotations.interactions.Param;
import com.github.kaktushose.jda.commands.annotations.interactions.Permissions;
@@ -39,4 +41,10 @@ public void onCollectEventStop(CommandEvent event) {
event.reply(embedCache.getEmbed("collectEventStop"));
}
+ @SlashCommand(value = "set collect-loot chance", desc = "Legt die Wahrscheinlichkeit für zufällige Collect-Loot-Drops fest", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ public void onSetXpLootDropChance(CommandEvent event, @Param("Die Wahrscheinlichkeit in Prozent") @Min(1) @Max(100) double chance) {
+ database.getCollectEventService().updateCollectLootChance(event.getGuild(), chance);
+ event.reply(embedCache.getEmbed("collectLootChanceUpdate").injectFields("value", chance));
+ }
+
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java
index ec95f54..ee3e33c 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java
@@ -98,6 +98,24 @@ public void createCollectReward(String name, int threshold, int xp, Role role, S
}
}
+ public void updateCollectLootChance(Guild guild, double chance) {
+ log.debug("Updating collect loot chance for guild: {}", guild);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("""
+ UPDATE rank_settings
+ SET collect_loot_chance = ?
+ WHERE guild_id = ?
+ """
+ );
+ statement.setDouble(1, chance);
+ statement.setLong(2, guild.getIdLong());
+
+ statement.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
public record CollectReward(int rewardId, String name) {
}
public List getCollectRewards() {
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java
index 0ca05ca..7bbc1c7 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankConfigCommands.java
@@ -40,7 +40,7 @@ public void onSetMinMessageLength(CommandEvent event, @Param("Die Mindestanzahl
event.reply(embedCache.getEmbed("rankConfig").injectFields(database.getRankService().getRankConfig(event.getGuild())));
}
- @SlashCommand(value = "set loot chance", desc = "Legt die Wahrscheinlichkeit für zufällige XP-Loot-Drops fest", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @SlashCommand(value = "set xp-loot chance", desc = "Legt die Wahrscheinlichkeit für zufällige XP-Loot-Drops fest", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
public void onSetXpLootDropChance(CommandEvent event, @Param("Die Wahrscheinlichkeit in Prozent") @Min(1) @Max(100) double chance) {
database.getRankService().updateXpLootChance(event.getGuild(), chance);
event.reply(embedCache.getEmbed("rankConfig").injectFields(database.getRankService().getRankConfig(event.getGuild())));
From 4d241e5f5b547417da5ef12de412ae2fcfd3b2c8 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Mon, 6 May 2024 20:34:25 +0200
Subject: [PATCH 44/66] implement collect event functionality
---
embeds.json | 9 +-
.../com/github/kaktushose/nplaybot/Bot.java | 4 +-
.../events/collect/CollectEventCommands.java | 2 +-
.../events/collect/CollectEventListener.java | 142 ++++++++++++++++++
.../events/collect/CollectEventService.java | 88 +++++++++--
.../events/collect/CollectRewardCommands.java | 2 +-
.../events/contest/ContestListener.java | 6 +
.../nplaybot/rank/RankListener.java | 29 +---
.../kaktushose/nplaybot/rank/RankService.java | 19 +++
.../rank/commands/RankInfoCommand.java | 22 ++-
.../nplaybot/rank/model/UserInfo.java | 18 ---
.../migration/V2.0.0__setup_event_system.sql | 21 ++-
12 files changed, 300 insertions(+), 62 deletions(-)
create mode 100644 src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventListener.java
diff --git a/embeds.json b/embeds.json
index d39885a..18aaa4f 100644
--- a/embeds.json
+++ b/embeds.json
@@ -187,7 +187,7 @@
},
"rewardCreateConfirm": {
"title": "Erfolg",
- "description": "Die Belohnung {name} wurde erstellt",
+ "description": "Die Belohnung `{name}` wurde erstellt",
"color": "#67c94f"
},
"rewardCreateCancel": {
@@ -222,6 +222,11 @@
},
"collectLootChanceUpdate": {
"title": "Erfolg",
- "description": "Die Wahrscheinlichkeit für zufällige Collect-Loo-Drops wurde auf {value} gesetzt"
+ "description": "Die Wahrscheinlichkeit für zufällige Collect-Loo-Drops wurde auf {chance} gesetzt"
+ },
+ "collectLootDropClaimed": {
+ "title": "Glückwunsch :tada:",
+ "description": "{user} hat 1 {name} gefunden",
+ "color": "#67c94f"
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/Bot.java b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
index dbacc56..54d175b 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/Bot.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/Bot.java
@@ -3,6 +3,7 @@
import com.github.kaktushose.jda.commands.JDACommands;
import com.github.kaktushose.jda.commands.annotations.Produces;
import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.nplaybot.events.collect.CollectEventListener;
import com.github.kaktushose.nplaybot.events.contest.ContestListener;
import com.github.kaktushose.nplaybot.permissions.CustomPermissionsProvider;
import com.github.kaktushose.nplaybot.rank.JoinLeaveListener;
@@ -47,7 +48,8 @@ private Bot(long guildId) throws InterruptedException, RuntimeException {
.addEventListeners(
new RankListener(database, embedCache),
new JoinLeaveListener(database.getRankService()),
- new ContestListener(database.getContestEventService())
+ new ContestListener(database.getContestEventService()),
+ new CollectEventListener(database, embedCache)
)
.build().awaitReady();
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java
index f703640..9c0e32d 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventCommands.java
@@ -44,7 +44,7 @@ public void onCollectEventStop(CommandEvent event) {
@SlashCommand(value = "set collect-loot chance", desc = "Legt die Wahrscheinlichkeit für zufällige Collect-Loot-Drops fest", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
public void onSetXpLootDropChance(CommandEvent event, @Param("Die Wahrscheinlichkeit in Prozent") @Min(1) @Max(100) double chance) {
database.getCollectEventService().updateCollectLootChance(event.getGuild(), chance);
- event.reply(embedCache.getEmbed("collectLootChanceUpdate").injectFields("value", chance));
+ event.reply(embedCache.getEmbed("collectLootChanceUpdate").injectValue("chance", chance));
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventListener.java b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventListener.java
new file mode 100644
index 0000000..6364f58
--- /dev/null
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventListener.java
@@ -0,0 +1,142 @@
+package com.github.kaktushose.nplaybot.events.collect;
+
+import com.github.kaktushose.jda.commands.data.EmbedCache;
+import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.rank.RankService;
+import com.github.kaktushose.nplaybot.settings.SettingsService;
+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.emoji.Emoji;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
+import net.dv8tion.jda.api.hooks.ListenerAdapter;
+import net.dv8tion.jda.api.utils.data.DataObject;
+import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class CollectEventListener extends ListenerAdapter {
+
+ private static final Logger log = LoggerFactory.getLogger(CollectEventListener.class);
+ private final RankService rankService;
+ private final CollectEventService eventService;
+ private final SettingsService settingsService;
+ private final EmbedCache embedCache;
+ private final Set collectLootDrops;
+
+ public CollectEventListener(Database database, EmbedCache embedCache) {
+ this.rankService = database.getRankService();
+ this.eventService = database.getCollectEventService();
+ this.settingsService = database.getSettingsService();
+ this.embedCache = embedCache;
+ collectLootDrops = new HashSet<>();
+ }
+
+ @Override
+ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
+ log.debug("Received message event");
+ var author = event.getAuthor();
+
+ if (author.isBot()) {
+ log.trace("Author is bot");
+ return;
+ }
+ if (!event.isFromGuild()) {
+ log.trace("Event is not from guild");
+ return;
+ }
+
+ if (!rankService.isValidChannel(event.getChannel(), event.getGuild())) {
+ return;
+ }
+
+ onCollectLootDrop(event);
+ onAddRegularCollectPoints(event);
+ }
+
+ private void onAddRegularCollectPoints(MessageReceivedEvent event) {
+ var oldPoints = eventService.getCollectPoints(event.getAuthor());
+ var newPoints = eventService.addCollectPoint(event.getAuthor());
+ onCollectPointChange(oldPoints, newPoints, event.getMember(), event.getGuild());
+ }
+
+ private void onCollectPointChange(int oldPoints, int newPoints, Member member, Guild guild) {
+ var rewards = eventService.getCollectRewards();
+ var optional = rewards.stream()
+ .filter(it -> it.threshold() > oldPoints)
+ .filter(it -> it.threshold() <= newPoints)
+ .findFirst();
+
+ if (optional.isEmpty()) {
+ return;
+ }
+ var reward = optional.get();
+
+ if (reward.xp() > 0) {
+ var xpChangeResult = rankService.addXp(member, reward.xp());
+ rankService.onXpChange(xpChangeResult, member, guild, embedCache).ifPresent(it ->
+ settingsService.getBotChannel(guild).sendMessage(it).queue()
+ );
+ }
+
+ if (reward.roleId() > 0) {
+ guild.addRoleToMember(member, guild.getRoleById(reward.roleId())).queue();
+ }
+
+ var builder = new MessageCreateBuilder().addContent(member.getAsMention())
+ .addEmbeds(EmbedBuilder.fromData(DataObject.fromJson(reward.embed())).build())
+ .build();
+ settingsService.getBotChannel(guild).sendMessage(builder).queue();
+ }
+
+ private void onCollectLootDrop(MessageReceivedEvent event) {
+ var points = eventService.getCollectLootDrop(event.getMessage());
+
+ if (points < 1) {
+ log.debug("No collect loot drop for this message");
+ return;
+ }
+
+ collectLootDrops.add(event.getMessageIdLong());
+ event.getMessage().addReaction(Emoji.fromUnicode(eventService.getCollectCurrency(event.getGuild()).emoji())).queue();
+ }
+
+ @Override
+ public void onMessageReactionAdd(@NotNull MessageReactionAddEvent event) {
+ if (event.getUser().isBot()) {
+ return;
+ }
+
+ var messageId = event.getMessageIdLong();
+ if (!collectLootDrops.contains(messageId)) {
+ return;
+ }
+ var currency = eventService.getCollectCurrency(event.getGuild());
+ if (!event.getEmoji().equals(Emoji.fromUnicode(currency.emoji()))) {
+ return;
+ }
+
+ log.debug("Collect loot drop got claimed by {}", event.getMember());
+
+ var oldPoints = eventService.getCollectPoints(event.getMember());
+ var newPoints = eventService.addCollectPoint(event.getMember());
+ onCollectPointChange(oldPoints, newPoints, event.getMember(), event.getGuild());
+ collectLootDrops.remove(messageId);
+
+ event.retrieveMessage().queue(message -> {
+ message.reply(
+ embedCache.getEmbed("collectLootDropClaimed")
+ .injectValue("user", event.getMember().getAsMention())
+ .injectValue("name", currency.name())
+ .toMessageCreateData()
+ ).mentionRepliedUser(false).queue(it -> it.delete().queueAfter(10, TimeUnit.SECONDS));
+ message.clearReactions().queue();
+ });
+ }
+}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java
index ee3e33c..bdda76a 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectEventService.java
@@ -2,7 +2,9 @@
import com.github.kaktushose.nplaybot.events.contest.ContestEventService;
import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.Role;
+import net.dv8tion.jda.api.entities.UserSnowflake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -17,6 +19,7 @@ public class CollectEventService {
private static final Logger log = LoggerFactory.getLogger(ContestEventService.class);
private final DataSource dataSource;
+
public CollectEventService(DataSource dataSource) {
this.dataSource = dataSource;
}
@@ -56,7 +59,7 @@ public void startCollectEvent(Guild guild, String eventName, String currencyName
);
statement.setString(1, eventName);
- statement.setString(2,currencyName);
+ statement.setString(2, currencyName);
statement.setString(3, emoji);
statement.setLong(4, guild.getIdLong());
@@ -102,7 +105,7 @@ public void updateCollectLootChance(Guild guild, double chance) {
log.debug("Updating collect loot chance for guild: {}", guild);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
- UPDATE rank_settings
+ UPDATE event_settings
SET collect_loot_chance = ?
WHERE guild_id = ?
"""
@@ -116,20 +119,63 @@ public void updateCollectLootChance(Guild guild, double chance) {
}
}
- public record CollectReward(int rewardId, String name) {
+ public int getCollectLootDrop(Message message) {
+ log.debug("Querying collect loot drop for message {}", message);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("SELECT * FROM get_collect_loot_drop(?)");
+ statement.setLong(1, message.getGuildIdLong());
+ var result = statement.executeQuery();
+ result.next();
+ var points = result.getInt(1);
+ log.debug("Collect loot drop: {} points", points);
+ return points;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
}
- public List getCollectRewards() {
- log.debug("Querying collect rewards");
+
+ public record CollectCurrency(String name, String emoji) {
+ }
+
+ public CollectCurrency getCollectCurrency(Guild guild) {
+ log.debug("Querying collect currency emoji");
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
- SELECT reward_id, name
- FROM collect_rewards
- """
+ SELECT collect_currency_emoji, collect_currency_name
+ FROM event_settings
+ WHERE guild_id = ?
+ """);
+ statement.setLong(1, guild.getIdLong());
+ var result = statement.executeQuery();
+ result.next();
+ return new CollectCurrency(
+ result.getString("collect_currency_name"),
+ result.getString("collect_currency_emoji")
);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public record CollectReward(int rewardId, String name, int threshold, int xp, long roleId, String embed) {
+ }
+
+ public List getCollectRewards() {
+ log.debug("Querying collect rewards");
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("SELECT * FROM collect_rewards");
var result = statement.executeQuery();
List rewards = new ArrayList<>();
while (result.next()) {
- rewards.add(new CollectReward(result.getInt("reward_id"), result.getString("name")));
+ rewards.add(new CollectReward(
+ result.getInt("reward_id"),
+ result.getString("name"),
+ result.getInt("threshold"),
+ result.getInt("xp"),
+ result.getLong("role_id"),
+ result.getString("embed")
+ )
+ );
}
return rewards;
} catch (SQLException e) {
@@ -148,4 +194,28 @@ public void deleteCollectReward(int rewardId) {
}
}
+ public int addCollectPoint(UserSnowflake user) {
+ log.debug("Adding one collect point to user: {}", user);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("UPDATE users SET collect_points = collect_points + 1 where user_id = ?");
+ statement.setLong(1, user.getIdLong());
+ statement.execute();
+ return getCollectPoints(user);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int getCollectPoints(UserSnowflake user) {
+ log.debug("Querying collect points for user {}", user);
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("SELECT collect_points FROM users WHERE user_Id = ?");
+ statement.setLong(1, user.getIdLong());
+ var result = statement.executeQuery();
+ result.next();
+ return result.getInt(1);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectRewardCommands.java b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectRewardCommands.java
index f37d462..3da17e8 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectRewardCommands.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/collect/CollectRewardCommands.java
@@ -158,7 +158,7 @@ private Optional parseJson(String json) {
}
object = object.get("embeds").getAsJsonArray().get(0).getAsJsonObject();
}
- if (!(object.has("title") || object.has("description"))) {
+ if (object.has("title") || object.has("description")) {
return Optional.of(object.toString());
}
return Optional.empty();
diff --git a/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestListener.java b/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestListener.java
index 6713bc5..4302b73 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestListener.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/events/contest/ContestListener.java
@@ -84,6 +84,9 @@ public void onMessageReactionRemove(@NotNull MessageReactionRemoveEvent event) {
@Override
public void onMessageReactionRemoveEmoji(@NotNull MessageReactionRemoveEmojiEvent event) {
+ if (event.getChannel().getIdLong() != eventService.getContestEventChannel(event.getGuild())) {
+ return;
+ }
if (!event.getEmoji().equals(Emoji.fromFormatted(eventService.getVoteEmoji(event.getGuild())))) {
return;
}
@@ -96,6 +99,9 @@ public void onMessageReactionRemoveEmoji(@NotNull MessageReactionRemoveEmojiEven
@Override
public void onMessageReactionRemoveAll(@NotNull MessageReactionRemoveAllEvent event) {
+ if (event.getChannel().getIdLong() != eventService.getContestEventChannel(event.getGuild())) {
+ return;
+ }
log.debug("Detected removal of all vote emojis. Adding initial emoji again");
event.getChannel().retrieveMessageById(event.getMessageId()).flatMap(message ->
message.addReaction(Emoji.fromFormatted(eventService.getVoteEmoji(event.getGuild())))
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
index c1766c1..608f3ff 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
@@ -2,15 +2,11 @@
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.nplaybot.Database;
-import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
import com.github.kaktushose.nplaybot.settings.SettingsService;
-import net.dv8tion.jda.api.entities.Guild;
-import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
-import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -68,24 +64,9 @@ private void onAddRegularXp(MessageReceivedEvent event) {
rankService.updateValidMessage(event.getAuthor());
var result = rankService.addRandomXp(event.getAuthor());
- onXpChange(result, event.getMember(), event.getGuild());
- }
-
- private void onXpChange(XpChangeResult result, Member member, Guild guild) {
- log.debug("Checking for rank up: {}", member);
- rankService.updateRankRoles(member, guild, result);
-
- if (!result.rankChanged()) {
- log.debug("Rank hasn't changed");
- return;
- }
- log.debug("Applying changes. New rank: {}", result.currentRank());
-
- var embed = result.nextRank().isPresent() ? "rankIncrease" : "rankIncreaseMax";
- var messageData = new MessageCreateBuilder().addContent(member.getAsMention())
- .addEmbeds(embedCache.getEmbed(embed).injectValues(result.getEmbedValues(member)).toMessageEmbed())
- .build();
- settingsService.getBotChannel(guild).sendMessage(messageData).queue();
+ rankService.onXpChange(result, event.getMember(), event.getGuild(), embedCache).ifPresent(it ->
+ settingsService.getBotChannel(event.getGuild()).sendMessage(it).queue()
+ );
}
private void onXpLootDrop(MessageReceivedEvent event) {
@@ -118,7 +99,9 @@ public void onMessageReactionAdd(@NotNull MessageReactionAddEvent event) {
var xp = xpLootDrops.get(messageId);
var result = rankService.addXp(event.getMember(), xp);
- onXpChange(result, event.getMember(), event.getGuild());
+ rankService.onXpChange(result, event.getMember(), event.getGuild(), embedCache).ifPresent(it ->
+ settingsService.getBotChannel(event.getGuild()).sendMessage(it).queue()
+ );
xpLootDrops.remove(messageId);
event.retrieveMessage().queue(message -> {
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
index ae5563c..178d9e2 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
@@ -1,5 +1,6 @@
package com.github.kaktushose.nplaybot.rank;
+import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.nplaybot.rank.leaderboard.LeaderboardPage;
import com.github.kaktushose.nplaybot.rank.model.RankConfig;
import com.github.kaktushose.nplaybot.rank.model.RankInfo;
@@ -10,6 +11,8 @@
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.UserSnowflake;
import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion;
+import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
+import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -338,6 +341,22 @@ public XpChangeResult setXp(UserSnowflake user, int value) {
}
}
+ public Optional onXpChange(XpChangeResult result, Member member, Guild guild, EmbedCache embedCache) {
+ log.debug("Checking for rank up: {}", member);
+ updateRankRoles(member, guild, result);
+
+ if (!result.rankChanged()) {
+ log.debug("Rank hasn't changed");
+ return Optional.empty();
+ }
+ log.debug("Applying changes. New rank: {}", result.currentRank());
+
+ var embed = result.nextRank().isPresent() ? "rankIncrease" : "rankIncreaseMax";
+ return Optional.of(new MessageCreateBuilder().addContent(member.getAsMention())
+ .addEmbeds(embedCache.getEmbed(embed).injectValues(result.getEmbedValues(member)).toMessageEmbed())
+ .build());
+ }
+
public void updateRankRoles(Member member, Guild guild, XpChangeResult result) {
var validRole = guild.getRoleById(result.currentRank().roleId());
var invalidRoles = getRankRoleIds().stream()
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
index 33abb34..b4216ee 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/commands/RankInfoCommand.java
@@ -9,6 +9,7 @@
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.UserSnowflake;
import net.dv8tion.jda.api.interactions.commands.Command;
@Interaction
@@ -24,16 +25,27 @@ public class RankInfoCommand {
public void onRankInfo(CommandEvent event, @Optional Member member) {
var target = member == null ? event.getMember() : member;
UserInfo userInfo = database.getRankService().getUserInfo(target);
-
- var embed = userInfo.nextRank().isPresent() ? "rankInfo" : "rankInfoMax";
- event.reply(embedCache.getEmbed(embed).injectValues(userInfo.getEmbedValues(target)));
+ sendReply(userInfo, target.getUser(), event);
}
@ContextCommand(value = "Kontoinformation abrufen", type = Command.Type.USER, isGuildOnly = true, ephemeral = true)
public void onContextRankInfo(CommandEvent event, User user) {
UserInfo userInfo = database.getRankService().getUserInfo(user);
+ sendReply(userInfo, user, event);
+ }
- var embed = userInfo.nextRank().isPresent() ? "rankInfo" : "rankInfoMax";
- event.reply(embedCache.getEmbed(embed).injectValues(userInfo.getEmbedValues(user)));
+ private void sendReply(UserInfo userInfo, User user, CommandEvent event) {
+ var embed = embedCache.getEmbed(userInfo.nextRank().isPresent() ? "rankInfo" : "rankInfoMax")
+ .injectValues(userInfo.getEmbedValues(user))
+ .toEmbedBuilder();
+
+ var guild = event.getGuild();
+ if (database.getCollectEventService().isActive(guild)) {
+ var currency = database.getCollectEventService().getCollectCurrency(guild);
+ var points = database.getCollectEventService().getCollectPoints(user);
+ embed.addField(currency.name(), String.format("%s %d", currency.emoji(), points), false);
+ }
+ event.reply(embed);
}
+
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java b/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
index af6e222..774022b 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/model/UserInfo.java
@@ -1,6 +1,5 @@
package com.github.kaktushose.nplaybot.rank.model;
-import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
import java.util.HashMap;
@@ -9,23 +8,6 @@
public record UserInfo(int currentXp, RankInfo currentRank, Optional nextRank, int messageCount, int xpGain) {
- public Map getEmbedValues(Member member) {
- var result = new HashMap() {{
- put("user", String.format("<@%d>", member.getIdLong()));
- put("color", currentRank.color());
- put("avatarUrl", member.getEffectiveAvatarUrl());
- put("currentRank", String.format("<@&%d>", currentRank.roleId()));
- put("currentXp", currentXp);
- put("xpGain", xpGain);
- put("messageCount", messageCount);
- }};
- nextRank.ifPresent(rank -> {
- result.put("nextRank", String.format("<@&%d>", rank.roleId()));
- result.put("missingXp", rank.xpBound() - currentXp);
- });
- return result;
- }
-
public Map getEmbedValues(User user) {
var result = new HashMap() {{
put("user", String.format("<@%d>", user.getIdLong()));
diff --git a/src/main/resources/db/migration/V2.0.0__setup_event_system.sql b/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
index da377f4..7582163 100644
--- a/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
+++ b/src/main/resources/db/migration/V2.0.0__setup_event_system.sql
@@ -23,7 +23,24 @@ CREATE TABLE collect_rewards (
reward_id SERIAL PRIMARY KEY,
name VARCHAR NOT NULL DEFAULT 0,
threshold INT NOT NULL,
- xp INT,
- role_id BIGINT,
+ xp INT NOT NULL DEFAULT 0,
+ role_id BIGINT NOT NULL DEFAULT 0,
embed JSONB NOT NULL
);
+
+CREATE FUNCTION get_collect_loot_drop(id BIGINT)
+RETURNS TABLE (points INT) AS
+$$
+DECLARE
+ chance INT;
+ drop_chance REAL;
+BEGIN
+ SELECT event_settings.collect_loot_chance INTO drop_chance FROM event_settings WHERE guild_id = id;
+ chance := floor(random() * 100) + 1;
+ IF ROUND(drop_chance) >= chance THEN
+ RETURN QUERY SELECT 1;
+ ELSE
+ RETURN QUERY SELECT 0;
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
From eff6bedb87ae75374b6690672e9d41e3c55f5d4e Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Fri, 10 May 2024 11:35:27 +0200
Subject: [PATCH 45/66] fix typos
---
embeds.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/embeds.json b/embeds.json
index 18aaa4f..45e1a5a 100644
--- a/embeds.json
+++ b/embeds.json
@@ -222,7 +222,7 @@
},
"collectLootChanceUpdate": {
"title": "Erfolg",
- "description": "Die Wahrscheinlichkeit für zufällige Collect-Loo-Drops wurde auf {chance} gesetzt"
+ "description": "Die Wahrscheinlichkeit für zufällige Collect-Loot-Drops wurde auf {chance}% gesetzt"
},
"collectLootDropClaimed": {
"title": "Glückwunsch :tada:",
From e5865e200b783d0ab5d232b411255ae04300cfc2 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Fri, 10 May 2024 11:35:47 +0200
Subject: [PATCH 46/66] add missing permissions annotation for
SwitchDailyMessageCommand
---
.../nplaybot/rank/daily/SwitchDailyMessageCommand.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/daily/SwitchDailyMessageCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/daily/SwitchDailyMessageCommand.java
index 8301a57..d1cd90f 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/daily/SwitchDailyMessageCommand.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/daily/SwitchDailyMessageCommand.java
@@ -3,12 +3,15 @@
import com.github.kaktushose.jda.commands.annotations.Inject;
import com.github.kaktushose.jda.commands.annotations.interactions.Interaction;
import com.github.kaktushose.jda.commands.annotations.interactions.Param;
+import com.github.kaktushose.jda.commands.annotations.interactions.Permissions;
import com.github.kaktushose.jda.commands.annotations.interactions.SlashCommand;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
import com.github.kaktushose.nplaybot.Database;
+import com.github.kaktushose.nplaybot.permissions.BotPermissions;
@Interaction
+@Permissions(BotPermissions.USER)
public class SwitchDailyMessageCommand {
@Inject
From cb5544485c49e3526a5742c9cf0e4130910140e2 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Fri, 10 May 2024 11:41:26 +0200
Subject: [PATCH 47/66] fix Leaderboard index numbers
---
.../nplaybot/rank/leaderboard/LeaderboardCommand.java | 2 +-
.../kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
index b320d37..c142e0f 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardCommand.java
@@ -78,7 +78,7 @@ public void onEnd(ComponentEvent event) {
private void reply(Replyable event) {
log.debug("Sending new leaderboard with index {}/{}", index, maxIndex);
event.with(getButtons()).reply(
- embedCache.getEmbed("leaderboard").injectValue("leaderboard", leaderboard.get(index - 1).getPage(guild))
+ embedCache.getEmbed("leaderboard").injectValue("leaderboard", leaderboard.get(index - 1).getPage(guild, index - 1))
.toEmbedBuilder()
.setFooter(String.format("Seite (%d/%d)", index, maxIndex))
);
diff --git a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java
index c8c1376..bc4b910 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/rank/leaderboard/LeaderboardPage.java
@@ -8,11 +8,11 @@
import java.util.Optional;
public record LeaderboardPage(List rows) {
- public String getPage(Guild guild) {
+ public String getPage(Guild guild, int index) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < rows.size(); i++) {
var row = rows.get(i);
- appendRow(builder, i + 1, resolveName(guild, row.userId), row.xp, String.format("<@&%d>", row.roleId));
+ appendRow(builder, (i + 1) + index * 10, resolveName(guild, row.userId), row.xp, String.format("<@&%d>", row.roleId));
}
return builder.toString();
}
From f1b6cee45472e9faca802c72af54fc0313c89434 Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Fri, 10 May 2024 12:10:34 +0200
Subject: [PATCH 48/66] adjust embed builder link
---
embeds.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/embeds.json b/embeds.json
index 45e1a5a..9a209c4 100644
--- a/embeds.json
+++ b/embeds.json
@@ -163,7 +163,7 @@
},
"rewardCreateInvalidEmbed": {
"title": "Belohnung: {name}",
- "description": "Bitte gib ein gültiges Embed im JSON-Format an. [Online Embed Builder](https://glitchii.github.io/embedbuilder/)",
+ "description": "Bitte gib ein gültiges Embed im JSON-Format an. [Online Embed Builder](https://glitchii.github.io/embedbuilder/?single=true&data=e30=)",
"color": "#ffc926"
},
"rewardCreateSummarize": {
From 12e432d16146ac5df454da4128fdf64a438916ee Mon Sep 17 00:00:00 2001
From: Kaktushose <42280757+Kaktushose@users.noreply.github.com>
Date: Fri, 10 May 2024 14:32:00 +0200
Subject: [PATCH 49/66] refactor permissions commands
---
embeds.json | 12 +-
pom.xml | 2 +-
.../nplaybot/permissions/BotPermissions.java | 34 +++--
.../permissions/PermissionCommands.java | 116 +++++++++++-------
.../permissions/PermissionsService.java | 70 ++++++++---
.../V2.1.0__add_role_permissions.sql | 23 ++++
6 files changed, 182 insertions(+), 75 deletions(-)
create mode 100644 src/main/resources/db/migration/V2.1.0__add_role_permissions.sql
diff --git a/embeds.json b/embeds.json
index 9a209c4..f3c4bc9 100644
--- a/embeds.json
+++ b/embeds.json
@@ -136,14 +136,14 @@
"description": "{channels}",
"color": "#67c94f"
},
- "userPermissions": {
- "title": "Berechtigungen von {user}",
- "description": "{permissions}",
+ "permissionsEdit": {
+ "title": "Berechtigungen von {target}",
+ "description": "Bearbeite die Berechtigungen, indem du sie im Select Menü an- oder abwählst",
"color": "#67c94f"
},
- "permissionsBulkEdit": {
- "title": "Erfolg",
- "description": "Die Berechtigungen wurden angepasst",
+ "permissionsList": {
+ "title": "Berechtigungen von {target}",
+ "description": "{permissions}",
"color": "#67c94f"
},
"rewardCreateSelectType": {
diff --git a/pom.xml b/pom.xml
index 5e23208..9797aa4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,7 +77,7 @@
com.github.Kaktushose
jda-commands
- da36e41af0
+ 649440b3e8
com.zaxxer
diff --git a/src/main/java/com/github/kaktushose/nplaybot/permissions/BotPermissions.java b/src/main/java/com/github/kaktushose/nplaybot/permissions/BotPermissions.java
index 825560f..e3319a6 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/permissions/BotPermissions.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/permissions/BotPermissions.java
@@ -1,8 +1,6 @@
package com.github.kaktushose.nplaybot.permissions;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
public class BotPermissions {
@@ -29,24 +27,42 @@ public class BotPermissions {
public static int compute(Set permissions) {
int computedPermissions = 0;
for (String permission : permissions) {
- computedPermissions = computedPermissions | permissionMapping.getOrDefault(permission, 0);
+ computedPermissions = computedPermissions | getPermissionValue(permission);
}
return computedPermissions;
}
public static boolean hasPermissions(Set permissions, int userPermission) {
- if (userPermission == permissionMapping.get(BOT_OWNER)) {
+ if (userPermission == getPermissionValue(BOT_OWNER)) {
return true;
}
return (userPermission & compute(permissions)) != 0;
}
- public static int grant(int currentPermissions, String permission) {
- return currentPermissions |= permissionMapping.getOrDefault(permission, 0);
+ public static int combine(Collection permissions) {
+ int result = 0;
+ for (int permission : permissions) {
+ result |= permission;
+ }
+ return result;
+ }
+
+ public static Map permissionsMapping() {
+ return new LinkedHashMap<>(permissionMapping);
+ }
+
+ public static int getPermissionValue(String permission) {
+ return permissionMapping.getOrDefault(permission, 0);
}
- public static int revoke(int currentPermissions, String permission) {
- return currentPermissions &= ~permissionMapping.getOrDefault(permission, 0);
+ public static Set getRawPermissionsValues(int permissions) {
+ Set result = new HashSet<>();
+ permissionMapping.forEach((name, value) -> {
+ if (hasPermissions(Set.of(name), permissions)) {
+ result.add(value);
+ }
+ });
+ return result;
}
public static String listPermissions(int permissions) {
diff --git a/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionCommands.java b/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionCommands.java
index 36402ba..48f4b75 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionCommands.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionCommands.java
@@ -4,83 +4,111 @@
import com.github.kaktushose.jda.commands.annotations.interactions.*;
import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.jda.commands.dispatching.interactions.commands.CommandEvent;
+import com.github.kaktushose.jda.commands.dispatching.interactions.components.ComponentEvent;
import com.github.kaktushose.nplaybot.Database;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
+import net.dv8tion.jda.api.interactions.components.selections.SelectMenu;
+
+import java.util.List;
import static com.github.kaktushose.nplaybot.permissions.BotPermissions.*;
@Interaction
public class PermissionCommands {
+ private static final String NONE = "NONE";
@Inject
private Database database;
@Inject
private EmbedCache embedCache;
+ private Member targetMember;
+ private Role targetRole;
@SlashCommand(value = "permissions list", desc = "Zeigt die Berechtigungen eines Users an", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
@Permissions(USER)
public void onPermissionsList(CommandEvent event, @Optional Member member) {
var target = member == null ? event.getMember() : member;
- event.reply(embedCache.getEmbed("userPermissions")
- .injectValue("user", target.getEffectiveName())
- .injectValue("permissions", BotPermissions.listPermissions(database.getPermissionsService().getPermissions(target)))
+ event.reply(embedCache.getEmbed("permissionsList")
+ .injectValue("target", target.getEffectiveName())
+ .injectValue("permissions", BotPermissions.listPermissions(database.getPermissionsService().getMemberPermissions(target)))
);
}
- @SlashCommand(value = "permissions grant", desc = "Fügt einem Nutzer eine Berechtigung hinzu", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @SlashCommand(value = "permissions user edit", desc = "Bearbeitet die Berechtigungen von einem Nutzer. Hat keinen Einfluss auf die Rollen-Berechtigungen", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
@Permissions(MODIFY_USER_PERMISSIONS)
- public void onPermissionsGrant(CommandEvent event,
- Member member,
- @Param("Die Berechtigung die hinzugefügt werden soll")
- @Choices({USER, MODIFY_USER_BALANCE, MODIFY_RANK_SETTINGS, MANAGE_EVENTS, MODIFY_USER_PERMISSIONS, BOT_ADMINISTRATOR})
- String permission) {
- database.getPermissionsService().grantPermissions(member, permission);
-
- event.reply(embedCache.getEmbed("userPermissions")
- .injectValue("user", member.getEffectiveName())
- .injectValue("permissions", BotPermissions.listPermissions(database.getPermissionsService().getPermissions(member)))
- );
+ public void onPermissionsUserEdit(CommandEvent event, Member member) {
+ targetMember = member;
+
+ var permissionsMap = BotPermissions.permissionsMapping();
+ permissionsMap.put(NONE, 0);
+ permissionsMap.remove(BOT_OWNER);
+
+ var menu = ((net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu)
+ event.getJdaCommands().getSelectMenu(
+ "PermissionCommands.onPermissionsUserSelect",
+ event.getContext().getRuntime().getRuntimeId())
+ ).createCopy();
+ menu.getOptions().clear();
+ menu.setMaxValues(SelectMenu.OPTIONS_MAX_AMOUNT);
+
+ permissionsMap.forEach((label, value) -> menu.addOption(label, String.valueOf(value)));
+ var permissions = database.getPermissionsService().getUserPermissions(member.getUser());
+ menu.setDefaultValues(BotPermissions.getRawPermissionsValues(permissions).stream().map(String::valueOf).toList());
+
+ event.getReplyContext().getBuilder().addActionRow(menu.build());
+ event.reply(embedCache.getEmbed("permissionsEdit").injectValue("target", targetMember.getEffectiveName()));
}
- @SlashCommand(value = "permissions revoke", desc = "Entzieht einem Nutzer eine Berechtigung", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @StringSelectMenu(value = "Wähle eine oder mehrere Berechtigungen aus")
+ @SelectOption(label = "dummy option", value = "dummy option")
@Permissions(MODIFY_USER_PERMISSIONS)
- public void onPermissionsRevoke(CommandEvent event,
- Member member,
- @Param("Die Berechtigung die entzogen werden soll")
- @Choices({USER, MODIFY_USER_BALANCE, MODIFY_RANK_SETTINGS, MANAGE_EVENTS, MODIFY_USER_PERMISSIONS, BOT_ADMINISTRATOR})
- String permission) {
- database.getPermissionsService().revokePermissions(member, permission);
-
- event.reply(embedCache.getEmbed("userPermissions")
- .injectValue("user", member.getEffectiveName())
- .injectValue("permissions", BotPermissions.listPermissions(database.getPermissionsService().getPermissions(member)))
+ public void onPermissionsUserSelect(ComponentEvent event, List selection) {
+ database.getPermissionsService().setUserPermissions(targetMember, BotPermissions.combine(selection.stream().map(Integer::valueOf).toList()));
+
+ event.keepComponents(false).reply(embedCache.getEmbed("permissionsList")
+ .injectValue("target", targetMember.getEffectiveName())
+ .injectValue("permissions", BotPermissions.listPermissions(database.getPermissionsService().getUserPermissions(targetMember.getUser())))
);
}
- @SlashCommand(value = "permissions bulk grant", desc = "Fügt allen Nutzern mit der angegebenen Rolle eine Berechtigung hinzu", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @SlashCommand(value = "permissions role edit", desc = "Bearbeitet die Berechtigungen von einer Rolle", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
@Permissions(MODIFY_USER_PERMISSIONS)
- public void onPermissionsBulkGrant(CommandEvent event,
- Role role,
- @Param("Die Berechtigung die hinzugefügt werden soll")
- @Choices({USER, MODIFY_USER_BALANCE, MODIFY_RANK_SETTINGS, MANAGE_EVENTS, MODIFY_USER_PERMISSIONS, BOT_ADMINISTRATOR})
- String permission) {
- event.getGuild().getMembersWithRoles(role).forEach(member -> database.getPermissionsService().grantPermissions(member, permission));
-
- event.reply(embedCache.getEmbed("permissionsBulkEdit"));
+ public void onPermissionsRoleEdit(CommandEvent event, Role role) {
+ targetRole = role;
+
+ var permissionsMap = BotPermissions.permissionsMapping();
+ permissionsMap.put(NONE, 0);
+ permissionsMap.remove(USER);
+ permissionsMap.remove(BOT_OWNER);
+
+ var menu = ((net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu)
+ event.getJdaCommands().getSelectMenu(
+ "PermissionCommands.onPermissionsRoleSelect",
+ event.getContext().getRuntime().getRuntimeId())
+ ).createCopy();
+ menu.getOptions().clear();
+ menu.setMaxValues(SelectMenu.OPTIONS_MAX_AMOUNT);
+
+ permissionsMap.forEach((label, value) -> menu.addOption(label, String.valueOf(value)));
+ var permissions = database.getPermissionsService().getRolePermissions(List.of(targetRole));
+ menu.setDefaultValues(BotPermissions.getRawPermissionsValues(permissions).stream().map(String::valueOf).toList());
+
+ event.getReplyContext().getBuilder().addActionRow(menu.build());
+ event.reply(embedCache.getEmbed("permissionsEdit").injectValue("target", targetRole.getName()));
}
- @SlashCommand(value = "permissions bulk revoke", desc = "Entzieht allen Nutzern mit der angegebenen Rolle eine Berechtigung", isGuildOnly = true, enabledFor = Permission.BAN_MEMBERS)
+ @StringSelectMenu(value = "Wähle eine oder mehrere Berechtigungen aus")
+ @SelectOption(label = "dummy option", value = "dummy option")
@Permissions(MODIFY_USER_PERMISSIONS)
- public void onPermissionsBulkRevoke(CommandEvent event,
- Role role,
- @Param("Die Berechtigung die entzogen werden soll")
- @Choices({USER, MODIFY_USER_BALANCE, MODIFY_RANK_SETTINGS, MANAGE_EVENTS, MODIFY_USER_PERMISSIONS, BOT_ADMINISTRATOR})
- String permission) {
- event.getGuild().getMembersWithRoles(role).forEach(member -> database.getPermissionsService().revokePermissions(member, permission));
-
- event.reply(embedCache.getEmbed("permissionsBulkEdit"));
+ public void onPermissionsRoleSelect(ComponentEvent event, List selection) {
+ database.getPermissionsService().setRolePermissions(targetRole, BotPermissions.combine(selection.stream().map(Integer::valueOf).toList()));
+
+ event.keepComponents(false).reply(embedCache.getEmbed("permissionsList")
+ .injectValue("target", targetRole.getName())
+ .injectValue("permissions", BotPermissions.listPermissions(database.getPermissionsService().getRolePermissions(List.of(targetRole))))
+ );
}
}
diff --git a/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionsService.java b/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionsService.java
index 1c855ec..4b74f3d 100644
--- a/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionsService.java
+++ b/src/main/java/com/github/kaktushose/nplaybot/permissions/PermissionsService.java
@@ -1,6 +1,6 @@
package com.github.kaktushose.nplaybot.permissions;
-import net.dv8tion.jda.api.entities.UserSnowflake;
+import net.dv8tion.jda.api.entities.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -8,6 +8,7 @@
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
+import java.util.List;
import java.util.Set;
public class PermissionsService {
@@ -19,7 +20,7 @@ public PermissionsService(DataSource dataSource) {
this.dataSource = dataSource;
}
- public int getPermissions(UserSnowflake user) {
+ public int getUserPermissions(User user) {
log.debug("Querying permissions for user {}", user);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
@@ -38,8 +39,42 @@ public int getPermissions(UserSnowflake user) {
}
}
- public void grantPermissions(UserSnowflake user, String permission) {
- log.warn("Granting permission {} for user {}", permission, user);
+ public int getRolePermissions(List roles) {
+ log.debug("Querying permissions for member roles");
+ try (Connection connection = dataSource.getConnection()) {
+ var statement = connection.prepareStatement("SELECT * FROM get_role_permissions(?)");
+ statement.setArray(1, connection.createArrayOf("BIGINT", roles.stream().map(ISnowflake::getIdLong).toArray()));
+ var result = statement.executeQuery();
+ result.next();
+ var permissions = result.getInt(1);
+ if (permissions >= BotPermissions.getPermissionValue(BotPermissions.BOT_OWNER)) {
+ permissions = BotPermissions.getPermissionValue(BotPermissions.BOT_OWNER);
+ }
+ return permissions;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Returns the combined permissions from {@link #getUserPermissions(User)} and {@link #getRolePermissions(List)} for
+ * the given member
+ *
+ * @param member the {@link Member} to return the combined permissions for
+ * @return the combined permissions
+ */
+ public int getMemberPermissions(Member member) {
+ log.debug("Querying permissions for member {}", member);
+ int permissions = getUserPermissions(member.getUser()) | getRolePermissions(member.getRoles());
+
+ if (permissions >= BotPermissions.getPermissionValue(BotPermissions.BOT_OWNER)) {
+ permissions = BotPermissions.getPermissionValue(BotPermissions.BOT_OWNER);
+ }
+ return permissions;
+ }
+
+ public void setUserPermissions(UserSnowflake user, int permissions) {
+ log.info("Granting permission {} for user {}", permissions, user);
try (Connection connection = dataSource.getConnection()) {
PreparedStatement statement = connection.prepareStatement("""
UPDATE users
@@ -48,7 +83,7 @@ public void grantPermissions(UserSnowflake user, String permission) {
"""
);
- statement.setLong(1, BotPermissions.grant(getPermissions(user), permission));
+ statement.setLong(1, permissions);
statement.setLong(2, user.getIdLong());
statement.execute();
@@ -57,27 +92,32 @@ public void grantPermissions(UserSnowflake user, String permission) {
}
}
- public void revokePermissions(UserSnowflake user, String permission) {
- log.warn("Revoking permission {} for user {}", permission, user);
+ public void setRolePermissions(Role role, int permissions) {
+ log.info("Granting permission {} for role {}", permissions, role);
try (Connection connection = dataSource.getConnection()) {
PreparedStatement statement = connection.prepareStatement("""
- UPDATE users
- SET permissions = ?
- WHERE user_id = ?
+ INSERT INTO role_permissions
+ VALUES(?, ?)
+ ON CONFLICT (role_id) DO UPDATE SET permissions = EXCLUDED.permissions;
"""
);
- statement.setLong(1, BotPermissions.revoke(getPermissions(user), permission));
- statement.setLong(2, user.getIdLong());
-
+ statement.setLong(1, role.getIdLong());
+ statement.setLong(2, permissions);
statement.execute();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
- public boolean hasPermissions(UserSnowflake user, Set