diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..ebe3a024 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +This project does not accept pull requests. + +If you would like to modify or extend the bot, please feel free to fork the repository and maintain your own version. + +Bug reports and suggestions are welcome through the Issues tab. I may review and address them as time permits. \ No newline at end of file diff --git a/LICENSE b/LICENSE index b09cd785..0ad25db4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,661 @@ -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. + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 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 Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are 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. + + 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. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + 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 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 work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + 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 AGPL, see +. diff --git a/PRIVACY.md b/PRIVACY.md index f0e076ee..f2a76e93 100644 --- a/PRIVACY.md +++ b/PRIVACY.md @@ -1,6 +1,8 @@ # Privacy Policy -**Data Controller:** This project is maintained by [@Egg-03](https://github.com/eggy03). +**Data Controller:** This project is maintained by [@Egg-03](https://github.com/eggy03). + +**Last Updated:** February 16, 2026 This Discord bot was built as an open source project with a privacy-first mindset. The Service is provided at no cost and is intended for use as-is. @@ -33,52 +35,70 @@ The bot only stores data when specific features are explicitly enabled by server ### If **Message Logging** is enabled: - Message Content - Message ID -- Author ID (Discord user ID) +- Author ID (Discord user ID of the message owner) - Channel ID - Guild ID - Timestamp -Message content is stored in plain text and is not used for analytics or shared outside your server. - ### If **only Audit Logging** is enabled: - Guild ID - Channel ID where audit logs should be sent (one per guild) -No message content or user data is stored in this case. +No message content, message ID or Author ID is stored in this case. -The stored data is used solely for server moderation purposes. +**Note on Direct Messages (DMs)**: The bot does not monitor, read, or store data from Direct Messages between users. +It only processes data within Discord Guilds (servers) where it has been explicitly invited. --- ## Data Retention -- All stored message contents and their metadata are automatically deleted after **30 days**. -- No data is permanently retained or used for any analytics. -- Configuration data (e.g., log channel IDs) is kept until the server administrator unregisters the bot or removes it from the server. -- Server administrators can also request immediate deletion of all stored data for their guild by contacting us. +We adhere to a strict data minimization policy. +Information is only retained for the duration necessary to provide the bot's logging features. + +- **Temporary Message Logs**: All captured message content (text-only) and metadata logs are stored for a maximum period + of 30 days. + Following this period, data is programmatically purged from our production databases. +- **System Backups**: Data contained within database backups may persist for up to an additional 7 days beyond the + standard retention period before being overwritten. +- **Administrative Data**: Configuration settings (e.g. designated log channels) are retained as long as the bot + remains authorized within the Discord Guild. --- -## Diagnostic Logs +## Data Security -In case of runtime errors, the bot may log basic diagnostic information such as error messages, timestamps, and internal event states to assist with debugging. -Logs may include additional metadata such as guild IDs, channel IDs, message IDs, or user IDs when necessary to diagnose issues. +We implement reasonable technical and organizational measures to protect stored data from unauthorized access, loss, +or misuse. This includes strict access controls, limited operator access, and infrastructure security best practices. -Log retention is governed by our infrastructure providers and operational requirements, and may vary over time. -Logs are not used for analytics. +**Infrastructure & Storage** ---- +- Cloud Providers: We utilize `Northflank` for application hosting and `Aiven` for managed database services. +- Encryption: While all collected data is stored in a readable format, our infrastructure providers employ encryption + to protect data on the physical disk level. To know more, read their security + policies of our providers [Northflank](https://northflank.com/security) + and [Aiven](https://aiven.io/security-compliance). + +**Access Control** -## Security +Access to the production environment and database is strictly limited to the Data Controller (@Egg-03). +No other contributors or third parties have access to the raw data stored by the bot. -We take reasonable technical and organizational measures to protect stored data from unauthorized access, loss, or misuse. -This includes access controls, limited operator access, and infrastructure security best practices. +**Disclaimer** -Message content is stored in plain text on cloud infrastructure. -This is the same general model used by Discord (i.e., messages are not end-to-end encrypted). -We do not perform analytics on message content. +While we strive to use commercially acceptable means to protect your information, no method of transmission over the +internet or method of electronic storage is 100% secure. +We cannot guarantee absolute security and the service is provided on an "as-is" basis. -However, no method of transmission over the internet or method of electronic storage is 100% secure, and we cannot guarantee absolute security. +--- + +## Diagnostic Logs + +In case of runtime errors, the bot may log basic diagnostic information such as error messages, timestamps, and internal event states to assist with debugging. +Logs may include additional metadata such as guild IDs, channel IDs, message IDs, or user IDs when necessary to diagnose issues. + +Log retention is governed by our infrastructure providers and operational requirements, and may vary over time. +Logs are not used for analytics. --- @@ -91,16 +111,15 @@ If it is discovered that such data has been inadvertently stored, it will be del ## User Rights -All users, regardless of location, have the following rights: - -- **Right of Access**: You may request what data (if any) is associated with your Discord user ID. -- **Right to Erasure**: You may request deletion of your data from the database. +We respect the privacy rights of all Discord users. Regardless of your jurisdiction, you may exercise the following: -To protect user privacy, we will verify the identity of the requestor before fulfilling access or deletion requests (for example: confirmation from the guild owner or proof of control of the Discord user account). -We will respond to verified requests within 30 days. -If additional information is needed, we will notify you and may extend the response period where permitted by law. +- **Right to Access**: Users may request a transcript of all stored data associated with their Discord Snowflake ID. +- **Right to Erasure**: Users may request the immediate removal of their data from our active logs. -To request access or deletion, please contact us using the method below. +To submit a request: Please contact us using one of the methods below. +For security purposes, we may require you to verify your identity via a signed message or a direct interaction through +the official Discord client. +NOTE: We will never ask for any kinds of passwords or secret tokens from you. --- diff --git a/README.md b/README.md index ed4a09ae..958e1d0f 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,147 @@ # Overview -PaperTrail is a free and open-source, self-hostable, and privacy-friendly Discord bot designed to provide audit log data directly in a channelβ€”without requiring users to navigate server settings each time. + +PaperTrail is a free and open-source, self-hostable, and privacy-friendly Discord bot +designed to provide audit log data directly in a channel without requiring users to navigate server settings each time. Key Features: -- Full audit log integration (supports over 50+ event types) and generic support for unknown types +- Full audit log integration (supports over 72 event types) and generic support for unknown types - Message logging (edit, delete) - Member activity tracking (joins, leaves, kicks, bans, updates) - Voice activity logging (join/leave, move) - Auto-deletion of logged messages after 30 days +> Get it from here: https://discord.com/discovery/applications/1381658412550590475 + +# Repositories + +| Repository | Description | +|---------------------------------------------------------------------------------------|------------------------------------------| +| [PaperTrailBot](https://github.com/eggy03/PaperTrailBot) | Core bot application | +| [PaperTrail SDK](https://github.com/eggy03/papertrail-sdk) | Client library for the API | +| [PaperTrail Persistence Service](https://github.com/eggy03/PaperTrail-PersistenceAPI) | Backend API for providing CRUD functions | + > [!IMPORTANT] > PaperTrail is currently in maintenance mode. Existing bugs will be fixed, dependency updates will be provided > but large new features will likely not be added. # Self-Hosting Guide + > [!IMPORTANT] -> It is recommended that you deploy the [Persistence API](https://github.com/Egg-03/PaperTrail-PersistenceAPI?tab=readme-ov-file#papertrail-persistenceapi) service before deploying the bot itself since the bot relies on the URL of the service to communicate +> Please note that this is only for advanced users who want to self-host this bot +> +> Set up the API Service before setting up the bot + +## Setting up the API Service + +Follow this [guide](https://github.com/Egg-03/PaperTrail-PersistenceAPI?tab=readme-ov-file#papertrail-persistenceapi) + +## Setting up the Bot Service + +### Step 1: Create an application in the Developer Portal + +Log on to the [Discord Developer Portal](https://discord.com/developers/applications) and create an application. + +The application can have any name, avatar, banner and description but the following scopes, permissions and intents are +needed +for it to work properly: + +**Installation Contexts** -The project is split into two services: -1) The core bot service -2) A [Persistence API](https://github.com/Egg-03/PaperTrail-PersistenceAPI) service +1) Guild Install -The following guide shows how to set up the bot service +**Scopes** -To read the guide on deploying the Persistence API Service, click [here](https://github.com/eggy03/PaperTrail-PersistenceAPI?tab=readme-ov-file#papertrail-persistenceapi) +1) applications.commands +2) bot -### Step 1: Get Required Secrets +**Permissions** + +1) Manage Server +2) Read Message History +3) Send Messages +4) Send Messages In Threads +5) View Audit Log +6) View Channels + +**Privileged Gateway Intents** + +1) Presence Intent +2) Server Members Intent +3) Message Content Intent + +Don't forget to copy the `bot token` as it will be required in the next step + +### Step 2: Get Required Secrets You will need the following environment variables to run the bot: -| Variable | Description | -|-----------|-----------------------------------------------------------------------------------------------------------| -| `TOKEN` | Discord application bot token (from the [Developer Portal](https://discord.com/developers/applications)) | -| `API_URL` | Internal URL of the Persistence API (e.g., `http://persistence:8080`) | +| Variable | Description | +|----------------|-----------------------------------------------------------------------| +| `TOKEN` | Discord application bot token (from the Developer Portal) | +| `API_URL` | Internal URL of the Persistence API (e.g., `http://persistence:8080`) | +| `TOTAL_SHARDS` | The total number of shards (connections) your bot is using overall. | +| `MIN_SHARD_ID` | The first shard number this bot instance should handle. | +| `MAX_SHARD_ID` | The last shard number this bot instance should handle. | + +Each shard allows handling up-to 2500 guilds. + +Take a look at the following configuration examples to have a clearer picture of what values to put +for your use-case + +**1: JVM Instance / 1-2500 Guilds / 1 Shard** + +If your bot is small or self-hosted for a limited number of servers, you only need one shard. +This should be sufficient for the majority of self-host users + +```dotenv +TOTAL_SHARDS=1 +MIN_SHARD_ID=0 +MAX_SHARD_ID=0 +``` + +**2: JVM Instance /2500-5000 Guilds / 2 Shards** -### Step 2: Deployment Options +If your bot is in more than 2,500 servers, but you are still running a single JVM instance, you can increase the total +shard count: + +```dotenv +TOTAL_SHARDS=2 +MIN_SHARD_ID=0 +MAX_SHARD_ID=1 +``` + +Remember that each shard can only handle up to 2500 guilds so plan the total number shards accordingly + +**3: JVM Instances / 25000 Guilds / 10 Shards** + +If you scale your bot horizontally, you need to split the shards between them. + +Instance 1: + +```dotenv +TOTAL_SHARDS=10 +MIN_SHARD_ID=0 +MAX_SHARD_ID=4 +``` + +Instance 2: + +```dotenv +TOTAL_SHARDS=10 +MIN_SHARD_ID=5 +MAX_SHARD_ID=9 +``` + +Shard ID ranges must never overlap between running instances. + +### Step 3: Deployment Options Fork this repository to your GitHub account, connect it to your preferred cloud platform, and configure your environment variables in the platform. Some platform services may also support adding secrets directly from your `.env` file. #### Cloud Platforms with GitHub + Docker Support - These can auto-deploy using the included `Dockerfile` -- Optional: The bot exposes a `/ping` endpoint which can be used by platforms to periodically check for it's health #### Locally - You can also test it locally by building and running using the `Dockerfile` @@ -56,46 +156,13 @@ Some platform services may also support adding secrets directly from your `.env` The bot exposes a `/ping` endpoint on port **8080**. This endpoint simply returns `200 OK` and is intended for platforms or uptime monitors to check if the bot is alive. -> Note: This is **not a public API** and serves no other function beyond internal service health monitoring. - -# Privacy - -PaperTrail is built with privacy-first principles. By default, it **does not log any personal data** unless features are explicitly enabled by server admins. - -- Messages are logged for moderation purposes only, if enabled. -- Logs are automatically deleted after 30 days. -- No personal data is used for analytics, profiling, or sold to third parties. -- If requested, users can have their data deleted by ID. - -*Never post sensitive information in public channels.* - -[Read the full Privacy Policy](./PRIVACY.md) - -# Security - -If you discover a security vulnerability in PaperTrail, please report it **privately**. - -- Do **not** open public GitHub issues for security bugs. -- Instead, email me at πŸ“§ **eggzerothree@proton.me** -- I will respond as soon as possible and work with you to resolve the issue. - -[View the full Security Policy](./SECURITY.md) - -# Terms of Use - -PaperTrail is provided under the Apache 2.0 License and is intended for responsible use. -By using the official hosted instance or self-hosting it, you agree to the basic terms outlined in our [Terms of Service](./TERMS.md). +> Note: This is **not a public endpoint** and serves no other function beyond internal service health monitoring. # License -PaperTrail is licensed under the [Apache License 2.0](./LICENSE). - -You are free to: -- Use, modify, and redistribute the code -- Self-host or publicly host your own instance -- Build on top of this bot for your own projects - -Just make sure to include proper attribution and comply with the [terms](https://www.apache.org/licenses/LICENSE-2.0). +- **PaperTrailBot**: AGPLv3 +- **PaperTrail Persistence API**: AGPLv3 +- **PaperTrail SDK**: GNU GPLv3 --- -Feel free to contribute to this guide or raise issues on GitHub if you get stuck! +Feel free to raise issues on GitHub if you get stuck! diff --git a/TERMS.md b/TERMS.md index 5c66e6d7..238c6b5a 100644 --- a/TERMS.md +++ b/TERMS.md @@ -1,6 +1,6 @@ # Terms of Service -_Last updated: February 02, 2026_ +_Last updated: February 16, 2026_ Thank you for using **PaperTrail**, an open-source Discord audit and message logging bot. @@ -24,7 +24,7 @@ You agree to use the bot responsibly, and not for any of the following: ## 2. Privacy This bot logs message and event data **only if you enable those features**. -Message content is stored in plain text and logs are automatically deleted after 30 days. +All content is stored in a readable format . See our [Privacy Policy](./PRIVACY.md) for full details on data handling, retention, and user rights. @@ -43,8 +43,7 @@ The project maintainers are not responsible for how self-hosted instances handle ## 4. Modifications -You are free to fork, modify, or self-host this project under the terms of the [Apache 2.0 License](./LICENSE). -If you publicly redistribute a modified version, you must preserve the original license and attribution. +You are free to fork, modify, or self-host this project under the terms of the [AGPLv3](./LICENSE). --- diff --git a/pom.xml b/pom.xml index 97bd8993..4c2fc4ef 100644 --- a/pom.xml +++ b/pom.xml @@ -4,11 +4,11 @@ 4.0.0 - org.egg.papertrail - paper-trail-bot - 2.5.0 - PaperTrail - A simple bot for logging all user actions + io.github.eggy03 + papertrailbot + 3.0.0 + PaperTrail Bot + A simple bot for logging all server and member actions UTF-8 @@ -17,15 +17,13 @@ 21 - 6.3.0 - 1.0.0 + 6.3.1 + 1.0.1 2.7.0 3.2.0 - 3.19.0 - 1.9.3 - 1.83 - 33.4.8-jre - 7.0.3 + 3.20.0 + 33.5.0-jre + 7.0.4 2.13.2 1.18.42 @@ -83,18 +81,6 @@ ${commons-lang3.version} - - org.jasypt - jasypt - ${jasypt.version} - - - - org.bouncycastle - bcprov-jdk18on - ${bouncycastle.version} - - com.google.guava guava @@ -136,7 +122,7 @@ spring-boot-maven-plugin ${spring-boot-maven-plugin.version} - org.papertrail.main.Start + io.github.eggy03.papertrail.bot.main.Start diff --git a/src/main/java/io/github/eggy03/papertrail/bot/commons/constant/ProjectInfo.java b/src/main/java/io/github/eggy03/papertrail/bot/commons/constant/ProjectInfo.java new file mode 100644 index 00000000..c4e24b65 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/commons/constant/ProjectInfo.java @@ -0,0 +1,17 @@ +package io.github.eggy03.papertrail.bot.commons.constant; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; + +@UtilityClass +public class ProjectInfo { + + @NonNull + public static final String APPNAME = "PaperTrail"; + + @NonNull + public static final String VERSION = "v3.0.0"; + + @NonNull + public static final String PROJECT_ISSUE_LINK = "https://github.com/eggy03/PaperTrailBot/issues"; +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/BooleanUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/BooleanUtils.java new file mode 100644 index 00000000..cea106f4 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/BooleanUtils.java @@ -0,0 +1,57 @@ +package io.github.eggy03.papertrail.bot.commons.utils; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@UtilityClass +@Slf4j +public class BooleanUtils { + + @NonNull + private static final String FALLBACK_STRING = "N/A"; + + @NotNull + public static String formatToEmoji(@Nullable Object booleanValueObject) { + + if (booleanValueObject == null) { + log.debug("boolean value for formatting to emoji is null (caller={})", StackWalkerUtils.getCallHierarchy()); + return FALLBACK_STRING; + } + + if (Boolean.TRUE.equals(booleanValueObject)) + return "βœ…"; + + return "❌"; + } + + @NotNull + public static String formatToYesOrNo(@Nullable Object booleanValueObject) { + + if (booleanValueObject == null) { + log.debug("boolean value for formatting to yes/no is null (caller={})", StackWalkerUtils.getCallHierarchy()); + return FALLBACK_STRING; + } + + + if (Boolean.TRUE.equals(booleanValueObject)) + return "Yes"; + + return "No"; + } + + @NotNull + public static String formatToEnabledOrDisabled(@Nullable Object booleanValueObject) { + if (booleanValueObject == null) { + log.debug("boolean value for formatting to enabled/disabled is null (caller={})", StackWalkerUtils.getCallHierarchy()); + return FALLBACK_STRING; + } + + if (Boolean.TRUE.equals(booleanValueObject)) + return "Enabled"; + + return "Disabled"; + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/DurationUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/DurationUtils.java new file mode 100644 index 00000000..b635d058 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/DurationUtils.java @@ -0,0 +1,102 @@ +package io.github.eggy03.papertrail.bot.commons.utils; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.Nullable; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +@UtilityClass +@Slf4j +public class DurationUtils { + + @NonNull + private static final String FALLBACK_STRING = "N/A"; + + public static String formatSeconds(@Nullable Object seconds) { + if (seconds == null) { + log.debug("seconds value is null (caller={})", StackWalkerUtils.getCallHierarchy()); + return FALLBACK_STRING; + } + + try { + long secondsLong = Long.parseLong(seconds.toString()); + if (secondsLong == 0L) return "No Limits"; + Duration d = Duration.ofSeconds(secondsLong); + long durationDays = d.toDays(); + long durationHours = d.toHoursPart(); + long durationMinutes = d.toMinutesPart(); + long durationSeconds = d.toSecondsPart(); + + StringBuilder sb = new StringBuilder(); + + if (durationDays > 0) + sb.append(durationDays).append("d "); + if (durationHours > 0) + sb.append(durationHours).append("h "); + if (durationMinutes > 0) + sb.append(durationMinutes).append("m "); + if (durationSeconds > 0) + sb.append(durationSeconds).append("s"); + + return sb.toString().trim(); + } catch (NumberFormatException e) { + log.debug("failed to parse seconds from value={} (caller={})", seconds, StackWalkerUtils.getCallHierarchy()); + return String.valueOf(seconds); + } + + + } + + public static String formatMinutes(@Nullable Object minutes) { + if (minutes == null) { + log.debug("minutes value is null (caller={})", StackWalkerUtils.getCallHierarchy()); + return FALLBACK_STRING; + } + try { + long minutesLong = Long.parseLong(minutes.toString()); + if (minutesLong == 0L) return "No Limits"; + Duration d = Duration.ofMinutes(minutesLong); + long days = d.toDays(); + long hours = d.toHoursPart(); + + StringBuilder sb = new StringBuilder(); + if (days > 0) sb.append(days).append("d "); + if (hours > 0) sb.append(hours).append("h "); + return sb.toString().trim(); + } catch (NumberFormatException e) { + log.debug("failed to parse minutes from value={} (caller={})", minutes, StackWalkerUtils.getCallHierarchy()); + return String.valueOf(minutes); + } + + + } + + public static String isoToLocalTimeCounter(@Nullable Object isoTime) { + + if (isoTime == null) { + log.debug("iso time is null (caller={})", StackWalkerUtils.getCallHierarchy()); + return FALLBACK_STRING; + } + + String isoTimeString = String.valueOf(isoTime); + if (isoTimeString.trim().isEmpty()) { + log.debug("iso time is blank (caller={})", StackWalkerUtils.getCallHierarchy()); + return FALLBACK_STRING; + } + + try { + OffsetDateTime odt = OffsetDateTime.parse(isoTimeString, DateTimeFormatter.ISO_OFFSET_DATE_TIME); + long unixTimestamp = odt.toEpochSecond(); + return ""; + } catch (DateTimeParseException e) { + log.debug("failed to parse ISO_OFFSET_DATE_TIME from value={} (caller={})", isoTimeString, StackWalkerUtils.getCallHierarchy()); + return String.valueOf(isoTime); + } + + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/EnvConfig.java b/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/EnvConfig.java new file mode 100644 index 00000000..d7ce3fd7 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/EnvConfig.java @@ -0,0 +1,22 @@ +package io.github.eggy03.papertrail.bot.commons.utils; + +import io.github.cdimascio.dotenv.Dotenv; +import lombok.NonNull; +import lombok.experimental.UtilityClass; + +@UtilityClass +public class EnvConfig { + + @NonNull + private static final Dotenv dotenv = Dotenv.configure().ignoreIfMalformed().ignoreIfMissing().load(); + + public static String get(String key) { + + String value = dotenv.get(key); + if (value != null) { + return value; + } + + return System.getenv(key); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/NumberParseUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/NumberParseUtils.java new file mode 100644 index 00000000..1eb42f66 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/NumberParseUtils.java @@ -0,0 +1,63 @@ +package io.github.eggy03.papertrail.bot.commons.utils; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.Nullable; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +@UtilityClass +@Slf4j +public class NumberParseUtils { + + @Nullable + public static Long parseLong(@Nullable Object possibleLongValue) { + + if (possibleLongValue == null) { + log.debug("long value is null (caller={})", StackWalkerUtils.getCallHierarchy()); + return null; + } + + try { + return Long.parseLong(String.valueOf(possibleLongValue)); + } catch (NumberFormatException e) { + log.debug("failed to parse long from value={} (caller={})", possibleLongValue, StackWalkerUtils.getCallHierarchy()); + return null; + } + } + + @Nullable + public static Integer parseInt(@Nullable Object possibleIntegerValue) { + + if (possibleIntegerValue == null) { + log.debug("int value is null (caller={})", StackWalkerUtils.getCallHierarchy()); + return null; + } + try { + return Integer.parseInt(String.valueOf(possibleIntegerValue)); + } catch (NumberFormatException e) { + log.debug("failed to parse int from value={} (caller={})", possibleIntegerValue, StackWalkerUtils.getCallHierarchy()); + return null; + } + } + + @Nullable + public static Double parseDouble(@Nullable Object possibleDoubleValue, int roundingDigits, @NonNull RoundingMode roundingMode) { + + if (possibleDoubleValue == null) { + log.debug("double value is null (caller={})", StackWalkerUtils.getCallHierarchy()); + return null; + } + + try { + double doubleValue = Double.parseDouble(String.valueOf(possibleDoubleValue)); + return BigDecimal.valueOf(doubleValue).setScale(roundingDigits, roundingMode).doubleValue(); + } catch (NumberFormatException e) { + log.debug("failed to parse double from value={}, roundingDigits={}, roundingMode={} (caller={})" + , possibleDoubleValue, roundingDigits, roundingMode, StackWalkerUtils.getCallHierarchy()); + return null; + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/StackWalkerUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/StackWalkerUtils.java new file mode 100644 index 00000000..ec5c0037 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/commons/utils/StackWalkerUtils.java @@ -0,0 +1,25 @@ +package io.github.eggy03.papertrail.bot.commons.utils; + +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; + +import java.util.stream.Collectors; + +@UtilityClass +public class StackWalkerUtils { + + private static final StackWalker STACK_WALKER = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); + + // will show call hierarchies + @NotNull + public static String getCallHierarchy() { + return STACK_WALKER.walk(frames -> frames + .skip(1) + .limit(3) + .map(frame -> frame.getDeclaringClass().getSimpleName() + + "#" + frame.getMethodName() + + ":" + frame.getLineNumber() + ).collect(Collectors.joining(" -> ")) + ); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/event/AuditLogEventListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/event/AuditLogEventListener.java new file mode 100644 index 00000000..55171228 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/event/AuditLogEventListener.java @@ -0,0 +1,209 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.event; + +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod.AutoModerationFlagToChannelEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod.AutoModerationMemberTimeoutEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod.AutoModerationRuleBlockMessageEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod.AutoModerationRuleCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod.AutoModerationRuleDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod.AutoModerationRuleUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.bot.BotAddEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.ChannelCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.ChannelDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.ChannelOverrideCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.ChannelOverrideDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.ChannelOverrideUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.ChannelUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.VoiceChannelStatusDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.VoiceChannelStatusUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.emoji.EmojiCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.emoji.EmojiDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.emoji.EmojiUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.generic.GenericAuditLogEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.guild.GuildProfileUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.guild.GuildUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.homesettings.HomeSettingsCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.homesettings.HomeSettingsUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.integration.ApplicationCommandPrivilegesUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.integration.IntegrationCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.integration.IntegrationDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.invite.InviteCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.invite.InviteDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.member.MemberRoleUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.member.MemberUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.member.MemberVoiceKickEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.member.MemberVoiceMoveEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.message.MessagePinEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.message.MessageUnpinEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.modactions.BanEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.modactions.KickEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.modactions.UnbanEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.onboarding.OnboardingPromptCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.onboarding.OnboardingPromptDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.onboarding.OnboardingPromptUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.onboarding.OnboardingUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.role.RoleCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.role.RoleDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.role.RoleUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.scheduledevent.ScheduledEventCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.scheduledevent.ScheduledEventDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.scheduledevent.ScheduledEventUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.soundboard.SoundboardSoundCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.soundboard.SoundboardSoundDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.soundboard.SoundboardSoundUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.stage.StageInstanceCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.stage.StageInstanceDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.stage.StageInstanceUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.sticker.StickerCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.sticker.StickerDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.sticker.StickerUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.thread.ThreadCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.thread.ThreadDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.thread.ThreadUpdateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.webhook.WebhookCreateEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.webhook.WebhookRemoveEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.webhook.WebhookUpdateEventHelper; +import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; +import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.audit.ActionType; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; +import java.util.concurrent.Executor; + +@Slf4j +@RequiredArgsConstructor +public class AuditLogEventListener extends ListenerAdapter { + + @NonNull + private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); + + @NonNull + private final Executor vThreadPool; + + @Override + public void onGuildAuditLogEntryCreate(@NotNull GuildAuditLogEntryCreateEvent event) { + vThreadPool.execute(() -> { + // Call the API and see if the event came from a registered Guild + Optional response = client.getRegisteredGuild(event.getGuild().getId()); + response.ifPresent(success -> auditLogParser(event, success.getChannelId())); + }); + } + + private void auditLogParser(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + AuditLogEntry ale = event.getEntry(); + ActionType action = ale.getType(); + switch (action) { + + case AUTO_MODERATION_FLAG_TO_CHANNEL -> + AutoModerationFlagToChannelEventHelper.format(event, channelIdToSendTo); + case AUTO_MODERATION_MEMBER_TIMEOUT -> + AutoModerationMemberTimeoutEventHelper.format(event, channelIdToSendTo); + case AUTO_MODERATION_RULE_BLOCK_MESSAGE -> + AutoModerationRuleBlockMessageEventHelper.format(event, channelIdToSendTo); + case AUTO_MODERATION_RULE_CREATE -> AutoModerationRuleCreateEventHelper.format(event, channelIdToSendTo); + case AUTO_MODERATION_RULE_UPDATE -> AutoModerationRuleUpdateEventHelper.format(event, channelIdToSendTo); + case AUTO_MODERATION_RULE_DELETE -> AutoModerationRuleDeleteEventHelper.format(event, channelIdToSendTo); + + case KICK -> KickEventHelper.format(event, channelIdToSendTo); + case BAN -> BanEventHelper.format(event, channelIdToSendTo); + case UNBAN -> UnbanEventHelper.format(event, channelIdToSendTo); + case BOT_ADD -> BotAddEventHelper.format(event, channelIdToSendTo); + // PRUNE has generic formatting + + case CHANNEL_CREATE -> ChannelCreateEventHelper.format(event, channelIdToSendTo); + case CHANNEL_UPDATE -> ChannelUpdateEventHelper.format(event, channelIdToSendTo); + case CHANNEL_DELETE -> ChannelDeleteEventHelper.format(event, channelIdToSendTo); + case CHANNEL_OVERRIDE_CREATE -> ChannelOverrideCreateEventHelper.format(event, channelIdToSendTo); + case CHANNEL_OVERRIDE_UPDATE -> ChannelOverrideUpdateEventHelper.format(event, channelIdToSendTo); + case CHANNEL_OVERRIDE_DELETE -> ChannelOverrideDeleteEventHelper.format(event, channelIdToSendTo); + + case ROLE_CREATE -> RoleCreateEventHelper.format(event, channelIdToSendTo); + case ROLE_UPDATE -> RoleUpdateEventHelper.format(event, channelIdToSendTo); + case ROLE_DELETE -> RoleDeleteEventHelper.format(event, channelIdToSendTo); + + case EMOJI_CREATE -> EmojiCreateEventHelper.format(event, channelIdToSendTo); + case EMOJI_UPDATE -> EmojiUpdateEventHelper.format(event, channelIdToSendTo); + case EMOJI_DELETE -> EmojiDeleteEventHelper.format(event, channelIdToSendTo); + + case STICKER_CREATE -> StickerCreateEventHelper.format(event, channelIdToSendTo); + case STICKER_UPDATE -> StickerUpdateEventHelper.format(event, channelIdToSendTo); + case STICKER_DELETE -> StickerDeleteEventHelper.format(event, channelIdToSendTo); + + case GUILD_UPDATE -> GuildUpdateEventHelper.format(event, channelIdToSendTo); + case GUILD_PROFILE_UPDATE -> GuildProfileUpdateEventHelper.format(event, channelIdToSendTo); + + case INTEGRATION_CREATE -> IntegrationCreateEventHelper.format(event, channelIdToSendTo); + case INTEGRATION_DELETE -> IntegrationDeleteEventHelper.format(event, channelIdToSendTo); + case APPLICATION_COMMAND_PRIVILEGES_UPDATE -> + ApplicationCommandPrivilegesUpdateEventHelper.format(event, channelIdToSendTo); + // INTEGRATION_UPDATE has generic formatting + + case INVITE_CREATE -> InviteCreateEventHelper.format(event, channelIdToSendTo); + case INVITE_DELETE -> InviteDeleteEventHelper.format(event, channelIdToSendTo); + // INVITE_UPDATE has generic formatting + + case MEMBER_ROLE_UPDATE -> MemberRoleUpdateEventHelper.format(event, channelIdToSendTo); + case MEMBER_UPDATE -> MemberUpdateEventHelper.format(event, channelIdToSendTo); + + case MEMBER_VOICE_KICK -> MemberVoiceKickEventHelper.format(event, channelIdToSendTo); + case MEMBER_VOICE_MOVE -> MemberVoiceMoveEventHelper.format(event, channelIdToSendTo); + + case MESSAGE_PIN -> MessagePinEventHelper.format(event, channelIdToSendTo); + case MESSAGE_UNPIN -> MessageUnpinEventHelper.format(event, channelIdToSendTo); + + case SCHEDULED_EVENT_CREATE -> ScheduledEventCreateEventHelper.format(event, channelIdToSendTo); + case SCHEDULED_EVENT_UPDATE -> ScheduledEventUpdateEventHelper.format(event, channelIdToSendTo); + case SCHEDULED_EVENT_DELETE -> ScheduledEventDeleteEventHelper.format(event, channelIdToSendTo); + + case STAGE_INSTANCE_CREATE -> StageInstanceCreateEventHelper.format(event, channelIdToSendTo); + case STAGE_INSTANCE_UPDATE -> StageInstanceUpdateEventHelper.format(event, channelIdToSendTo); + case STAGE_INSTANCE_DELETE -> StageInstanceDeleteEventHelper.format(event, channelIdToSendTo); + + case THREAD_CREATE -> ThreadCreateEventHelper.format(event, channelIdToSendTo); + case THREAD_UPDATE -> ThreadUpdateEventHelper.format(event, channelIdToSendTo); + case THREAD_DELETE -> ThreadDeleteEventHelper.format(event, channelIdToSendTo); + + case VOICE_CHANNEL_STATUS_DELETE -> VoiceChannelStatusDeleteEventHelper.format(event, channelIdToSendTo); + case VOICE_CHANNEL_STATUS_UPDATE -> VoiceChannelStatusUpdateEventHelper.format(event, channelIdToSendTo); + + case WEBHOOK_CREATE -> WebhookCreateEventHelper.format(event, channelIdToSendTo); + case WEBHOOK_UPDATE -> WebhookUpdateEventHelper.format(event, channelIdToSendTo); + case WEBHOOK_REMOVE -> WebhookRemoveEventHelper.format(event, channelIdToSendTo); + + case SOUNDBOARD_SOUND_CREATE -> SoundboardSoundCreateEventHelper.format(event, channelIdToSendTo); + case SOUNDBOARD_SOUND_UPDATE -> SoundboardSoundUpdateEventHelper.format(event, channelIdToSendTo); + case SOUNDBOARD_SOUND_DELETE -> SoundboardSoundDeleteEventHelper.format(event, channelIdToSendTo); + + case ONBOARDING_UPDATE -> OnboardingUpdateEventHelper.format(event, channelIdToSendTo); + case ONBOARDING_PROMPT_CREATE -> OnboardingPromptCreateEventHelper.format(event, channelIdToSendTo); + case ONBOARDING_PROMPT_UPDATE -> OnboardingPromptUpdateEventHelper.format(event, channelIdToSendTo); + case ONBOARDING_PROMPT_DELETE -> OnboardingPromptDeleteEventHelper.format(event, channelIdToSendTo); + + case HOME_SETTINGS_CREATE -> HomeSettingsCreateEventHelper.format(event, channelIdToSendTo); + case HOME_SETTINGS_UPDATE -> HomeSettingsUpdateEventHelper.format(event, channelIdToSendTo); + + // these seemingly don't trigger properly, or are unreliable + case MESSAGE_BULK_DELETE, + MESSAGE_CREATE, + MESSAGE_DELETE, + MESSAGE_UPDATE -> GenericAuditLogEventHelper.format(event, channelIdToSendTo); + + // except UNKNOWN, the rest have never been seen to be triggered + case PRUNE, INTEGRATION_UPDATE, + INVITE_UPDATE, ONBOARDING_CREATE, + UNKNOWN -> GenericAuditLogEventHelper.format(event, channelIdToSendTo); + + default -> { + GenericAuditLogEventHelper.format(event, channelIdToSendTo); + log.warn("The following event is either not covered by JDA's UNKNOWN type or is not implemented by PaperTrail yet {}", ale.getType().name()); + } + } + } +} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationFlagToChannelEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationFlagToChannelEventHelper.java similarity index 51% rename from src/main/java/org/papertrail/listeners/audit/helper/AutoModerationFlagToChannelEventHelper.java rename to src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationFlagToChannelEventHelper.java index fcdb0bc8..40613b88 100644 --- a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationFlagToChannelEventHelper.java +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationFlagToChannelEventHelper.java @@ -1,9 +1,10 @@ -package org.papertrail.listeners.audit.helper; +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod; +import lombok.NonNull; import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; @@ -11,29 +12,38 @@ import java.awt.Color; @UtilityClass +@Slf4j public class AutoModerationFlagToChannelEventHelper { - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Automod Event"); + eb.setTitle("Audit Log Entry | Auto-Mod Event"); User targetUser = ale.getJDA().getUserById(ale.getTargetId()); String mentionableTargetUser = (targetUser != null ? targetUser.getAsMention() : ale.getTargetId()); - eb.setDescription("πŸ›ˆ Automod has flagged a message sent by: "+mentionableTargetUser); + eb.setDescription("Auto-mod has flagged a message sent by: " + mentionableTargetUser); eb.setColor(Color.YELLOW); eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); + eb.addField("Info", "For more info, check the channel where auto-mod is set to send events", false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); } } } diff --git a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationMemberTimeoutEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationMemberTimeoutEventHelper.java similarity index 51% rename from src/main/java/org/papertrail/listeners/audit/helper/AutoModerationMemberTimeoutEventHelper.java rename to src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationMemberTimeoutEventHelper.java index 32b5a99a..61c18e39 100644 --- a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationMemberTimeoutEventHelper.java +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationMemberTimeoutEventHelper.java @@ -1,9 +1,10 @@ -package org.papertrail.listeners.audit.helper; +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod; +import lombok.NonNull; import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; @@ -11,29 +12,38 @@ import java.awt.Color; @UtilityClass +@Slf4j public class AutoModerationMemberTimeoutEventHelper { - public static void format (GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Automod Event"); + eb.setTitle("Audit Log Entry | Auto-mod Event"); User targetUser = ale.getJDA().getUserById(ale.getTargetId()); String mentionableTargetUser = (targetUser != null ? targetUser.getAsMention() : ale.getTargetId()); - eb.setDescription("πŸ›ˆ Automod has timed out"+mentionableTargetUser+" for a defined rule violation"); + eb.setDescription("Auto-mod has timed out " + mentionableTargetUser + " for a defined rule violation"); eb.setColor(Color.MAGENTA); eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); + eb.addField("Info", "For more info, check the channel where auto-mod is set to send events", false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); } } } diff --git a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleBlockMessageEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleBlockMessageEventHelper.java similarity index 51% rename from src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleBlockMessageEventHelper.java rename to src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleBlockMessageEventHelper.java index 97d26f89..80265ffd 100644 --- a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleBlockMessageEventHelper.java +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleBlockMessageEventHelper.java @@ -1,9 +1,10 @@ -package org.papertrail.listeners.audit.helper; +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod; +import lombok.NonNull; import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; @@ -11,29 +12,38 @@ import java.awt.Color; @UtilityClass +@Slf4j public class AutoModerationRuleBlockMessageEventHelper { - public static void format (GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Automod Event"); + eb.setTitle("Audit Log Entry | Auto-mod Event"); User targetUser = ale.getJDA().getUserById(ale.getTargetId()); String mentionableTargetUser = (targetUser != null ? targetUser.getAsMention() : ale.getTargetId()); - eb.setDescription("πŸ›ˆ Automod has blocked a message sent by: "+mentionableTargetUser); + eb.setDescription("Auto-mod has blocked a message sent by: " + mentionableTargetUser); eb.setColor(Color.ORANGE); eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); + eb.addField("Info", "For more info, check the channel where auto-mod is set to send events", false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); } } } diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleCreateEventHelper.java new file mode 100644 index 00000000..5f05ad5d --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleCreateEventHelper.java @@ -0,0 +1,72 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod.utils.AutoModUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class AutoModerationRuleCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | AutoMod Rule Create"); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + eb.setDescription("ℹ️ The following AutoMod rule was created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "enabled" -> eb.addField("Enabled", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), false); + + case "trigger_type" -> + eb.addField("Trigger Type", "β•°β”ˆβž€" + AutoModUtils.autoModTriggerTypeResolver(newValue), false); + + case "event_type" -> + eb.addField("Event Type", "β•°β”ˆβž€" + AutoModUtils.autoModEventTypeResolver(newValue), false); + + case "name" -> eb.addField("AutoMod Rule Name ", "β•°β”ˆβž€" + newValue, false); + + default -> { + // ignore everything else + } + } + }); + + eb.addField("Additional Info", "For more info on trigger metadata, actions, exempt roles and channels, visit Safety Setup in your server", false); + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleDeleteEventHelper.java new file mode 100644 index 00000000..8084852a --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleDeleteEventHelper.java @@ -0,0 +1,56 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class AutoModerationRuleDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | AutoMod Rule Delete"); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + eb.setDescription("ℹ️ The following AutoMod rule was deleted by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + + if (changeKey.equals("name")) { + eb.addField("AutoMod Rule Name ", "β•°β”ˆβž€" + oldValue, false); + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleUpdateEventHelper.java new file mode 100644 index 00000000..d8b30a57 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/AutoModerationRuleUpdateEventHelper.java @@ -0,0 +1,54 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.automod.AutoModRule; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class AutoModerationRuleUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | AutoMod Rule Update"); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + eb.setDescription("ℹ️ The following AutoMod rule was updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + // add name of the rule which got updated + AutoModRule rule = ale.getGuild().retrieveAutoModRuleById(ale.getTargetId()).complete(); + eb.addField("AutoMod Rule Name ", "β•°β”ˆβž€" + rule.getName(), false); + + eb.addField("Additional Info", "For more info on trigger metadata, actions, exempt roles and channel changes, visit Safety Setup in your server", false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/utils/AutoModUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/utils/AutoModUtils.java new file mode 100644 index 00000000..4717a051 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/automod/utils/AutoModUtils.java @@ -0,0 +1,42 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.automod.utils; + +import io.github.eggy03.papertrail.bot.commons.utils.NumberParseUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import net.dv8tion.jda.api.entities.automod.AutoModEventType; +import net.dv8tion.jda.api.entities.automod.AutoModTriggerType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + + +/* + * See {@link io.github.eggy03.papertrail.bot.commons.utils.StackWalkerUtils} + * and other utilities in the util package + * to know why logging isn't needed here + */ +@UtilityClass +public class AutoModUtils { + + @NonNull + public static final String FALLBACK_STRING = "N/A"; + + @NotNull + public static String autoModEventTypeResolver(@Nullable Object autoModEventTypeInteger) { + Integer eventTypeInt = NumberParseUtils.parseInt(autoModEventTypeInteger); + if (eventTypeInt == null) { + return FALLBACK_STRING; + } + + return AutoModEventType.fromKey(eventTypeInt).name(); + } + + @NotNull + public static String autoModTriggerTypeResolver(@Nullable Object autoModTriggerTypeInteger) { + Integer triggerTypeInt = NumberParseUtils.parseInt(autoModTriggerTypeInteger); + if (triggerTypeInt == null) + return FALLBACK_STRING; + + + return AutoModTriggerType.fromKey(triggerTypeInt).name(); + } +} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/BotAddEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/bot/BotAddEventHelper.java similarity index 54% rename from src/main/java/org/papertrail/listeners/audit/helper/BotAddEventHelper.java rename to src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/bot/BotAddEventHelper.java index d2640d34..ff6685ce 100644 --- a/src/main/java/org/papertrail/listeners/audit/helper/BotAddEventHelper.java +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/bot/BotAddEventHelper.java @@ -1,9 +1,10 @@ -package org.papertrail.listeners.audit.helper; +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.bot; +import lombok.NonNull; import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; @@ -11,34 +12,40 @@ import java.awt.Color; @UtilityClass +@Slf4j public class BotAddEventHelper { - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Bot Add Event"); + AuditLogEntry ale = event.getEntry(); User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - User target = ale.getJDA().getUserById(ale.getTargetIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTarget = (target !=null ? target.getAsMention() : ale.getTargetId()); - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A bot was added"); + User target = ale.getJDA().getUserById(ale.getTargetIdLong()); + String mentionableTarget = (target != null ? target.getAsMention() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Bot Add Event"); + eb.setDescription("ℹ️ A bot was added by: " + mentionableExecutor); eb.setColor(Color.CYAN); eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.addField("πŸ€– Added a bot: ", "β•°β”ˆβž€"+mentionableTarget, false); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); + eb.addField("Bot Added: ", "β•°β”ˆβž€" + mentionableTarget, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); } } } diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelCreateEventHelper.java new file mode 100644 index 00000000..3e5215e4 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelCreateEventHelper.java @@ -0,0 +1,91 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.commons.utils.DurationUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.utils.ChannelUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ChannelCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + GuildChannel targetChannel = ale.getGuild().getGuildChannelById(ale.getTargetId()); + String mentionableTargetChannel = (targetChannel != null ? targetChannel.getAsMention() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Channel Create Event"); + + eb.setDescription("ℹ️ The following channel was created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "user_limit" -> + eb.addField("User Limit", "β•°β”ˆβž€" + ChannelUtils.resolveVoiceChannelUserLimit(newValue), false); + + case "rate_limit_per_user" -> + eb.addField("Slow Mode", "β•°β”ˆβž€" + DurationUtils.formatSeconds(newValue), false); + + case "type" -> eb.addField("Channel Type", "β•°β”ˆβž€" + ChannelUtils.resolveChannelType(newValue), false); + + case "nsfw" -> eb.addField("Is NSFW", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), false); + + case "name" -> { + eb.addField("Channel Name", "β•°β”ˆβž€" + newValue, false); + eb.addField("Channel Mention", "β•°β”ˆβž€" + mentionableTargetChannel, true); + } + + case "bitrate" -> + eb.addField("Voice Channel Bitrate", "β•°β”ˆβž€" + ChannelUtils.resolveVoiceChannelBitrate(newValue), false); + + case "permission_overwrites", "flags", "template", "available_tags" -> { + // the first two are for all types of channels and may stay empty during creation events + // the second two are forum only cases which stay empty during creation + } + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelDeleteEventHelper.java new file mode 100644 index 00000000..5b57177c --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelDeleteEventHelper.java @@ -0,0 +1,70 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.utils.ChannelUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ChannelDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + GuildChannel targetChannel = ale.getJDA().getGuildChannelById(ale.getTargetIdLong()); + + String mentionableTargetChannel = (targetChannel != null ? targetChannel.getAsMention() : ale.getTargetId()); // this will return only the ID cause the channel with the ID has been deleted + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Channel Delete Event"); + + eb.setDescription("ℹ️ The following channel was deleted by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + + switch (changeKey) { + case "name" -> eb.addField("Name", "β•°β”ˆβž€" + oldValue, false); + + case "type" -> eb.addField("Type", "β•°β”ˆβž€" + ChannelUtils.resolveChannelType(oldValue), false); + + default -> { + // omit all other fields + } + } + }); + + eb.addField("Deleted Channel ID", "β•°β”ˆβž€" + mentionableTargetChannel, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelOverrideCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelOverrideCreateEventHelper.java new file mode 100644 index 00000000..9919cbda --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelOverrideCreateEventHelper.java @@ -0,0 +1,81 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.utils.ChannelUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ChannelOverrideCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + GuildChannel targetChannel = event.getGuild().getGuildChannelById(ale.getTargetId()); + String mentionableTargetChannel = (targetChannel != null ? targetChannel.getAsMention() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Channel Override Create"); + eb.setDescription("ℹ️ The following channel overrides were created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "type" -> + eb.addField("Override Type", "β•°β”ˆβž€" + ChannelUtils.resolveChannelOverrideTargetType(newValue), false); + + case "deny" -> + eb.addField("Denied Permissions", ChannelUtils.resolveChannelOverridePermissions(newValue, "❌"), false); + case "allow" -> + eb.addField("Allowed Permissions", ChannelUtils.resolveChannelOverridePermissions(newValue, "βœ…"), false); + + // id exposes the member/role id which for which the channel permissions are overridden + // only one member/role permission id is fetched per loop + case "id" -> + eb.addField("Target", "β•°β”ˆβž€" + ChannelUtils.autoResolveMemberOrRole(newValue, event), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + // add the target channel whose permissions were overridden + // exposed via ALE's TargetID + eb.addField("Target Channel", "β•°β”ˆβž€" + mentionableTargetChannel, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelOverrideDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelOverrideDeleteEventHelper.java new file mode 100644 index 00000000..17b58769 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelOverrideDeleteEventHelper.java @@ -0,0 +1,81 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.utils.ChannelUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ChannelOverrideDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + GuildChannel targetChannel = event.getGuild().getGuildChannelById(ale.getTargetId()); + String mentionableTargetChannel = (targetChannel != null ? targetChannel.getAsMention() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Channel Override Delete"); + + eb.setDescription("ℹ️ The following channel overrides were deleted by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "type" -> + eb.addField("Override Type", "β•°β”ˆβž€" + ChannelUtils.resolveChannelOverrideTargetType(oldValue), false); + + case "deny" -> + eb.addField("Denied Permissions", ChannelUtils.resolveChannelOverridePermissions(oldValue, "❌"), false); + case "allow" -> + eb.addField("Allowed Permissions", ChannelUtils.resolveChannelOverridePermissions(oldValue, "βœ…"), false); + + // id exposes the member/role id which for which the channel permissions are overridden + // only one member/role permission id is fetched per loop + case "id" -> + eb.addField("Target", "β•°β”ˆβž€" + ChannelUtils.autoResolveMemberOrRole(oldValue, event), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + // add the target channel whose permissions were overridden + // can be retrieved via ALE's TargetID + eb.addField("Target Channel", "β•°β”ˆβž€" + mentionableTargetChannel, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelOverrideUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelOverrideUpdateEventHelper.java new file mode 100644 index 00000000..0f5694b7 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelOverrideUpdateEventHelper.java @@ -0,0 +1,113 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.utils.ChannelUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; +import org.jetbrains.annotations.NotNull; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ChannelOverrideUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + GuildChannel targetChannel = event.getGuild().getGuildChannelById(ale.getTargetId()); + String mentionableTargetChannel = (targetChannel != null ? targetChannel.getAsMention() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Channel Override Update"); + eb.setDescription("ℹ️ The following channel overrides were updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.addField("Override Type", "β•°β”ˆβž€" + ChannelUtils.resolveChannelOverrideTargetType(ale.getOptionByName("type")), false); + eb.addField("Permissions Overridden For", "β•°β”ˆβž€" + getTargetRoleOrMember(ale, event), false); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "deny" -> + eb.addField("Denied Permissions", ChannelUtils.resolveChannelOverridePermissions(newValue, "❌"), false); + case "allow" -> + eb.addField("Allowed Permissions", ChannelUtils.resolveChannelOverridePermissions(newValue, "βœ…"), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + + } + }); + + // add the target channel whose permissions were overridden + // can be retrieved via ALE's TargetID + eb.addField("Target Channel", "β•°β”ˆβž€" + mentionableTargetChannel, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } + + // ALE changes do not expose the id and type keys in case of override updates + // therefore, this hacky method is required + // IDK why channel override updates don't show this info + @NotNull + private static String getTargetRoleOrMember(@NonNull AuditLogEntry ale, @NonNull GuildAuditLogEntryCreateEvent event) { + + String overriddenId = ale.getOptionByName("id"); // id of the member or role + String overriddenType = ale.getOptionByName("type"); // type that determines if the ID is that of a role or a member + + if (overriddenId == null) + return "Member or Role ID is null"; + + return switch (overriddenType) { + + case "0" -> { + // It’s a role + Role role = event.getGuild().getRoleById(overriddenId); + yield role != null ? role.getAsMention() : overriddenId; + } + + case "1" -> { + // It's a member + Member member = event.getGuild().getMemberById(overriddenId); + yield member != null ? member.getAsMention() : overriddenId; + } + + case null -> "Override Type is null"; + default -> "Unimplemented Override Type: " + overriddenType; + + }; + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelUpdateEventHelper.java new file mode 100644 index 00000000..a2004e2b --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/ChannelUpdateEventHelper.java @@ -0,0 +1,144 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.commons.utils.DurationUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.utils.ChannelUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ChannelUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + GuildChannel targetChannel = event.getGuild().getGuildChannelById(ale.getTargetId()); + String mentionableTargetChannel = (targetChannel != null ? targetChannel.getAsMention() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Channel Update Event"); + + eb.setDescription("ℹ️ The following channel was updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + eb.addBlankField(true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "user_limit" -> { + eb.addField("Old User Limit", "β•°β”ˆβž€" + ChannelUtils.resolveVoiceChannelUserLimit(oldValue), true); + eb.addField("New User Limit", "β•°β”ˆβž€" + ChannelUtils.resolveVoiceChannelUserLimit(newValue), true); + eb.addBlankField(true); + } + + case "rate_limit_per_user" -> { + eb.addField("Old Slow mode Value", "β•°β”ˆβž€" + DurationUtils.formatSeconds(oldValue), true); + eb.addField("New Slow mode Value", "β•°β”ˆβž€" + DurationUtils.formatSeconds(newValue), true); + eb.addBlankField(true); + } + + case "default_thread_rate_limit_per_user" -> { + eb.addField("Old Thread Slow mode Value", "β•°β”ˆβž€" + DurationUtils.formatSeconds(oldValue), true); + eb.addField("New Thread Slow mode Value", "β•°β”ˆβž€" + DurationUtils.formatSeconds(newValue), true); + eb.addBlankField(true); + } + + case "nsfw" -> { + eb.addField("Was NSFW", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), true); + eb.addField("Is NSFW", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), true); + eb.addBlankField(true); + } + + case "video_quality_mode" -> { + eb.addField("Old Video Quality Mode", "β•°β”ˆβž€" + ChannelUtils.resolveVoiceChannelVideoQuality(oldValue), true); + eb.addField("New Video Quality Mode", "β•°β”ˆβž€" + ChannelUtils.resolveVoiceChannelVideoQuality(newValue), true); + eb.addBlankField(true); + } + + case "name" -> { + eb.addField("Old Channel Name", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Channel Name", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + + case "bitrate" -> { + eb.addField("Old Voice Channel Bitrate", "β•°β”ˆβž€" + ChannelUtils.resolveVoiceChannelBitrate(oldValue), true); + eb.addField("New Voice Channel Bitrate", "β•°β”ˆβž€" + ChannelUtils.resolveVoiceChannelBitrate(newValue), true); + eb.addBlankField(true); + } + + case "rtc_region" -> { + eb.addField("Old Region", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Region", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + + case "topic" -> { + eb.addField("Old Topic", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New topic", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + + case "default_auto_archive_duration" -> { + eb.addField("Old Hide After Inactivity Timer", "β•°β”ˆβž€" + DurationUtils.formatMinutes(oldValue), true); + eb.addField("New Hide After Inactivity Timer", "β•°β”ˆβž€" + DurationUtils.formatMinutes(newValue), true); + eb.addBlankField(true); + } + + case "type" -> { + eb.addField("Old Type", ChannelUtils.resolveChannelType(oldValue), true); + eb.addField("New Type", ChannelUtils.resolveChannelType(newValue), true); + eb.addBlankField(true); + } + + case "available_tags" -> eb.addField("Tags", "β•°β”ˆβž€The channel's tags were updated", false); + case "default_reaction_emoji" -> + eb.addField("Reaction Emoji", "β•°β”ˆβž€Default reaction emoji was updated", false); + case "flags" -> eb.addField("Flags", "β•°β”ˆβž€The channel's flags were updated", false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + + } + }); + + // mention the channel that got updated, id can be exposed via ALE's TargetID + eb.addField("Target Channel", "β•°β”ˆβž€" + mentionableTargetChannel, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/VoiceChannelStatusDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/VoiceChannelStatusDeleteEventHelper.java similarity index 59% rename from src/main/java/org/papertrail/listeners/audit/helper/VoiceChannelStatusDeleteEventHelper.java rename to src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/VoiceChannelStatusDeleteEventHelper.java index 75e35437..ba43dc80 100644 --- a/src/main/java/org/papertrail/listeners/audit/helper/VoiceChannelStatusDeleteEventHelper.java +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/VoiceChannelStatusDeleteEventHelper.java @@ -1,9 +1,10 @@ -package org.papertrail.listeners.audit.helper; +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel; +import lombok.NonNull; import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; @@ -12,11 +13,12 @@ import java.awt.Color; @UtilityClass +@Slf4j public class VoiceChannelStatusDeleteEventHelper { - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Voice Channel Status Delete"); + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); User executor = ale.getJDA().getUserById(ale.getUserId()); String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); @@ -24,20 +26,29 @@ public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale GuildChannel targetChannel = ale.getJDA().getGuildChannelById(ale.getTargetId()); String mentionableTargetChannel = (targetChannel != null ? targetChannel.getAsMention() : ale.getTargetId()); - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following voice channel's status was deleted: "+mentionableTargetChannel); + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Voice Channel Status Delete"); + + eb.setDescription("ℹ️ A voice channel's status was deleted"); eb.setColor(Color.ORANGE); eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); + eb.addField("Status Deleted By", "β•°β”ˆβž€" + mentionableExecutor, false); + eb.addField("Target Voice Channel", "β•°β”ˆβž€" + mentionableTargetChannel, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); } } } diff --git a/src/main/java/org/papertrail/listeners/audit/helper/VoiceChannelStatusUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/VoiceChannelStatusUpdateEventHelper.java similarity index 59% rename from src/main/java/org/papertrail/listeners/audit/helper/VoiceChannelStatusUpdateEventHelper.java rename to src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/VoiceChannelStatusUpdateEventHelper.java index bcfcf704..46d63384 100644 --- a/src/main/java/org/papertrail/listeners/audit/helper/VoiceChannelStatusUpdateEventHelper.java +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/VoiceChannelStatusUpdateEventHelper.java @@ -1,9 +1,10 @@ -package org.papertrail.listeners.audit.helper; +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel; +import lombok.NonNull; import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; @@ -12,11 +13,12 @@ import java.awt.Color; @UtilityClass +@Slf4j public class VoiceChannelStatusUpdateEventHelper { - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Voice Channel Status Update"); + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); User executor = ale.getJDA().getUserById(ale.getUserId()); String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); @@ -24,20 +26,29 @@ public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale GuildChannel targetChannel = ale.getJDA().getGuildChannelById(ale.getTargetId()); String mentionableTargetChannel = (targetChannel != null ? targetChannel.getAsMention() : ale.getTargetId()); - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following voice channel's status was updated: "+mentionableTargetChannel); + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Voice Channel Status Update"); + + eb.setDescription("ℹ️ A voice channel's status was updated"); eb.setColor(Color.YELLOW); eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); + eb.addField("Status Updated By", "β•°β”ˆβž€" + mentionableExecutor, false); + eb.addField("Target Voice Channel", "β•°β”ˆβž€" + mentionableTargetChannel, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); } } } diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/utils/ChannelUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/utils/ChannelUtils.java new file mode 100644 index 00000000..47b95c36 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/channel/utils/ChannelUtils.java @@ -0,0 +1,129 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.utils; + +import io.github.eggy03.papertrail.bot.commons.utils.NumberParseUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +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.entities.channel.ChannelType; +import net.dv8tion.jda.api.events.guild.GenericGuildEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.EnumSet; + +/* + * See {@link io.github.eggy03.papertrail.bot.commons.utils.StackWalkerUtils} + * and other utilities in the util package + * to know why logging isn't needed in some of the methods here + */ +@UtilityClass +@Slf4j +public class ChannelUtils { + + @NonNull + public static final String FALLBACK_STRING = "N/A"; + + /** + * can also be used for threads + */ + @NotNull + public static String resolveChannelType(@Nullable Object channelTypeInteger) { + + Integer channelType = NumberParseUtils.parseInt(channelTypeInteger); + if (channelType == null) + return FALLBACK_STRING; + + return ChannelType.fromId(channelType).name(); + } + + @NotNull + public static String resolveVoiceChannelUserLimit(@Nullable Object limitNumber) { + Integer userLimit = NumberParseUtils.parseInt(limitNumber); + if (userLimit == null) + return FALLBACK_STRING; + + return userLimit == 0 ? "Unlimited" : userLimit.toString(); + } + + @NotNull + public static String resolveVoiceChannelBitrate(@Nullable Object bitrateInteger) { + Integer bitrate = NumberParseUtils.parseInt(bitrateInteger); + if (bitrate == null) + return FALLBACK_STRING; + + return (bitrate / 1000) + " kbps"; + } + + @NotNull + public static String resolveVoiceChannelVideoQuality(@Nullable Object voiceChannelVideoQualityInteger) { + + Integer videoQuality = NumberParseUtils.parseInt(voiceChannelVideoQualityInteger); + + return switch (videoQuality) { + case 1 -> "Auto"; + case 2 -> "720p/full"; + case null -> FALLBACK_STRING; + default -> "Unknown Quality Mode: " + videoQuality; + }; + } + + // CHANNEL OVERRIDE UTILS + @NotNull + public static String resolveChannelOverrideTargetType(@Nullable Object targetTypeInteger) { + Integer targetType = NumberParseUtils.parseInt(targetTypeInteger); + + return switch (targetType) { + case 0 -> "Role"; + case 1 -> "Member/Application"; + case null -> FALLBACK_STRING; + default -> "Unknown Type: " + targetType; + }; + + } + + @NotNull + public static String resolveChannelOverridePermissions(@Nullable Object permissionValueLong, @NonNull String emoji) { + + Long permissionValue = NumberParseUtils.parseLong(permissionValueLong); + if (permissionValue == null) + return FALLBACK_STRING; + + if (permissionValue == 0) + return "β•°β”ˆβž€Permissions synced with category"; + + StringBuilder permissions = new StringBuilder(); + EnumSet permissionEnumSet = Permission.getPermissions(permissionValue); + permissionEnumSet.forEach(permission -> permissions + .append(emoji) + .append(" ") + .append(permission.getName()) + .append(System.lineSeparator())); + + return permissions.toString().trim(); + } + + // MISC UTILS + @NotNull + public static String autoResolveMemberOrRole(@Nullable Object memberOrRoleId, @NonNull GenericGuildEvent event) { + + if (memberOrRoleId == null) { + log.debug("null member/role id"); + return FALLBACK_STRING; + } + + Member mb = event.getGuild().getMemberById(String.valueOf(memberOrRoleId)); + Role r = event.getGuild().getRoleById(String.valueOf(memberOrRoleId)); + + if (mb != null) { + return mb.getAsMention(); + } else if (r != null) { + return r.getAsMention(); + } + + log.debug("ID doesn't belong to a member or a role, value: {}", memberOrRoleId); + return String.valueOf(memberOrRoleId); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/emoji/EmojiCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/emoji/EmojiCreateEventHelper.java new file mode 100644 index 00000000..b7602b3d --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/emoji/EmojiCreateEventHelper.java @@ -0,0 +1,60 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.emoji; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class EmojiCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Emoji Create Event"); + eb.setDescription("ℹ️ The following emoji was created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + if (changeKey.equals("name")) { + eb.addField("Emoji Name", "β•°β”ˆβž€" + newValue, false); + eb.addField("Emoji", "β•°β”ˆβž€" + "<:" + newValue + ":" + ale.getTargetId() + ">", false); // ale's TargetID retrieves the ID of the created emoji + } else { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/emoji/EmojiDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/emoji/EmojiDeleteEventHelper.java new file mode 100644 index 00000000..5cb91520 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/emoji/EmojiDeleteEventHelper.java @@ -0,0 +1,60 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.emoji; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class EmojiDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Emoji Delete Event"); + eb.setDescription("ℹ️ The following emoji was deleted by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + if (changeKey.equals("name")) { + eb.addField("Emoji Name", "β•°β”ˆβž€" + oldValue, false); + } else { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + }); + eb.addField("Deleted Emoji ID", "β•°β”ˆβž€" + ale.getTargetId(), false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/emoji/EmojiUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/emoji/EmojiUpdateEventHelper.java new file mode 100644 index 00000000..e9050f8d --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/emoji/EmojiUpdateEventHelper.java @@ -0,0 +1,61 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.emoji; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class EmojiUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Emoji Update Event"); + eb.setDescription("ℹ️ The following emoji was updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + if (changeKey.equals("name")) { + eb.addField("Emoji Name Updated", "β•°β”ˆβž€" + "From " + oldValue + " to " + newValue, false); + eb.addField("Target Emoji", "β•°β”ˆβž€" + "<:" + newValue + ":" + ale.getTargetId() + ">", false); + } else { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/generic/GenericAuditLogEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/generic/GenericAuditLogEventHelper.java new file mode 100644 index 00000000..da529486 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/generic/GenericAuditLogEventHelper.java @@ -0,0 +1,49 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.generic; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +// for events not defined by JDA yet or not implemented by papertrail +@UtilityClass +@Slf4j +public class GenericAuditLogEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = executor != null ? executor.getAsMention() : ale.getUserId(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Generic Event"); + eb.setDescription("An un-implemented action event has been triggered by: " + mentionableExecutor); + eb.setColor(Color.LIGHT_GRAY); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + eb.addField(changeKey, "OLD_VALUE: " + changeValue.getOldValue(), false); + eb.addField(changeKey, "NEW_VALUE: " + changeValue.getNewValue(), false); + }); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/guild/GuildProfileUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/guild/GuildProfileUpdateEventHelper.java new file mode 100644 index 00000000..09df7992 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/guild/GuildProfileUpdateEventHelper.java @@ -0,0 +1,55 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.guild; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class GuildProfileUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Guild Profile Update Event"); + eb.setDescription("ℹ️ The following guild profile updates were made by: " + mentionableExecutor); + eb.setColor(Color.PINK); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().keySet().forEach(key -> { + switch (key) { + case "traits" -> eb.addField("Server Traits", "β•°β”ˆβž€Server Traits have been updated", false); + case "visibility" -> eb.addField("Visibility", "β•°β”ˆβž€Profile Visibility has been changed", false); + case "brand_color_primary" -> eb.addField("Banner Color", "β•°β”ˆβž€Banner Color has been updated", false); + case "game_application_ids" -> eb.addField("Games", "β•°β”ˆβž€Games have been updated", false); + default -> eb.addField(key, "β•°β”ˆβž€" + key + " has/have been updated", false); + } + }); + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/guild/GuildUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/guild/GuildUpdateEventHelper.java new file mode 100644 index 00000000..339d3692 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/guild/GuildUpdateEventHelper.java @@ -0,0 +1,124 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.guild; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.commons.utils.DurationUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.guild.utils.GuildUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class GuildUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Guild Update Event"); + eb.setDescription("ℹ️ The following guild updates were made by: " + mentionableExecutor); + eb.setColor(Color.MAGENTA); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "description" -> { + eb.addField("Old Description", "β•°β”ˆβž€" + oldValue, false); + eb.addField("New Description", "β•°β”ˆβž€" + newValue, false); + } + + case "icon_hash" -> eb.addField("Icon Hash Change", "Guild Icon has been updated", false); + + case "name" -> { + eb.addField("Old Guild Name", "β•°β”ˆβž€" + oldValue, false); + eb.addField("New Guild Name", "β•°β”ˆβž€" + newValue, false); + } + + case "preferred_locale" -> eb.addField("Preferred Locale Set To", "β•°β”ˆβž€" + newValue, false); + + case "afk_channel_id" -> + eb.addField("AFK Channel Changed To", "β•°β”ˆβž€" + GuildUtils.resolveMentionableChannel(newValue, event), false); + + case "default_message_notifications" -> + eb.addField("Default Message Notifications Update", "β•°β”ˆβž€" + GuildUtils.resolveGuildDefaultMessageNotificationLevel(newValue), false); + + case "afk_timeout" -> + eb.addField("AFK Channel Timeout Change", "β•°β”ˆβž€" + DurationUtils.formatSeconds(newValue), false); + + case "system_channel_id" -> + eb.addField("Community Updates Channel Changed To", "β•°β”ˆβž€" + GuildUtils.resolveMentionableChannel(newValue, event), false); + + case "widget_enabled" -> + eb.addField("Widget Enabled", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), false); + + case "widget_channel_id" -> + eb.addField("Widget Channel Changed To", "β•°β”ˆβž€" + GuildUtils.resolveMentionableChannel(newValue, event), false); + + case "premium_progress_bar_enabled" -> + eb.addField("Server Boost Progress Bar Enabled", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), false); + + case "mfa_level" -> + eb.addField("MFA Requirement Set To", "β•°β”ˆβž€" + GuildUtils.resolveGuildModActionMFALevel(newValue), false); + + case "verification_level" -> + eb.addField("Verification Level Set To", "β•°β”ˆβž€" + GuildUtils.resolveGuildVerificationLevel(newValue), false); + + case "owner_id" -> { + User oldOwner = ale.getJDA().getUserById(String.valueOf(oldValue)); + User newOwner = ale.getJDA().getUserById(String.valueOf(newValue)); + String mentionableOldOwner = (oldOwner != null ? oldOwner.getAsMention() : String.valueOf(oldValue)); + String mentionableNewOwner = (newOwner != null ? newOwner.getAsMention() : String.valueOf(newValue)); + eb.addField("Old Owner", "β•°β”ˆβž€" + mentionableOldOwner, false); + eb.addField("New Owner", "β•°β”ˆβž€" + mentionableNewOwner, false); + } + + case "public_updates_channel_id" -> + eb.addField("Announcements Channel Changed To", "β•°β”ˆβž€" + GuildUtils.resolveMentionableChannel(newValue, event), false); + + case "rules_channel_id" -> + eb.addField("Rules Channel Changed To", "β•°β”ˆβž€" + GuildUtils.resolveMentionableChannel(newValue, event), false); + + case "system_channel_flags" -> + eb.addField("System Channel Flags", "β•°β”ˆβž€" + GuildUtils.resolveSystemChannelFlags(newValue), false); + + case "explicit_content_filter" -> + eb.addField("Explicit Content Filter", "β•°β”ˆβž€" + GuildUtils.resolveExplicitContentFilterLevel(newValue), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/guild/utils/GuildUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/guild/utils/GuildUtils.java new file mode 100644 index 00000000..33db0cce --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/guild/utils/GuildUtils.java @@ -0,0 +1,101 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.guild.utils; + +import io.github.eggy03.papertrail.bot.commons.utils.NumberParseUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.entities.guild.SystemChannelFlag; +import net.dv8tion.jda.api.events.guild.GenericGuildEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/* + * See {@link io.github.eggy03.papertrail.bot.commons.utils.StackWalkerUtils} + * and other utilities in the util package + * to know why logging isn't needed in some of the methods here + */ +@UtilityClass +public class GuildUtils { + + @NonNull + public static final String FALLBACK_STRING = "N/A"; + + // GUILD UTILS + @NotNull + public static String resolveGuildVerificationLevel(@Nullable Object verificationLevelInteger) { + + Integer verificationLevel = NumberParseUtils.parseInt(verificationLevelInteger); + return switch (verificationLevel) { //we could have used JDA's Guild.VerficationLevel but they don't have description + case 0 -> "NONE"; + case 1 -> "LOW (Verified Email)"; + case 2 -> "MEDIUM (Registered on Discord for more than 5 minutes"; + case 3 -> "HIGH (Must be a member of the server for longer than 10 minutes)"; + case 4 -> "VERY_HIGH (Must have a verified phone number)"; + case null -> FALLBACK_STRING; + default -> "Unknown"; + }; + + } + + @NotNull + public static String resolveGuildModActionMFALevel(@Nullable Object mfaLevelInteger) { + Integer mfaLevel = NumberParseUtils.parseInt(mfaLevelInteger); + if (mfaLevel == null) + return FALLBACK_STRING; + + return Guild.MFALevel.fromKey(mfaLevel).name(); + + } + + @NotNull + public static String resolveGuildDefaultMessageNotificationLevel(@Nullable Object notificationLevelInteger) { + Integer notificationLevel = NumberParseUtils.parseInt(notificationLevelInteger); + if (notificationLevel == null) + return FALLBACK_STRING; + + return Guild.NotificationLevel.fromKey(notificationLevel).name(); + + } + + @NotNull + public static String resolveExplicitContentFilterLevel(@Nullable Object explicitContentFilterLevelInteger) { + Integer ecfLevel = NumberParseUtils.parseInt(explicitContentFilterLevelInteger); + if (ecfLevel == null) + return FALLBACK_STRING; + + return Guild.ExplicitContentLevel.fromKey(ecfLevel).getDescription(); + } + + @NotNull + public static String resolveSystemChannelFlags(@Nullable Object systemChannelFlagsIntegerObject) { + Integer systemChannelFlagsInteger = NumberParseUtils.parseInt(systemChannelFlagsIntegerObject); + + if (systemChannelFlagsInteger == null) + return FALLBACK_STRING; + + if (systemChannelFlagsInteger == 0) + return "No Flags Suppressed"; + + StringBuilder systemChannelFlags = new StringBuilder(); + SystemChannelFlag + .getFlags(systemChannelFlagsInteger) + .forEach(flag -> + systemChannelFlags + .append(flag.name()) + .append(System.lineSeparator())); + + return systemChannelFlags.toString().trim(); + } + + // MISC GUILD UTILS (BROADER COVERAGE) + @NotNull + public static String resolveMentionableChannel(Object channelId, @NonNull GenericGuildEvent event) { + Long channelIdLong = NumberParseUtils.parseLong(channelId); + if (channelIdLong == null) + return FALLBACK_STRING; + + GuildChannel channel = event.getGuild().getGuildChannelById(channelIdLong); + return channel != null ? channel.getAsMention() : channelIdLong.toString(); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/homesettings/HomeSettingsCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/homesettings/HomeSettingsCreateEventHelper.java new file mode 100644 index 00000000..3d0fac09 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/homesettings/HomeSettingsCreateEventHelper.java @@ -0,0 +1,47 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.homesettings; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class HomeSettingsCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Server Guide Create Event"); + eb.setDescription("ℹ️ A server guide has been created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/homesettings/HomeSettingsUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/homesettings/HomeSettingsUpdateEventHelper.java new file mode 100644 index 00000000..dc4beba5 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/homesettings/HomeSettingsUpdateEventHelper.java @@ -0,0 +1,57 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.homesettings; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class HomeSettingsUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Server Guide Update Event"); + eb.setDescription("ℹ️ The server guide has been updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().keySet().forEach(key -> { + switch (key) { + case "welcome_message" -> eb.addField("Welcome Message", "β•°β”ˆβž€Welcome Message has been updated", false); + case "resource_channels" -> eb.addField("Resources", "β•°β”ˆβž€Resources have been updated", false); + case "new_member_actions" -> + eb.addField("New Member Join To-Do", "β•°β”ˆβž€Interactive Actions have been updated", false); + default -> eb.addField(key, "β•°β”ˆβž€" + key + " has/have been updated", false); + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/integration/ApplicationCommandPrivilegesUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/integration/ApplicationCommandPrivilegesUpdateEventHelper.java new file mode 100644 index 00000000..932b6d32 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/integration/ApplicationCommandPrivilegesUpdateEventHelper.java @@ -0,0 +1,48 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.integration; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ApplicationCommandPrivilegesUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Integration Create Event"); + eb.setDescription("ℹ️ An application command privilege was updated by: " + mentionableExecutor); + eb.setColor(Color.PINK); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.addField("", "To know more about what changes were made, visit the Integrations section", false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/integration/IntegrationCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/integration/IntegrationCreateEventHelper.java new file mode 100644 index 00000000..8d75bf76 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/integration/IntegrationCreateEventHelper.java @@ -0,0 +1,62 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.integration; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class IntegrationCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Integration Create Event"); + eb.setDescription("ℹ️ The following integration was created by: " + mentionableExecutor); + eb.setColor(Color.PINK); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "type" -> eb.addField("Integration Type", "β•°β”ˆβž€" + newValue, false); + case "name" -> eb.addField("Integration Name", "β•°β”ˆβž€" + newValue, false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/integration/IntegrationDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/integration/IntegrationDeleteEventHelper.java new file mode 100644 index 00000000..fcf63b18 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/integration/IntegrationDeleteEventHelper.java @@ -0,0 +1,61 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.integration; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class IntegrationDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Integration Delete Event"); + eb.setDescription("ℹ️ The following integration was deleted by: " + mentionableExecutor); + eb.setColor(Color.MAGENTA); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "type" -> eb.addField("Integration Type", "β•°β”ˆβž€" + oldValue, false); + case "name" -> eb.addField("Integration Name", "β•°β”ˆβž€" + oldValue, false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/invite/InviteCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/invite/InviteCreateEventHelper.java new file mode 100644 index 00000000..7329fecb --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/invite/InviteCreateEventHelper.java @@ -0,0 +1,89 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.invite; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.commons.utils.DurationUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class InviteCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Invite Create Event"); + + eb.setDescription("ℹ️ The following invite was created"); + eb.setColor(Color.CYAN); + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "code" -> eb.addField("Invite Code", "β•°β”ˆβž€" + newValue, false); + + case "inviter_id" -> { + User inviter = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableInviter = (inviter != null ? inviter.getAsMention() : ale.getUserId()); + eb.addField("Invite Created By", "β•°β”ˆβž€" + mentionableInviter, false); + } + + case "temporary" -> + eb.addField("Temporary Invite", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), false); + + case "max_uses" -> { + int maxUses = Integer.parseInt(String.valueOf(newValue)); + eb.addField("Max Uses", "β•°β”ˆβž€" + (maxUses == 0 ? "Unlimited" : String.valueOf(maxUses)), false); + } + + case "uses", "flags" -> { + // ignore + } + + case "max_age" -> eb.addField("Expires After", "β•°β”ˆβž€" + DurationUtils.formatSeconds(newValue), false); + + case "channel_id" -> { + GuildChannel channel = ale.getGuild().getGuildChannelById(String.valueOf(newValue)); + eb.addField("Invite Channel", "β•°β”ˆβž€" + (channel != null ? channel.getAsMention() : "`" + newValue + "`"), false); + } + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/invite/InviteDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/invite/InviteDeleteEventHelper.java new file mode 100644 index 00000000..664a59ef --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/invite/InviteDeleteEventHelper.java @@ -0,0 +1,83 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.invite; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.Channel; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class InviteDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Invite Delete Event"); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + eb.setDescription("ℹ️ The following invite has been deleted by: " + mentionableExecutor); + eb.setColor(Color.BLUE); + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "code" -> eb.addField("Deleted Invite Code", "β•°β”ˆβž€" + oldValue, false); + + case "inviter_id" -> { + User inviter = ale.getJDA().getUserById(String.valueOf(oldValue)); + eb.addField("Invite Originally Created By", "β•°β”ˆβž€" + (inviter != null ? inviter.getAsMention() : "`Unknown`"), false); + } + + case "temporary" -> + eb.addField("Temporary Invite", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), false); + + case "max_uses", "flags", "max_age" -> { + // ignore + } + + case "uses" -> eb.addField("Number of times the invite was used", "β•°β”ˆβž€" + oldValue, false); + + case "channel_id" -> { + Channel channel = ale.getGuild().getGuildChannelById(String.valueOf(oldValue)); + eb.addField("Invite Channel", "β•°β”ˆβž€" + (channel != null ? channel.getAsMention() : "`" + oldValue + "`"), false); + } + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberRoleUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberRoleUpdateEventHelper.java new file mode 100644 index 00000000..f710964e --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberRoleUpdateEventHelper.java @@ -0,0 +1,72 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.member; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.member.utils.MemberUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; +import java.util.Objects; + +@UtilityClass +@Slf4j +public class MemberRoleUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + User target = ale.getJDA().getUserById(ale.getTargetIdLong()); + String mentionableTarget = (target != null ? target.getAsMention() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Member Role Update"); + eb.setDescription("ℹ️ The following member had their role(s) updated by: " + mentionableExecutor); + eb.setThumbnail(Objects.requireNonNull(event.getGuild().getMemberById(ale.getTargetIdLong())).getEffectiveAvatarUrl()); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.addField("\uD83C\uDFF7️️ Target Member", "β•°β”ˆβž€" + mentionableTarget, false); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "$add" -> + eb.addField("βœ… Role(s) Added", "β•°β”ˆβž€" + MemberUtils.parseRoleListMap(event, newValue), false); + + case "$remove" -> + eb.addField("❌ Role(s) Removed", "β•°β”ˆβž€" + MemberUtils.parseRoleListMap(event, newValue), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberUpdateEventHelper.java new file mode 100644 index 00000000..5bae7e8e --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberUpdateEventHelper.java @@ -0,0 +1,112 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.member; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.commons.utils.DurationUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.Color; +import java.util.Objects; + +@UtilityClass +@Slf4j +public class MemberUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + User target = ale.getJDA().getUserById(ale.getTargetIdLong()); + String mentionableTarget = (target != null ? target.getAsMention() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Member Update Event"); + eb.setDescription("ℹ️ The following member was updated by: " + mentionableExecutor); + eb.setThumbnail(Objects.requireNonNull(event.getGuild().getMemberById(ale.getTargetId())).getEffectiveAvatarUrl()); + eb.setColor(Color.CYAN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.addField("Target", "β•°β”ˆβž€" + mentionableTarget, false); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "communication_disabled_until" -> { + if (newValue == null) { + eb.setColor(Color.GREEN); + eb.addField("Timeout Lifted", "β•°β”ˆβž€ Timeout has been removed", false); + } else { + eb.setColor(Color.YELLOW); + eb.addField("Timeout Received", "β•°β”ˆβž€ Member has received a timeout", false); + eb.addField("Timeout Ends On", "β•°β”ˆβž€" + DurationUtils.isoToLocalTimeCounter(newValue), false); + eb.addField("Timeout Reason", "β•°β”ˆβž€" + (ale.getReason() != null ? ale.getReason() : "No Reason Provided"), false); + } + } + + case "nick" -> + eb.addField("Nickname Update", "β•°β”ˆβž€" + resolveNickNameChanges(oldValue, newValue), false); + + case "mute" -> eb.addField("Is Muted in VC", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), false); + + case "deaf" -> eb.addField("Is Deafened in VC", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), false); + + case "bypasses_verification" -> + eb.addField("Bypass Verification", "β•°β”ˆβž€" + BooleanUtils.formatToEnabledOrDisabled(newValue), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } + + @NotNull + @SuppressWarnings("all") + private static String resolveNickNameChanges(@Nullable Object oldNickValue, @Nullable Object newNickValue) { + + if (oldNickValue == null && newNickValue != null) { // change from global name to a new nickname in the server + return "New Nickname Added: `" + newNickValue + "`"; + } + + if (oldNickValue != null && newNickValue == null) { // change to the global name from having a nickname + return "Reset to Global Name from: `" + oldNickValue + "`"; + } + + if (oldNickValue != null && newNickValue != null) { // changing from one nick to another + return "Changed nickname from: `" + oldNickValue + "` to: `" + newNickValue + "`"; + } + + // both shouldn't be null which indicates that names couldn't be fetched from the event + return "Changes could not be resolved!"; + } +} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/MemberVoiceKickEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberVoiceKickEventHelper.java similarity index 61% rename from src/main/java/org/papertrail/listeners/audit/helper/MemberVoiceKickEventHelper.java rename to src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberVoiceKickEventHelper.java index 401112c6..688b7cea 100644 --- a/src/main/java/org/papertrail/listeners/audit/helper/MemberVoiceKickEventHelper.java +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberVoiceKickEventHelper.java @@ -1,9 +1,10 @@ -package org.papertrail.listeners.audit.helper; +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.member; +import lombok.NonNull; import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; @@ -11,31 +12,37 @@ import java.awt.Color; @UtilityClass +@Slf4j public class MemberVoiceKickEventHelper { // the audit log does not expose much information regarding member vc move and kick events // therefore GuildVoiceEventListener has been created to know about channels the target has been moved or kicked from - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Member Voice Kick Event"); + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); User executor = ale.getJDA().getUserById(ale.getUserId()); String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A voice kick event was detected"); + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Member Voice Kick Event"); + eb.setDescription("ℹ️ A member was kicked from a voice channel by: " + mentionableExecutor); eb.setColor(Color.RED); eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); + eb.setFooter("Audit Log Entry ID: " + ale.getId()); eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); } } } diff --git a/src/main/java/org/papertrail/listeners/audit/helper/MemberVoiceMoveEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberVoiceMoveEventHelper.java similarity index 61% rename from src/main/java/org/papertrail/listeners/audit/helper/MemberVoiceMoveEventHelper.java rename to src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberVoiceMoveEventHelper.java index a79e02f2..bf8658b8 100644 --- a/src/main/java/org/papertrail/listeners/audit/helper/MemberVoiceMoveEventHelper.java +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/MemberVoiceMoveEventHelper.java @@ -1,9 +1,10 @@ -package org.papertrail.listeners.audit.helper; +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.member; +import lombok.NonNull; import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; @@ -11,31 +12,37 @@ import java.awt.Color; @UtilityClass +@Slf4j public class MemberVoiceMoveEventHelper { // the audit log does not expose much information regarding member vc move and kick events // therefore GuildVoiceEventListener has been created to know about channels the target has been moved or kicked from - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Member Voice Move Event"); + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); User executor = ale.getJDA().getUserById(ale.getUserId()); String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A voice move event was detected"); + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Member Voice Move Event"); + eb.setDescription("ℹ️ A member was moved to a different voice channel by: " + mentionableExecutor); eb.setColor(Color.YELLOW); eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); + eb.setFooter("Audit Log Entry ID: " + ale.getId()); eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); } } } diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/utils/MemberUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/utils/MemberUtils.java new file mode 100644 index 00000000..364984ed --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/member/utils/MemberUtils.java @@ -0,0 +1,51 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.member.utils; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.events.guild.GenericGuildEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +/* + * See {@link io.github.eggy03.papertrail.bot.commons.utils.StackWalkerUtils} + * and other utilities in the util package + * to know why logging isn't needed in some of the methods here + */ +@UtilityClass +@Slf4j +public class MemberUtils { + + @NonNull + public static final String FALLBACK_STRING = "N/A"; + + // Parses an array list of map of role objects supplied by JDA + // roles are exposed as arraylists of maps [{name=role, id=1}, {name=role2, id=2}] + @NotNull + public static String parseRoleListMap(@NonNull GenericGuildEvent event, @Nullable Object roleObject) { + + if (roleObject == null) { + log.debug("role object was null"); + return FALLBACK_STRING; + } + + if (roleObject instanceof List roleList) { + StringBuilder roleString = new StringBuilder(); + roleList.forEach(o -> { + if (o instanceof Map roleMap && roleMap.containsKey("id")) { + String roleId = (String) roleMap.get("id"); + Role role = event.getGuild().getRoleById(roleId); + roleString.append(role != null ? role.getAsMention() : roleMap.get("name")).append(" "); + } + }); + return roleString.toString().trim(); + } + + log.debug("role object was not an instance of a list-map, value: {}", roleObject); + return FALLBACK_STRING; + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/message/MessagePinEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/message/MessagePinEventHelper.java new file mode 100644 index 00000000..b3a30499 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/message/MessagePinEventHelper.java @@ -0,0 +1,50 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.message; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class MessagePinEventHelper { + + // this audit log event does not expose anything other than the target of the event who sent the message + // nothing about the person who pinned it or the message itself + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Message Pin Event"); + + User target = ale.getJDA().getUserById(ale.getTargetId()); + String mentionableTarget = (target != null ? target.getAsMention() : ale.getTargetId()); + + eb.setDescription("**A message from **: " + mentionableTarget + " was pinned"); + eb.setColor(Color.PINK); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } + +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/message/MessageUnpinEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/message/MessageUnpinEventHelper.java new file mode 100644 index 00000000..720c3621 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/message/MessageUnpinEventHelper.java @@ -0,0 +1,49 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.message; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class MessageUnpinEventHelper { + + // this audit log event does not expose anything other than the target of the event who sent the message + // nothing about the person who un-pinned it or the message itself + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Message Unpin Event"); + + User target = ale.getJDA().getUserById(ale.getTargetId()); + String mentionableTarget = (target != null ? target.getAsMention() : ale.getTargetId()); + + eb.setDescription("**A message from **: " + mentionableTarget + " un-pinned"); + eb.setColor(Color.MAGENTA); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/modactions/BanEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/modactions/BanEventHelper.java new file mode 100644 index 00000000..9d3674a9 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/modactions/BanEventHelper.java @@ -0,0 +1,56 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.modactions; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class BanEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User moderator = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableModerator = (moderator != null ? moderator.getAsMention() : ale.getUserId()); + String reasonForBan = ale.getReason() == null ? "No Reason Provided" : ale.getReason(); + + // A REST Action is required here because banned members are not cached + event.getJDA().retrieveUserById(ale.getTargetId()).queue(bannedUser -> { + + String mentionableBannedUser = bannedUser != null ? bannedUser.getAsMention() : ale.getTargetId(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Ban Event"); + eb.setDescription("ℹ️ A moderator: " + mentionableModerator + " has banned a member"); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.addField("Banned Member", "β•°β”ˆβž€" + mentionableBannedUser, false); + eb.addField("Ban Reason", "β•°β”ˆβž€" + reasonForBan, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + }); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/modactions/KickEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/modactions/KickEventHelper.java new file mode 100644 index 00000000..9d8d317a --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/modactions/KickEventHelper.java @@ -0,0 +1,56 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.modactions; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class KickEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User moderator = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableModerator = (moderator != null ? moderator.getAsMention() : ale.getUserId()); + String reasonForKick = ale.getReason() == null ? "No Reason Provided" : ale.getReason(); + + // A REST Action is required here because kicked members are not cached + event.getJDA().retrieveUserById(ale.getTargetId()).queue(kickedUser -> { + + String mentionableKickedUser = kickedUser != null ? kickedUser.getAsMention() : ale.getTargetId(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Kick Event"); + eb.setDescription("ℹ️ The following member was kicked by: " + mentionableModerator); + eb.setColor(Color.ORANGE); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.addField("Kicked Member/Application", "β•°β”ˆβž€" + mentionableKickedUser, false); + eb.addField("Reason", "β•°β”ˆβž€" + reasonForKick, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + }); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/modactions/UnbanEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/modactions/UnbanEventHelper.java new file mode 100644 index 00000000..6180aaa9 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/modactions/UnbanEventHelper.java @@ -0,0 +1,53 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.modactions; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class UnbanEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User moderator = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableModerator = (moderator != null ? moderator.getAsMention() : ale.getUserId()); + + event.getJDA().retrieveUserById(ale.getTargetId()).queue(unbannedUser -> { + + String mentionableUnbannedUser = unbannedUser != null ? unbannedUser.getAsMention() : ale.getTargetId(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Member Unban Event"); + eb.setDescription("ℹ️ The following user was un-banned by: " + mentionableModerator); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.addField("Un-banned User", "β•°β”ˆβž€" + mentionableUnbannedUser, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + }); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingPromptCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingPromptCreateEventHelper.java new file mode 100644 index 00000000..c5455ba5 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingPromptCreateEventHelper.java @@ -0,0 +1,78 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.onboarding; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class OnboardingPromptCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Onboarding Prompt Create Event"); + + User executor = ale.getJDA().getUserById(ale.getUserId()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getTargetId()); + + eb.setDescription("πŸ‘€ " + mentionableExecutor + "has created an Onboarding Prompt"); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "single_select" -> + eb.addField("Single Selection Mode", BooleanUtils.formatToYesOrNo(newValue), false); + + case "required" -> eb.addField("Required", BooleanUtils.formatToYesOrNo(newValue), false); + + case "type", "id" -> { + // skip + } + + case "title" -> eb.addField("Question Title", String.valueOf(newValue), false); + + case "options" -> eb.addField("Question Options", "Review the options in Onboarding Settings", false); + + case "in_onboarding" -> + eb.addField("Is a Pre-Join Question", BooleanUtils.formatToYesOrNo(newValue), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingPromptDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingPromptDeleteEventHelper.java new file mode 100644 index 00000000..1b34159b --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingPromptDeleteEventHelper.java @@ -0,0 +1,76 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.onboarding; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class OnboardingPromptDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Onboarding Prompt Delete Event"); + + User executor = ale.getJDA().getUserById(ale.getUserId()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getTargetId()); + + eb.setDescription("πŸ‘€ " + mentionableExecutor + "has made deleted an Onboarding Prompt"); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "single_select" -> + eb.addField("Single Selection Mode", BooleanUtils.formatToYesOrNo(oldValue), false); + + case "required" -> eb.addField("Was Required", BooleanUtils.formatToYesOrNo(oldValue), false); + + case "type", "id", "options" -> { + // skip + } + case "title" -> eb.addField("Question Title", String.valueOf(oldValue), false); + + case "in_onboarding" -> + eb.addField("Was a Pre-Join Question", BooleanUtils.formatToYesOrNo(oldValue), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } + +} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/OnboardingPromptUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingPromptUpdateEventHelper.java similarity index 50% rename from src/main/java/org/papertrail/listeners/audit/helper/OnboardingPromptUpdateEventHelper.java rename to src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingPromptUpdateEventHelper.java index bf21d7ec..4a6d1a44 100644 --- a/src/main/java/org/papertrail/listeners/audit/helper/OnboardingPromptUpdateEventHelper.java +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingPromptUpdateEventHelper.java @@ -1,20 +1,22 @@ -package org.papertrail.listeners.audit.helper; +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.onboarding; +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import lombok.NonNull; import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; import java.awt.Color; @UtilityClass +@Slf4j public class OnboardingPromptUpdateEventHelper { - public static void format(GuildAuditLogEntryCreateEvent event, String channelIdToSendTo) { + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { AuditLogEntry ale = event.getEntry(); @@ -35,49 +37,52 @@ public static void format(GuildAuditLogEntryCreateEvent event, String channelIdT Object oldValue = changeValue.getOldValue(); Object newValue = changeValue.getNewValue(); - switch (changeKey){ - case "single_select": - eb.addField("Old Single Selection Mode", BooleanFormatter.formatToYesOrNo(oldValue), false); - eb.addField("New Single Selection Mode", BooleanFormatter.formatToYesOrNo(newValue), false); - break; + switch (changeKey) { + case "single_select" -> { + eb.addField("Old Single Selection Mode", BooleanUtils.formatToYesOrNo(oldValue), false); + eb.addField("New Single Selection Mode", BooleanUtils.formatToYesOrNo(newValue), false); + } - case "required": - eb.addField("Was Required", BooleanFormatter.formatToYesOrNo(oldValue), false); - eb.addField("Is Required", BooleanFormatter.formatToYesOrNo(newValue), false); - break; + case "required" -> { + eb.addField("Was Required", BooleanUtils.formatToYesOrNo(oldValue), false); + eb.addField("Is Required", BooleanUtils.formatToYesOrNo(newValue), false); + } - case "type", "id": - break; + case "type", "id" -> { + // skip + } - case "title": + case "title" -> { eb.addField("Old Question Title", String.valueOf(oldValue), false); eb.addField("New Question Title", String.valueOf(newValue), false); - break; + } - case "options": - eb.addField("Question Options", "Review the changed options in Onboarding Settings", false); - break; + case "options" -> + eb.addField("Question Options", "Review the changed options in Onboarding Settings", false); - case "in_onboarding": - eb.addField("Was a Pre-Join Question", BooleanFormatter.formatToYesOrNo(oldValue), false); - eb.addField("Is a Pre-Join Question", BooleanFormatter.formatToYesOrNo(newValue), false); - break; + case "in_onboarding" -> { + eb.addField("Was a Pre-Join Question", BooleanUtils.formatToYesOrNo(oldValue), false); + eb.addField("Is a Pre-Join Question", BooleanUtils.formatToYesOrNo(newValue), false); + } - default: - eb.addField(changeKey, "OLD_VALUE: "+oldValue, false); - eb.addField(changeKey, "NEW_VALUE: "+newValue, false); + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } } - }); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); + eb.setFooter("Audit Log Entry ID: " + ale.getId()); eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); } } } diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingUpdateEventHelper.java new file mode 100644 index 00000000..fc0afcbf --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/OnboardingUpdateEventHelper.java @@ -0,0 +1,88 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.onboarding; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.onboarding.utils.OnboardingUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class OnboardingUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Onboarding Update Event"); + + User executor = ale.getJDA().getUserById(ale.getUserId()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getTargetId()); + + Guild guild = event.getGuild(); + + eb.setDescription("πŸ‘€ " + mentionableExecutor + "has made changes to Onboarding"); + eb.setColor(Color.MAGENTA); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + eb.addBlankField(true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "enabled" -> { + eb.addField("Old Onboarding Status", BooleanUtils.formatToEnabledOrDisabled(oldValue), true); + eb.addField("New Onboarding Status", BooleanUtils.formatToEnabledOrDisabled(newValue), true); + eb.addBlankField(true); + } + + case "mode" -> { + eb.addField("Old Onboarding Mode", OnboardingUtils.formatMode(oldValue), true); + eb.addField("New Onboarding Mode", OnboardingUtils.formatMode(newValue), true); + eb.addBlankField(true); + } + + case "default_channel_ids" -> { + eb.addField("Old Default Channels", OnboardingUtils.resolveChannelsFromList(guild, oldValue), true); + eb.addField("New Default Channels", OnboardingUtils.resolveChannelsFromList(guild, newValue), true); + eb.addBlankField(true); + } + + // triggered also when prompts are deleted/created besides the default of update + case "prompts" -> + eb.addField("Prompt Updates", "Overall Pre-join/Post-join questions may have been updated.\n Review changes manually.", false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/utils/OnboardingUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/utils/OnboardingUtils.java new file mode 100644 index 00000000..cbc99067 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/onboarding/utils/OnboardingUtils.java @@ -0,0 +1,55 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.onboarding.utils; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +@UtilityClass +@Slf4j +public class OnboardingUtils { + + @NonNull + public static final String FALLBACK_STRING = "N/A"; + + @NotNull + public static String formatMode(@Nullable Object value) { + if (value == null) { + log.debug("format mode value was null"); + return FALLBACK_STRING; + } + + return switch (String.valueOf(value)) { + case "1" -> "Advanced Mode"; + case "0" -> "Regular Mode"; + default -> { + log.debug("unrecognized value: {}", value); + yield "Unrecognized Mode: " + value; + } + }; + } + + @NotNull + public static String resolveChannelsFromList(@NonNull Guild guild, @Nullable Object value) { + if (value == null) { + log.debug("channel list was null"); + return FALLBACK_STRING; + } + + StringBuilder sb = new StringBuilder(); + if (value instanceof List channelIdList) { + channelIdList.forEach(channelId -> { + GuildChannel channel = guild.getGuildChannelById((String) channelId); + sb.append(channel != null ? channel.getAsMention() : channelId).append(" "); + }); + } + + log.debug("channel list was not an instance of a list, value: {}", value); + return sb.toString().trim(); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/RoleCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/RoleCreateEventHelper.java new file mode 100644 index 00000000..9a82664a --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/RoleCreateEventHelper.java @@ -0,0 +1,74 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.role; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class RoleCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserId()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + Role targetRole = ale.getJDA().getRoleById(ale.getTargetId()); + String mentionableTargetRole = (targetRole != null ? targetRole.getAsMention() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Role Create Event"); + eb.setDescription("The following role was created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.addField("Target Role", "β•°β”ˆβž€" + mentionableTargetRole, false); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "name" -> eb.addField("Role Name", "β•°β”ˆβž€" + newValue, false); + + case "colors", "hoist", "color", "permissions", "mentionable" -> { + /* discord for some reason shows the following to be default/null even + * when you set them during the creation of the role itself + * and delegates them to ROLE_UPDATE event + */ + } + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/RoleDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/RoleDeleteEventHelper.java new file mode 100644 index 00000000..0eae95e2 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/RoleDeleteEventHelper.java @@ -0,0 +1,78 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.role; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.role.utils.RoleUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class RoleDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserId()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Role Delete Event"); + eb.setDescription("ℹ️ The following role was deleted by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "name" -> eb.addField("Role Name", "β•°β”ˆβž€" + oldValue, false); + + case "hoist" -> + eb.addField("Display Separately", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), false); + + case "color" -> eb.addField("Color", "β•°β”ˆβž€" + RoleUtils.formatToHex(oldValue), false); + + case "permissions" -> + eb.addField("Role Permissions", RoleUtils.resolveRolePermissions(oldValue, "βœ…"), false); + + case "mentionable" -> eb.addField("Mentionable", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), false); + + case "colors" -> eb.addField("Gradient Color System", RoleUtils.formatGradientToHex(oldValue), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + + }); + eb.addField("πŸ†” Deleted Role ID", "β•°β”ˆβž€" + ale.getTargetId(), false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/RoleUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/RoleUpdateEventHelper.java new file mode 100644 index 00000000..750e2068 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/RoleUpdateEventHelper.java @@ -0,0 +1,105 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.role; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.role.utils.RoleUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class RoleUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserId()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + Role targetRole = ale.getJDA().getRoleById(ale.getTargetId()); + String mentionableTargetRole = (targetRole != null ? targetRole.getAsMention() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Role Update Event"); + eb.setDescription("ℹ️ The following role was updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + eb.addField("Target Role", "β•°β”ˆβž€" + mentionableTargetRole, false); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "name" -> { + eb.addField("Old Role Name", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Role Name", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + + case "hoist" -> { + eb.addField("Old Display Separately", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), true); + eb.addField("New Display Separately", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), true); + eb.addBlankField(true); + } + + case "color" -> { + eb.addField("Old Color", "β•°β”ˆβž€" + RoleUtils.formatToHex(oldValue), true); + eb.addField("New Color", "β•°β”ˆβž€" + RoleUtils.formatToHex(newValue), true); + eb.addBlankField(true); + } + + case "permissions" -> { + eb.addField("Old Role Permissions", RoleUtils.resolveRolePermissions(oldValue, "βœ…"), true); + eb.addField("New Role Permissions", RoleUtils.resolveRolePermissions(newValue, "βœ…"), true); + eb.addBlankField(true); + } + + case "mentionable" -> { + eb.addField("Old Mentionable", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), true); + eb.addField("New Mentionable", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), true); + eb.addBlankField(true); + } + + case "colors" -> { + eb.addField("Old Gradient Color System", RoleUtils.formatGradientToHex(oldValue), true); + eb.addField("New Gradient Color System", RoleUtils.formatGradientToHex(newValue), true); + eb.addBlankField(true); + } + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/utils/RoleUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/utils/RoleUtils.java new file mode 100644 index 00000000..d1c322e1 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/role/utils/RoleUtils.java @@ -0,0 +1,93 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.role.utils; + +import io.github.eggy03.papertrail.bot.commons.utils.NumberParseUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.Permission; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.EnumSet; +import java.util.IllegalFormatException; +import java.util.Map; + +/* + * See {@link io.github.eggy03.papertrail.bot.commons.utils.StackWalkerUtils} + * and other utilities in the util package + * to know why logging isn't needed in some of the methods here + */ +@UtilityClass +@Slf4j +public class RoleUtils { + + @NonNull + private static final String FALLBACK_STRING = "N/A"; + + @NotNull + public static String resolveRolePermissions(@Nullable Object permissionsValue, @NonNull String emoji) { + Long permissionLong = NumberParseUtils.parseLong(permissionsValue); + if (permissionLong == null) + return FALLBACK_STRING; + + if (permissionLong == 0) + return "No Permissions set"; + + StringBuilder permissions = new StringBuilder(); + EnumSet permissionEnum = Permission.getPermissions(permissionLong); + + permissionEnum.forEach(permission -> permissions + .append(emoji) + .append(" ") + .append(permission.getName()) + .append(System.lineSeparator()) + ); + + return permissions.toString().trim(); + } + + @NotNull + public static String formatToHex(@Nullable Object colorValueInteger) { + + if (colorValueInteger == null) { + log.debug("colorValueInteger is null"); + return FALLBACK_STRING; + } + + String colorValueString = String.valueOf(colorValueInteger); + + try { + int color = Integer.parseInt(colorValueString); + return String.format("#%06X", color); + } catch (NumberFormatException e) { + log.debug("failed to parse color integer from value={})", colorValueInteger); + return colorValueString; + } catch (IllegalFormatException e) { + log.debug("failed to format color integer to hex, value={})", colorValueInteger); + return colorValueString; + } + } + + // gradient is returned as a hash map in the following structure + // {"primary_color" = 123456789, "secondary_color" = 123456789, "tertiary_color" = 123456789} + @NotNull + public static String formatGradientToHex(@Nullable Object gradientMap) { + + if (gradientMap == null) { + log.debug("color gradient map is null"); + return FALLBACK_STRING; + } + + if (gradientMap instanceof Map colorMap) { + + String primaryColor = "Primary Color: " + formatToHex(colorMap.get("primary_color")); + String secondaryColor = "Secondary Color: " + formatToHex(colorMap.get("secondary_color")); + String tertiaryColor = "Tertiary Color: " + formatToHex(colorMap.get("tertiary_color")); + + return primaryColor + System.lineSeparator() + secondaryColor + System.lineSeparator() + tertiaryColor; + } + + log.debug("gradient value is not a Map, value={}", gradientMap); + return gradientMap.toString(); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/ScheduledEventCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/ScheduledEventCreateEventHelper.java new file mode 100644 index 00000000..af0248c6 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/ScheduledEventCreateEventHelper.java @@ -0,0 +1,69 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.scheduledevent; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.scheduledevent.utils.ScheduledEventUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ScheduledEventCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Scheduled Event Create Event"); + eb.setDescription("ℹ️ A scheduled event was created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "entity_type" -> + eb.addField("Event Type", "β•°β”ˆβž€" + ScheduledEventUtils.resolveEventType(newValue), false); + case "name" -> eb.addField("Event Name", "β•°β”ˆβž€" + newValue, false); + case "description" -> eb.addField("Event Description", "β•°β”ˆβž€" + newValue, false); + case "status" -> + eb.addField("Event Status", "β•°β”ˆβž€" + ScheduledEventUtils.resolveStatusType(newValue), false); + case "location" -> eb.addField("Event Location", "β•°β”ˆβž€" + newValue, false); + case "privacy_level", "image_hash", "channel_id", "recurrence_rule" -> { + // skip + } + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/ScheduledEventDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/ScheduledEventDeleteEventHelper.java new file mode 100644 index 00000000..3ed8c03d --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/ScheduledEventDeleteEventHelper.java @@ -0,0 +1,69 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.scheduledevent; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.scheduledevent.utils.ScheduledEventUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ScheduledEventDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Scheduled Event Delete Event"); + eb.setDescription("ℹ️ A scheduled event has been deleted by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "entity_type" -> + eb.addField("Event Type", "β•°β”ˆβž€" + ScheduledEventUtils.resolveEventType(oldValue), false); + case "name" -> eb.addField("Event Name", "β•°β”ˆβž€" + oldValue, false); + case "description" -> eb.addField("Event Description", "β•°β”ˆβž€" + oldValue, false); + case "status" -> + eb.addField("Event Status", "β•°β”ˆβž€" + ScheduledEventUtils.resolveStatusType(oldValue), false); + case "location" -> eb.addField("Event Location", "β•°β”ˆβž€" + oldValue, false); + case "privacy_level", "image_hash", "channel_id", "recurrence_rule" -> { + // skip + } + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/ScheduledEventUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/ScheduledEventUpdateEventHelper.java new file mode 100644 index 00000000..3c4a2eba --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/ScheduledEventUpdateEventHelper.java @@ -0,0 +1,90 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.scheduledevent; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.scheduledevent.utils.ScheduledEventUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ScheduledEventUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Scheduled Event Update Event"); + eb.setDescription("ℹ️ The following scheduled event was updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + eb.addBlankField(true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "entity_type" -> { + eb.addField("Old Event Type", "β•°β”ˆβž€" + ScheduledEventUtils.resolveEventType(oldValue), true); + eb.addField("New Event Type", "β•°β”ˆβž€" + ScheduledEventUtils.resolveEventType(newValue), true); + eb.addBlankField(true); + } + case "name" -> { + eb.addField("Old Event Name", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Event Name", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + case "description" -> { + eb.addField("Old Event Description", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Event Description", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + case "status" -> { + eb.addField("Old Event Status", "β•°β”ˆβž€" + ScheduledEventUtils.resolveStatusType(oldValue), true); + eb.addField("New Event Status", "β•°β”ˆβž€" + ScheduledEventUtils.resolveStatusType(newValue), true); + eb.addBlankField(true); + } + case "location" -> { + eb.addField("Event Location", "β•°β”ˆβž€" + oldValue, true); + eb.addField("Event Location", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + case "privacy_level" -> eb.addField("Privacy", "β•°β”ˆβž€Event privacy has been updated", false); + case "image_hash" -> eb.addField("Image", "β•°β”ˆβž€Event Image has been updated", false); + case "channel_id" -> eb.addField("Channel", "β•°β”ˆβž€Event Channel has been updated", false); + case "recurrence_rule" -> eb.addField("Recurrence Rule", "β•°β”ˆβž€Recurrence Rule has been updated", false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/utils/ScheduledEventUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/utils/ScheduledEventUtils.java new file mode 100644 index 00000000..57d5a7a8 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/scheduledevent/utils/ScheduledEventUtils.java @@ -0,0 +1,125 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.scheduledevent.utils; + +import io.github.eggy03.papertrail.bot.commons.utils.NumberParseUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.ScheduledEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +/* + * See {@link io.github.eggy03.papertrail.bot.commons.utils.StackWalkerUtils} + * and other utilities in the util package + * to know why logging isn't needed in some of the methods here + */ +@UtilityClass +@Slf4j +public class ScheduledEventUtils { + + @NonNull + public static final String FALLBACK_STRING = "N/A"; + + @NotNull + public static String resolveEventType(@Nullable Object eventTypeInteger) { + + Integer eventType = NumberParseUtils.parseInt(eventTypeInteger); + if (eventType == null) + return FALLBACK_STRING; + + return ScheduledEvent.Type.fromKey(eventType).name(); + + } + + @NotNull + public static String resolveStatusType(@Nullable Object eventTypeInteger) { + Integer eventType = NumberParseUtils.parseInt(eventTypeInteger); + if (eventType == null) + return FALLBACK_STRING; + + return ScheduledEvent.Status.fromKey(eventType).name(); + } + + + /** + * @deprecated + */ + @NotNull + @Deprecated(forRemoval = true) + public static String resolveRecurrenceRules(@Nullable Object recurrenceRuleStructure) { + + if (recurrenceRuleStructure == null) { + log.debug("recurrence rule object was null"); + return FALLBACK_STRING; + } + + StringBuilder stringBuilder = new StringBuilder(); + if (recurrenceRuleStructure instanceof Map recurrenceRuleMap) { + + stringBuilder.append("**_Start Time of Interval_**") + .append(System.lineSeparator()) + .append("β•°β”ˆβž€") + .append(recurrenceRuleMap.get("start")) + .append(System.lineSeparator()); + + stringBuilder.append("**_End Time of Interval_**") + .append(System.lineSeparator()) + .append("β•°β”ˆβž€") + .append(recurrenceRuleMap.get("end")) + .append(System.lineSeparator()); + + stringBuilder.append("**_Frequency of Interval_**") + .append(System.lineSeparator()) + .append("β•°β”ˆβž€") + .append(recurrenceRuleMap.get("frequency")) + .append(System.lineSeparator()); + + stringBuilder.append("**_Spacing between events_**") + .append(System.lineSeparator()) + .append("β•°β”ˆβž€") + .append(recurrenceRuleMap.get("interval")) + .append(System.lineSeparator()); + + stringBuilder.append("**_Weekday Recurrence_**") + .append(System.lineSeparator()) + .append("β•°β”ˆβž€") + .append(recurrenceRuleMap.get("by_weekday")) + .append(System.lineSeparator()); + + stringBuilder.append("**_Specific days within a weekday to recur on_**") + .append(System.lineSeparator()) + .append("β•°β”ˆβž€") + .append(recurrenceRuleMap.get("by_n_weekday")) + .append(System.lineSeparator()); + + stringBuilder.append("**_Monthly Recurrence_**") + .append(System.lineSeparator()) + .append("β•°β”ˆβž€") + .append(recurrenceRuleMap.get("by_month")) + .append(System.lineSeparator()); + + stringBuilder.append("**_Specific days within a month to recur on_**") + .append(System.lineSeparator()) + .append("β•°β”ˆβž€") + .append(recurrenceRuleMap.get("by_month_day")) + .append(System.lineSeparator()); + + stringBuilder.append("**_Set of days within a year to recur on_**") + .append(System.lineSeparator()) + .append("β•°β”ˆβž€") + .append(recurrenceRuleMap.get("by_year_day")) + .append(System.lineSeparator()); + + stringBuilder.append("**_Event to be repeated_**") + .append(System.lineSeparator()) + .append("β•°β”ˆβž€") + .append(recurrenceRuleMap.get("count")); + + } else + log.debug("Recurrence rule object was not an instance of a map, value: {}", recurrenceRuleStructure); + + return stringBuilder.toString().trim(); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/SoundboardSoundCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/SoundboardSoundCreateEventHelper.java new file mode 100644 index 00000000..4a35af93 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/SoundboardSoundCreateEventHelper.java @@ -0,0 +1,73 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.soundboard; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.soundboard.utils.SoundboardUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class SoundboardSoundCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Soundboard Sound Create Event"); + eb.setDescription("ℹ️ A sound item was added to the soundboard by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "user_id", "sound_id", "id", "guild_id", "available" -> { + // skip + } + case "volume" -> + eb.addField("Volume", "β•°β”ˆβž€" + SoundboardUtils.resolveVolumePercentage(newValue), false); + + case "emoji_name" -> eb.addField("Related Emoji", "β•°β”ˆβž€" + newValue, false); + + case "emoji_id" -> eb.addField("Related Emoji ID", "β•°β”ˆβž€" + newValue, false); + + case "name" -> eb.addField("Sound Item Name", "β•°β”ˆβž€" + newValue, false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/SoundboardSoundDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/SoundboardSoundDeleteEventHelper.java new file mode 100644 index 00000000..3517796b --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/SoundboardSoundDeleteEventHelper.java @@ -0,0 +1,73 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.soundboard; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.soundboard.utils.SoundboardUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class SoundboardSoundDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Soundboard Sound Create Event"); + eb.setDescription("ℹ️ A sound item was deleted from the soundboard by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "user_id", "sound_id", "id", "guild_id", "available" -> { + // skip + } + case "volume" -> + eb.addField("Volume", "β•°β”ˆβž€" + SoundboardUtils.resolveVolumePercentage(oldValue), false); + + case "emoji_name" -> eb.addField("Related Emoji", "β•°β”ˆβž€" + oldValue, false); + + case "emoji_id" -> eb.addField("Related Emoji ID", "β•°β”ˆβž€" + oldValue, false); + + case "name" -> eb.addField("Sound Item Name", "β•°β”ˆβž€" + oldValue, false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/SoundboardSoundUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/SoundboardSoundUpdateEventHelper.java new file mode 100644 index 00000000..c75ba973 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/SoundboardSoundUpdateEventHelper.java @@ -0,0 +1,83 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.soundboard; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.soundboard.utils.SoundboardUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class SoundboardSoundUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Soundboard Sound Update Event"); + eb.setDescription("ℹ️ A sound item in the soundboard was updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + eb.addBlankField(true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "user_id", "sound_id", "id", "guild_id", "available" -> { + // skip + } + case "volume" -> { + eb.addField("Old Volume", "β•°β”ˆβž€" + SoundboardUtils.resolveVolumePercentage(oldValue), true); + eb.addField("New Volume", "β•°β”ˆβž€" + SoundboardUtils.resolveVolumePercentage(newValue), true); + eb.addBlankField(true); + } + case "emoji_name" -> { + eb.addField("Old Related Emoji", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Related Emoji", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + case "emoji_id" -> { + eb.addField("Old Related Emoji ID", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Related Emoji ID", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + case "name" -> { + eb.addField("Old Sound Item Name", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Sound Item Name", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/utils/SoundboardUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/utils/SoundboardUtils.java new file mode 100644 index 00000000..8f195d37 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/soundboard/utils/SoundboardUtils.java @@ -0,0 +1,26 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.soundboard.utils; + +import io.github.eggy03.papertrail.bot.commons.utils.NumberParseUtils; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.math.RoundingMode; + +/* + * See {@link io.github.eggy03.papertrail.bot.commons.utils.StackWalkerUtils} + * and other utilities in the util package + * to know why logging isn't needed in some of the methods here + */ +@UtilityClass +public class SoundboardUtils { + + @NotNull + public static String resolveVolumePercentage(@Nullable Object decimalVolume) { + Double volume = NumberParseUtils.parseDouble(decimalVolume, 4, RoundingMode.HALF_UP); + if (volume == null) + return "N/A"; + + return (volume * 100) + "%"; + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/StageInstanceCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/StageInstanceCreateEventHelper.java new file mode 100644 index 00000000..055875d0 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/StageInstanceCreateEventHelper.java @@ -0,0 +1,64 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.stage; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.stage.utils.StageUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class StageInstanceCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Stage Instance Create Event"); + eb.setDescription("ℹ️ A stage instance was created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "topic" -> eb.addField("Stage Topic", "β•°β”ˆβž€" + newValue, false); + + case "privacy_level" -> + eb.addField("Stage Privacy", "β•°β”ˆβž€" + StageUtils.resolveStagePrivacyLevel(newValue), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/StageInstanceDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/StageInstanceDeleteEventHelper.java new file mode 100644 index 00000000..d097dc70 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/StageInstanceDeleteEventHelper.java @@ -0,0 +1,63 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.stage; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.stage.utils.StageUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class StageInstanceDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Stage Instance Delete Event"); + eb.setDescription("ℹ️ A stage instance was deleted by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "topic" -> eb.addField("Stage Topic", "β•°β”ˆβž€" + oldValue, false); + + case "privacy_level" -> + eb.addField("Stage Privacy", "β•°β”ˆβž€" + StageUtils.resolveStagePrivacyLevel(oldValue), false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/StageInstanceUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/StageInstanceUpdateEventHelper.java new file mode 100644 index 00000000..ba4afec1 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/StageInstanceUpdateEventHelper.java @@ -0,0 +1,71 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.stage; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.stage.utils.StageUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class StageInstanceUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Stage Instance Update Event"); + eb.setDescription("ℹ️ A stage instance was updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + eb.addBlankField(true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "topic" -> { + eb.addField("Old Stage Topic", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Stage Topic", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + case "privacy_level" -> { + eb.addField("Old Stage Privacy", "β•°β”ˆβž€" + StageUtils.resolveStagePrivacyLevel(oldValue), true); + eb.addField("New Stage Privacy", "β•°β”ˆβž€" + StageUtils.resolveStagePrivacyLevel(newValue), true); + eb.addBlankField(true); + } + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/utils/StageUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/utils/StageUtils.java new file mode 100644 index 00000000..994acbc5 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/stage/utils/StageUtils.java @@ -0,0 +1,28 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.stage.utils; + +import io.github.eggy03.papertrail.bot.commons.utils.NumberParseUtils; +import lombok.experimental.UtilityClass; +import net.dv8tion.jda.api.entities.StageInstance; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/* + * See {@link io.github.eggy03.papertrail.bot.commons.utils.StackWalkerUtils} + * and other utilities in the util package + * to know why logging isn't needed in some of the methods here + */ +@UtilityClass +public class StageUtils { + + @NotNull + public static String resolveStagePrivacyLevel(@Nullable Object stagePrivacyLevelInteger) { + Integer privacyLevel = NumberParseUtils.parseInt(stagePrivacyLevelInteger); + + if (privacyLevel == null) return "N/A"; + + //JDA removed this, and it technically shouldn't happen either since all stages are GUILD_ONLY now + if (privacyLevel == 1) return "PUBLIC (Deprecated)"; + + return StageInstance.PrivacyLevel.fromKey(privacyLevel).name(); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/StickerCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/StickerCreateEventHelper.java new file mode 100644 index 00000000..1f1e7013 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/StickerCreateEventHelper.java @@ -0,0 +1,71 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.sticker; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.sticker.utils.StickerUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class StickerCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Sticker Create Event"); + eb.setDescription("ℹ️ The following sticker was created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "format_type", "type", "asset", "available", "guild_id" -> { + // skip + } + case "id" -> { + eb.addField("Sticker ID", "β•°β”ˆβž€" + newValue, false); + eb.addField("Sticker Link", "β•°β”ˆβž€" + StickerUtils.resolveStickerUrl(event, newValue), false); + } + case "tags" -> + eb.addField("Related Emoji", "β•°β”ˆβž€" + StickerUtils.resolveRelatedEmoji(event, newValue), false); + case "description" -> eb.addField("Description", "β•°β”ˆβž€" + newValue, false); + case "name" -> eb.addField("Sticker Name", "β•°β”ˆβž€" + newValue, false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/StickerDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/StickerDeleteEventHelper.java new file mode 100644 index 00000000..573b0533 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/StickerDeleteEventHelper.java @@ -0,0 +1,71 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.sticker; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.sticker.utils.StickerUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class StickerDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Sticker Delete Event"); + eb.setDescription("ℹ️ The following sticker was deleted by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "format_type", "type", "asset", "available", "guild_id" -> { + // skip + } + case "id" -> { + eb.addField("Sticker ID", "β•°β”ˆβž€" + oldValue, false); + eb.addField("Sticker Link", "β•°β”ˆβž€" + StickerUtils.resolveStickerUrl(event, oldValue), false); + } + case "tags" -> + eb.addField("Related Emoji", "β•°β”ˆβž€" + StickerUtils.resolveRelatedEmoji(event, oldValue), false); + case "description" -> eb.addField("Description", "β•°β”ˆβž€" + oldValue, false); + case "name" -> eb.addField("Sticker Name", "β•°β”ˆβž€" + oldValue, false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/StickerUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/StickerUpdateEventHelper.java new file mode 100644 index 00000000..05bc5ffa --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/StickerUpdateEventHelper.java @@ -0,0 +1,82 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.sticker; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.sticker.utils.StickerUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.sticker.GuildSticker; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class StickerUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + GuildSticker sticker = event.getGuild().getStickerById(ale.getTargetId()); + String mentionableSticker = (sticker != null ? sticker.getName() : ale.getTargetId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Sticker Update Event"); + eb.setDescription("ℹ️ The following sticker: " + mentionableSticker + " was updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + eb.addBlankField(true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + case "format_type", "type", "asset", "available", "guild_id", "id" -> { + // skip + } + case "tags" -> { + eb.addField("Old Related Emoji", "β•°β”ˆβž€" + StickerUtils.resolveRelatedEmoji(event, oldValue), true); + eb.addField("New Related Emoji", "β•°β”ˆβž€" + StickerUtils.resolveRelatedEmoji(event, newValue), true); + eb.addBlankField(true); + } + case "description" -> { + eb.addField("Old Description", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Description", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + case "name" -> { + eb.addField("Old Sticker Name", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Sticker Name", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/utils/StickerUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/utils/StickerUtils.java new file mode 100644 index 00000000..ad629030 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/sticker/utils/StickerUtils.java @@ -0,0 +1,68 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.sticker.utils; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.emoji.Emoji; +import net.dv8tion.jda.api.entities.sticker.GuildSticker; +import net.dv8tion.jda.api.events.guild.GenericGuildEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@UtilityClass +@Slf4j +public class StickerUtils { + + @NonNull + public static final String FALLBACK_STRING = "N/A"; + + @NotNull + public static String resolveStickerUrl(@NonNull GenericGuildEvent event, @Nullable Object stickerIdObject) { + + if (stickerIdObject == null) { + log.debug("stickerIdObject is null (guild={})", event.getGuild().getId()); + return FALLBACK_STRING; + } + + String stickerIdStr = String.valueOf(stickerIdObject); + GuildSticker sticker = event.getGuild().getStickerById(String.valueOf(stickerIdObject)); + + if (sticker == null) { + log.debug("sticker not found (stickerIdObject={}, guild={})", stickerIdStr, event.getGuild().getId()); + return stickerIdStr; + } + + return sticker.getIconUrl(); + + } + + // emojiIdObject does NOT give you snowflake IDs in case of Unicode emojis + // it only gives u IDs in case of custom emojis + // any values caught by NumberFormatException are Unicode emojis and can be returned raw + @NotNull + public static String resolveRelatedEmoji(@NonNull GenericGuildEvent event, @Nullable Object emojiIdObject) { + + if (emojiIdObject == null) { + log.debug("emojiIdObject is null (guild={})", event.getGuild().getId()); + return FALLBACK_STRING; + } + + String emojiIdString = String.valueOf(emojiIdObject); + + try { + long emojiIdLong = Long.parseLong(emojiIdString); + Emoji emoji = event.getGuild().getEmojiById(emojiIdLong); + + if (emoji == null) { + log.debug("custom emoji not found (emojiIdLong={}, guild={})", emojiIdLong, event.getGuild().getId()); + return emojiIdString; + } + return emoji.getFormatted(); + + } catch (NumberFormatException e) { + log.debug("value is not numeric, treating as Unicode (value={}, guild={})", emojiIdString, event.getGuild().getId()); + return emojiIdString; + } + + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/ThreadCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/ThreadCreateEventHelper.java new file mode 100644 index 00000000..ce382f44 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/ThreadCreateEventHelper.java @@ -0,0 +1,88 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.thread; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.commons.utils.DurationUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.utils.ChannelUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.thread.utils.ThreadUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ThreadCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + ThreadChannel targetThread = event.getGuild().getThreadChannelById(ale.getTargetId()); + String mentionableTargetThread = (targetThread != null ? targetThread.getAsMention() : ale.getTargetId()); + + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Thread Create Event"); + eb.setDescription("ℹ️ A thread has been created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "locked" -> eb.addField("Locked", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), false); + + case "auto_archive_duration" -> + eb.addField("Auto Archive Duration", "β•°β”ˆβž€" + ThreadUtils.resolveAutoArchiveDuration(newValue), false); + + case "rate_limit_per_user" -> + eb.addField("Slow Mode Limit", "β•°β”ˆβž€" + DurationUtils.formatSeconds(newValue), false); + + case "type" -> eb.addField("Thread Type", "β•°β”ˆβž€" + ChannelUtils.resolveChannelType(newValue), false); + + case "archived" -> eb.addField("Archived", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), false); + + case "flags" -> { + // skip + } + case "invitable" -> eb.addField("Invitable", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), false); + + case "name" -> eb.addField("Thread Name", "β•°β”ˆβž€" + newValue, false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + eb.addField("Target Thread", "β•°β”ˆβž€" + mentionableTargetThread, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/ThreadDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/ThreadDeleteEventHelper.java new file mode 100644 index 00000000..2f9bae55 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/ThreadDeleteEventHelper.java @@ -0,0 +1,83 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.thread; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.commons.utils.DurationUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.utils.ChannelUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.thread.utils.ThreadUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ThreadDeleteEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Thread Delete Event"); + eb.setDescription("ℹ️ A thread has been deleted by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "locked" -> eb.addField("Locked", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), false); + + case "auto_archive_duration" -> + eb.addField("Auto Archive Duration", "β•°β”ˆβž€" + ThreadUtils.resolveAutoArchiveDuration(oldValue), false); + + case "rate_limit_per_user" -> + eb.addField("Slow Mode Limit", "β•°β”ˆβž€" + DurationUtils.formatSeconds(oldValue), false); + + case "type" -> eb.addField("Thread Type", "β•°β”ˆβž€" + ChannelUtils.resolveChannelType(oldValue), false); + + case "archived" -> eb.addField("Archived", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), false); + + case "flags" -> { + // skip + } + + case "invitable" -> eb.addField("Invitable", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), false); + + case "name" -> eb.addField("Thread Name", "β•°β”ˆβž€" + oldValue, false); + + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/ThreadUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/ThreadUpdateEventHelper.java new file mode 100644 index 00000000..2851d6be --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/ThreadUpdateEventHelper.java @@ -0,0 +1,107 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.thread; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.commons.utils.DurationUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.channel.utils.ChannelUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.thread.utils.ThreadUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class ThreadUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + ThreadChannel targetThread = event.getGuild().getThreadChannelById(ale.getTargetId()); + String mentionableTargetThread = (targetThread != null ? targetThread.getAsMention() : ale.getTargetId()); + + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Thread Update Event"); + eb.setDescription("ℹ️ A thread has been updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + eb.addBlankField(true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "locked" -> { + eb.addField("Was Locked", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), true); + eb.addField("Is Locked", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), true); + eb.addBlankField(true); + } + case "auto_archive_duration" -> { + eb.addField("Old Auto Archive Duration", "β•°β”ˆβž€" + ThreadUtils.resolveAutoArchiveDuration(oldValue), true); + eb.addField("New Auto Archive Duration", "β•°β”ˆβž€" + ThreadUtils.resolveAutoArchiveDuration(newValue), true); + eb.addBlankField(true); + } + case "rate_limit_per_user" -> { + eb.addField("Old Slow Mode Limit", "β•°β”ˆβž€" + DurationUtils.formatSeconds(oldValue), true); + eb.addField("New Slow Mode Limit", "β•°β”ˆβž€" + DurationUtils.formatSeconds(newValue), true); + eb.addBlankField(true); + } + case "type" -> { + eb.addField("Old Thread Type", "β•°β”ˆβž€" + ChannelUtils.resolveChannelType(oldValue), true); + eb.addField("New Thread Type", "β•°β”ˆβž€" + ChannelUtils.resolveChannelType(newValue), true); + eb.addBlankField(true); + } + case "archived" -> { + eb.addField("Old Archive Status", "β•°β”ˆβž€" + BooleanUtils.formatToEnabledOrDisabled(oldValue), true); + eb.addField("New Archive Status", "β•°β”ˆβž€" + BooleanUtils.formatToEnabledOrDisabled(newValue), true); + eb.addBlankField(true); + } + case "flags" -> eb.addField("Flags", "β•°β”ˆβž€Thread flags were updated", false); + + case "invitable" -> { + eb.addField("Was Invitable", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(oldValue), true); + eb.addField("Is Invitable", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(newValue), true); + eb.addBlankField(true); + } + case "name" -> { + eb.addField("Old Thread Name", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Thread Name", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + eb.addField("Target Thread", "β•°β”ˆβž€" + mentionableTargetThread, false); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/utils/ThreadUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/utils/ThreadUtils.java new file mode 100644 index 00000000..86a5954e --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/thread/utils/ThreadUtils.java @@ -0,0 +1,31 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.thread.utils; + +import io.github.eggy03.papertrail.bot.commons.utils.NumberParseUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/* + * See {@link io.github.eggy03.papertrail.bot.commons.utils.StackWalkerUtils} + * and other utilities in the util package + * to know why logging isn't needed in some of the methods here + */ +@UtilityClass +public class ThreadUtils { + + @NonNull + public static final String FALLBACK_STRING = "N/A"; + + @NotNull + public static String resolveAutoArchiveDuration(@Nullable Object minutes) { + + Integer minuteInt = NumberParseUtils.parseInt(minutes); + + if (minuteInt == null) + return FALLBACK_STRING; + + return ThreadChannel.AutoArchiveDuration.fromKey(minuteInt).name(); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/WebhookCreateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/WebhookCreateEventHelper.java new file mode 100644 index 00000000..162f44f9 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/WebhookCreateEventHelper.java @@ -0,0 +1,69 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.webhook; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.guild.utils.GuildUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.webhook.utils.WebhookUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class WebhookCreateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Webhook Create Event"); + eb.setDescription("ℹ️ A webhook has been created by: " + mentionableExecutor); + eb.setColor(Color.GREEN); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "type" -> + eb.addField("Webhook Type", "β•°β”ˆβž€" + WebhookUtils.resolveWebhookEventType(newValue), false); + case "avatar_hash" -> { + // skip + } + case "channel_id" -> + eb.addField("Channel", "β•°β”ˆβž€" + GuildUtils.resolveMentionableChannel(newValue, event), false); + case "name" -> eb.addField("Webhook Name", "β•°β”ˆβž€" + newValue, false); + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/WebhookRemoveEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/WebhookRemoveEventHelper.java new file mode 100644 index 00000000..10d308a6 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/WebhookRemoveEventHelper.java @@ -0,0 +1,69 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.webhook; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.guild.utils.GuildUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.webhook.utils.WebhookUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class WebhookRemoveEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Webhook Remove Event"); + eb.setDescription("ℹ️ A webhook has been removed by: " + mentionableExecutor); + eb.setColor(Color.RED); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "type" -> + eb.addField("Webhook Type", "β•°β”ˆβž€" + WebhookUtils.resolveWebhookEventType(oldValue), false); + case "avatar_hash" -> { + // skip + } + case "channel_id" -> + eb.addField("Channel", "β•°β”ˆβž€" + GuildUtils.resolveMentionableChannel(oldValue, event), false); + case "name" -> eb.addField("Webhook Name", "β•°β”ˆβž€" + oldValue, false); + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/WebhookUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/WebhookUpdateEventHelper.java new file mode 100644 index 00000000..e3bd5837 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/WebhookUpdateEventHelper.java @@ -0,0 +1,80 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.webhook; + +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.guild.utils.GuildUtils; +import io.github.eggy03.papertrail.bot.listeners.auditlog.helper.webhook.utils.WebhookUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.audit.AuditLogEntry; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; + +import java.awt.Color; + +@UtilityClass +@Slf4j +public class WebhookUpdateEventHelper { + + public static void format(@NonNull GuildAuditLogEntryCreateEvent event, @NonNull String channelIdToSendTo) { + + AuditLogEntry ale = event.getEntry(); + + User executor = ale.getJDA().getUserById(ale.getUserIdLong()); + String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Entry | Webhook Update Event"); + eb.setDescription("ℹ️ A webhook has been updated by: " + mentionableExecutor); + eb.setColor(Color.YELLOW); + + eb.addField("Action Type", String.valueOf(ale.getType()), true); + eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); + eb.addBlankField(true); + + ale.getChanges().forEach((changeKey, changeValue) -> { + Object oldValue = changeValue.getOldValue(); + Object newValue = changeValue.getNewValue(); + + switch (changeKey) { + + case "type" -> { + eb.addField("Old Webhook Type", "β•°β”ˆβž€" + WebhookUtils.resolveWebhookEventType(oldValue), true); + eb.addField("New Webhook Type", "β•°β”ˆβž€" + WebhookUtils.resolveWebhookEventType(newValue), true); + eb.addBlankField(true); + } + case "avatar_hash" -> eb.addField("Avatar", "β•°β”ˆβž€Avatar has been updated", false); + + case "channel_id" -> { + eb.addField("Old Channel", "β•°β”ˆβž€" + GuildUtils.resolveMentionableChannel(oldValue, event), true); + eb.addField("New Channel", "β•°β”ˆβž€" + GuildUtils.resolveMentionableChannel(newValue, event), true); + eb.addBlankField(true); + } + case "name" -> { + eb.addField("Old Webhook Name", "β•°β”ˆβž€" + oldValue, true); + eb.addField("New Webhook Name", "β•°β”ˆβž€" + newValue, true); + eb.addBlankField(true); + } + default -> { + eb.addField("Unimplemented Change Key", changeKey, false); + log.info("Unimplemented Change Key: {}\nOLD_VALUE: {}\nNEW_VALUE: {}", changeKey, oldValue, newValue); + } + } + }); + + eb.setFooter("Audit Log Entry ID: " + ale.getId()); + eb.setTimestamp(ale.getTimeCreated()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } + +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/utils/WebhookUtils.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/utils/WebhookUtils.java new file mode 100644 index 00000000..916a8791 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/helper/webhook/utils/WebhookUtils.java @@ -0,0 +1,28 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.helper.webhook.utils; + +import io.github.eggy03.papertrail.bot.commons.utils.NumberParseUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@UtilityClass +@Slf4j +public class WebhookUtils { + + @NonNull + public static final String FALLBACK_STRING = "N/A"; + + @NotNull + public static String resolveWebhookEventType(@Nullable Object webhookInteger) { + Integer webhook = NumberParseUtils.parseInt(webhookInteger); + + return switch (webhook) { + case 0 -> "Ping"; + case 1 -> "Events"; + case null -> FALLBACK_STRING; + default -> "Unknown Type: " + webhook; + }; + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/setup/AuditLogSetupCommandListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/setup/AuditLogSetupCommandListener.java new file mode 100644 index 00000000..92feffd4 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlog/setup/AuditLogSetupCommandListener.java @@ -0,0 +1,125 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlog.setup; + +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; +import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +import java.awt.Color; +import java.util.Optional; + +@Slf4j +public class AuditLogSetupCommandListener extends ListenerAdapter { + + @NonNull + private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); + + @Override + public void onSlashCommandInteraction(@NonNull SlashCommandInteractionEvent event) { + + if (!event.getName().equals("auditlog") || event.getSubcommandName() == null) { + return; + } + + switch (event.getSubcommandName()) { + case "set" -> setAuditLogging(event); + case "view" -> retrieveAuditLoggingChannel(event); + case "remove" -> unsetAuditLogging(event); + default -> { + // do nothing + } + } + } + + private void setAuditLogging(@NonNull SlashCommandInteractionEvent event) { + + Guild callerGuild = event.getGuild(); + GuildChannel callerChannel = event.getChannel().asTextChannel(); + if (callerGuild == null) { + log.warn("An audit log set command may have been called outside of a guild. This should not happen."); + return; + } + + // Call the API to register the guild and the channel + boolean success = client.registerGuild(callerGuild.getId(), callerChannel.getId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Registration Process"); + + if (success) { + eb.setColor(Color.GREEN); + eb.addField("βœ… Channel Registration Success", "β•°β”ˆβž€" + "All audit log info will be logged here", false); + } else { + eb.setColor(Color.YELLOW); + eb.addField("❌ Channel Registration Failure", "β•°β”ˆβž€" + "Channel could not be registered.\nCheck if a channel in this guild is already registered for logging.", false); + } + + MessageEmbed mb = eb.build(); + event.replyEmbeds(mb).setEphemeral(false).queue(); + } + + private void retrieveAuditLoggingChannel(@NonNull SlashCommandInteractionEvent event) { + + Guild callerGuild = event.getGuild(); + if (callerGuild == null) { + log.warn("An audit log view command may have been called outside of a guild. This should not happen."); + return; + } + + // Call the API to retrieve the registered channel + Optional response = client.getRegisteredGuild(callerGuild.getId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("View Existing Audit Log Configuration"); + + // if there is no channel_id for the given guild_id returned by the API, then inform + // the user of the same, else link the channel that has been registered + response.ifPresentOrElse(success -> { + String registeredChannelId = success.getChannelId(); + GuildChannel registeredChannel = event.getJDA().getGuildChannelById(registeredChannelId); + String mentionableRegisteredChannel = registeredChannel != null ? registeredChannel.getAsMention() : registeredChannelId; + + eb.setColor(Color.CYAN); + eb.addField("βœ… Channel Registration Check", "β•°β”ˆβž€" + mentionableRegisteredChannel + " is found to be registered as the audit log channel", false); + }, () -> { + eb.setColor(Color.YELLOW); + eb.addField("⚠️ Channel Registration Check", "β•°β”ˆβž€" + "No channel has been registered for audit logs", false); + }); + + MessageEmbed mb = eb.build(); + event.replyEmbeds(mb).setEphemeral(false).queue(); + } + + private void unsetAuditLogging(@NonNull SlashCommandInteractionEvent event) { + + Guild callerGuild = event.getGuild(); + if (callerGuild == null) { + log.warn("An audit log unset command may have been called outside of a guild. This should not happen."); + return; + } + + // Call the API to unregister guild + boolean success = client.deleteRegisteredGuild(callerGuild.getId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Audit Log Un-Registration Process"); + + if (success) { + eb.setColor(Color.GREEN); + eb.addField("βœ… Channel Removal", "β•°β”ˆβž€" + "Channel successfully unset", false); + } else { + eb.setColor(Color.YELLOW); + eb.addField("❌ Channel Removal Failure", "β•°β”ˆβž€" + "Channel could not be unset.\nThis may be because no channel has been registered in this guild yet.", false); + } + + MessageEmbed mb = eb.build(); + event.replyEmbeds(mb).setEphemeral(false).queue(); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildBoostEventListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildBoostEventListener.java new file mode 100644 index 00000000..bfcd7218 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildBoostEventListener.java @@ -0,0 +1,61 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.event.guild; + +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild.GuildMemberUpdateBoostTimeEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild.GuildUpdateBoostCountEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild.GuildUpdateBoostTierEventHelper; +import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; +import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateBoostTimeEvent; +import net.dv8tion.jda.api.events.guild.update.GuildUpdateBoostCountEvent; +import net.dv8tion.jda.api.events.guild.update.GuildUpdateBoostTierEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +import java.util.Optional; +import java.util.concurrent.Executor; + +// Experimental +@RequiredArgsConstructor +public class GuildBoostEventListener extends ListenerAdapter { + + @NonNull + private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); + + @NonNull + private final Executor vThreadPool; + + @Override + public void onGuildUpdateBoostTier(@NonNull GuildUpdateBoostTierEvent event) { + + vThreadPool.execute(() -> { + Optional response = client.getRegisteredGuild(event.getGuild().getId()); + response.ifPresent(success -> + GuildUpdateBoostTierEventHelper.format(event, success.getChannelId()) + ); + }); + } + + @Override + public void onGuildUpdateBoostCount(@NonNull GuildUpdateBoostCountEvent event) { + + vThreadPool.execute(() -> { + Optional response = client.getRegisteredGuild(event.getGuild().getId()); + response.ifPresent(success -> + GuildUpdateBoostCountEventHelper.format(event, success.getChannelId()) + ); + }); + } + + @Override + public void onGuildMemberUpdateBoostTime(@NonNull GuildMemberUpdateBoostTimeEvent event) { + + vThreadPool.execute(() -> { + Optional response = client.getRegisteredGuild(event.getGuild().getId()); + response.ifPresent(success -> + GuildMemberUpdateBoostTimeEventHelper.format(event, success.getChannelId()) + ); + }); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildMemberJoinAndLeaveEventListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildMemberJoinAndLeaveEventListener.java new file mode 100644 index 00000000..bc522e3d --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildMemberJoinAndLeaveEventListener.java @@ -0,0 +1,53 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.event.guild; + +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild.GuildMemberJoinEventHelper; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild.GuildMemberRemoveEventHelper; +import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; +import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +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.Optional; +import java.util.concurrent.Executor; + +// this event is not properly logged in the audit logs, hence the usage of JDA's listener is preferred +// this event is logged in the same channel where the audit log events are logged +@RequiredArgsConstructor +public class GuildMemberJoinAndLeaveEventListener extends ListenerAdapter { + + @NonNull + private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); + + @NonNull + private final Executor vThreadPool; + + @Override + public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) { + + vThreadPool.execute(() -> { + // Call the API and see if the event came from a registered Guild + Optional response = client.getRegisteredGuild(event.getGuild().getId()); + response.ifPresent(success -> + GuildMemberJoinEventHelper.format(event, success.getChannelId()) + ); + }); + } + + @Override + public void onGuildMemberRemove(@NotNull GuildMemberRemoveEvent event) { + + vThreadPool.execute(() -> { + // Call the API and see if the event came from a registered Guild + Optional response = client.getRegisteredGuild(event.getGuild().getId()); + response.ifPresent(success -> + GuildMemberRemoveEventHelper.format(event, success.getChannelId()) + ); + }); + } + +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildPollEventListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildPollEventListener.java new file mode 100644 index 00000000..56bb3c7f --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildPollEventListener.java @@ -0,0 +1,45 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.event.guild; + +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild.GuildPollEventHelper; +import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; +import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.messages.MessagePoll; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +import java.util.Optional; +import java.util.concurrent.Executor; + +// guild poll events are mapped to audit log table +@RequiredArgsConstructor +public class GuildPollEventListener extends ListenerAdapter { + + @NonNull + private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); + + @NonNull + private final Executor vThreadPool; + + @Override + public void onMessageReceived(@NonNull MessageReceivedEvent event) { + + if (!event.isFromGuild()) + return; + + // check if message has a poll + MessagePoll messagePoll = event.getMessage().getPoll(); + if (messagePoll == null) + return; + + vThreadPool.execute(() -> { + // Call the API and see if the event came from a registered Guild + Optional response = client.getRegisteredGuild(event.getGuild().getId()); + response.ifPresent(success -> + GuildPollEventHelper.format(event, messagePoll, success.getChannelId()) + ); + }); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildVoiceEventListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildVoiceEventListener.java new file mode 100644 index 00000000..8ec99ddd --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/event/guild/GuildVoiceEventListener.java @@ -0,0 +1,38 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.event.guild; + +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild.GuildVoiceEventHelper; +import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; +import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; +import java.util.concurrent.Executor; + +// this event is not properly logged in the audit logs, hence the usage of JDA's listener is preferred +// this event is logged in the same channel where the audit log events are logged +@RequiredArgsConstructor +public class GuildVoiceEventListener extends ListenerAdapter { + + @NonNull + private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); + + @NonNull + private final Executor vThreadPool; + + @Override + public void onGuildVoiceUpdate(@NotNull GuildVoiceUpdateEvent event) { + + vThreadPool.execute(() -> { + // Call the API and see if the event came from a registered Guild + Optional response = client.getRegisteredGuild(event.getGuild().getId()); + response.ifPresent(success -> + GuildVoiceEventHelper.format(event, success.getChannelId()) + ); + }); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildMemberJoinEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildMemberJoinEventHelper.java new file mode 100644 index 00000000..26693783 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildMemberJoinEventHelper.java @@ -0,0 +1,51 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.commons.utils.DurationUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent; + +import java.awt.Color; +import java.time.Instant; + +@UtilityClass +@Slf4j +public class GuildMemberJoinEventHelper { + + public static void format(@NonNull GuildMemberJoinEvent event, @NonNull String channelIdToSendTo) { + + Guild guild = event.getGuild(); + User user = event.getUser(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ›¬ Member Join Event"); + eb.setDescription("A Member has joined " + guild.getName()); + eb.setThumbnail(user.getEffectiveAvatarUrl()); + eb.setColor(Color.GREEN); + + eb.addField("Member Name", "β•°β”ˆβž€" + user.getName(), false); + eb.addField("Member Mention", "β•°β”ˆβž€" + user.getAsMention(), false); + eb.addField("Member ID", "β•°β”ˆβž€" + user.getId(), false); + eb.addField("Account Created", "β•°β”ˆβž€" + DurationUtils.isoToLocalTimeCounter(user.getTimeCreated()), false); + eb.addField("Bot Account", "β•°β”ˆβž€" + BooleanUtils.formatToYesOrNo(user.isBot()), false); + + eb.setFooter(event.getGuild().getName()); + eb.setTimestamp(Instant.now()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildMemberRemoveEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildMemberRemoveEventHelper.java new file mode 100644 index 00000000..211b6d60 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildMemberRemoveEventHelper.java @@ -0,0 +1,68 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +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.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent; +import org.jetbrains.annotations.NotNull; + +import java.awt.Color; +import java.time.Instant; + +@UtilityClass +@Slf4j +public class GuildMemberRemoveEventHelper { + + public static void format(@NonNull GuildMemberRemoveEvent event, @NonNull String channelIdToSendTo) { + + Guild guild = event.getGuild(); + User user = event.getUser(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ›« Member Leave Event"); + eb.setDescription("A Member has left " + guild.getName()); + eb.setThumbnail(user.getEffectiveAvatarUrl()); + eb.setColor(Color.RED); + + eb.addField("🏷️ Member Name", "β•°β”ˆβž€" + user.getName(), false); + eb.addField("πŸ†” Member ID", "β•°β”ˆβž€" + user.getId(), false); + eb.addField("βŒ› Member Joined The Server On", "β•°β”ˆβž€" + getMemberJoinDate(event), false); + eb.addField("βŒ› Member Left The Server On", "β•°β”ˆβž€" + getMemberLeaveDate(), false); + + eb.setFooter(event.getGuild().getName()); + eb.setTimestamp(Instant.now()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } + + @NotNull + private static String getMemberJoinDate (@NonNull GuildMemberRemoveEvent event) { + + Member member = event.getMember(); + if(member==null) + return "Member not cached"; + + if (member.hasTimeJoined()) + return ""; + + return "Unavailable"; + } + + @NotNull + private static String getMemberLeaveDate () { + return ""; + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildMemberUpdateBoostTimeEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildMemberUpdateBoostTimeEventHelper.java new file mode 100644 index 00000000..ceb69c14 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildMemberUpdateBoostTimeEventHelper.java @@ -0,0 +1,56 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +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.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateBoostTimeEvent; + +import java.awt.Color; +import java.time.Instant; +import java.time.OffsetDateTime; + +@UtilityClass +@Slf4j +public class GuildMemberUpdateBoostTimeEventHelper { + + public static void format(@NonNull GuildMemberUpdateBoostTimeEvent event, @NonNull String channelIdToSendTo) { + Member member = event.getMember(); + Guild guild = event.getGuild(); + + String mentionableMember = member.getAsMention(); + + OffsetDateTime newBoostTime = event.getNewTimeBoosted(); // Will be null if the member stopped boosting + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Server Boost Event"); + eb.setThumbnail(guild.getIconUrl()); + eb.setImage(guild.getBannerUrl()); + + if (newBoostTime != null) { + eb.setDescription("**" + guild.getName() + "** has been boosted!"); + eb.setColor(Color.PINK); + eb.addField("Booster Gained", "β•°β”ˆβž€" + mentionableMember + " has applied their first boost to your server", false); + } else { + eb.setDescription("**" + guild.getName() + "** has lost a boost."); + eb.setColor(Color.GRAY); + eb.addField("Booster Lost", "β•°β”ˆβž€" + mentionableMember + " has removed their boost from your server", false); + } + + eb.setFooter(guild.getName()); + eb.setTimestamp(Instant.now()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildPollEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildPollEventHelper.java new file mode 100644 index 00000000..073bb163 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildPollEventHelper.java @@ -0,0 +1,69 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild; + +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.messages.MessagePoll; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.jetbrains.annotations.NotNull; + +import java.awt.Color; +import java.time.Instant; + +@UtilityClass +@Slf4j +public class GuildPollEventHelper { + + public static void format(@NonNull MessageReceivedEvent event, @NonNull MessagePoll messagePoll, @NonNull String channelIdToSendTo) { + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("\uD83D\uDCCA Poll Creation Log"); + eb.setColor(Color.PINK); + eb.setDescription("A Poll has been created"); + + eb.addField("Poll Creator", event.getAuthor().getAsMention(), false); + eb.addField("Question", messagePoll.getQuestion().getText(), false); + eb.addField("Answers", getMessagePollAnswers(messagePoll), false); + eb.addField("Poll Expiry Time", getPollExpiryTime(messagePoll), false); + eb.addField("Accepts Multiple Answers", BooleanUtils.formatToYesOrNo(messagePoll.isMultiAnswer()), false); + eb.addField("Channel", event.getChannel().getAsMention(), false); + + eb.setFooter("Poll Activity Detection"); + eb.setTimestamp(Instant.now()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } + + @NotNull + private static String getMessagePollAnswers(@NonNull MessagePoll messagePoll) { + + StringBuilder answers = new StringBuilder(); + messagePoll.getAnswers().forEach(answer -> answers + .append("*Answer: * ") + .append(answer.getText()) + .append(" *Emoji: * ") + .append(answer.getEmoji() == null ? "N/A" : answer.getEmoji().getFormatted()) + .append(System.lineSeparator()) + ); + + return answers.toString().trim(); + } + + @NotNull + private static String getPollExpiryTime(@NonNull MessagePoll messagePoll) { + return messagePoll.getTimeExpiresAt() != null ? + "" : + "Never Expires"; + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildUpdateBoostCountEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildUpdateBoostCountEventHelper.java new file mode 100644 index 00000000..bf48b48f --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildUpdateBoostCountEventHelper.java @@ -0,0 +1,46 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.update.GuildUpdateBoostCountEvent; + +import java.awt.Color; +import java.time.Instant; + +@UtilityClass +@Slf4j +public class GuildUpdateBoostCountEventHelper { + + public static void format(@NonNull GuildUpdateBoostCountEvent event, @NonNull String channelIdToSendTo) { + Guild guild = event.getGuild(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Server Boost Event"); + eb.setDescription("**" + guild.getName() + "** has had it's boost count updated!"); + + eb.setThumbnail(guild.getIconUrl()); + eb.setImage(guild.getBannerUrl()); + + eb.setColor(Color.YELLOW); + + eb.addField("Old Boost Count", "β•°β”ˆβž€" + event.getOldBoostCount(), false); + eb.addField("New Boost Count", "β•°β”ˆβž€" + event.getNewBoostCount(), false); + + eb.setFooter(guild.getName()); + eb.setTimestamp(Instant.now()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildUpdateBoostTierEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildUpdateBoostTierEventHelper.java new file mode 100644 index 00000000..14ca5510 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildUpdateBoostTierEventHelper.java @@ -0,0 +1,59 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.guild.update.GuildUpdateBoostTierEvent; + +import java.awt.Color; +import java.time.Instant; + +@UtilityClass +@Slf4j +public class GuildUpdateBoostTierEventHelper { + + public static void format(@NonNull GuildUpdateBoostTierEvent event, @NonNull String channelIdToSendTo) { + + Guild guild = event.getGuild(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Server Boost Tier Update"); + eb.setDescription(guild.getName() + " has had it's boost tier updated"); + + eb.setThumbnail(guild.getIconUrl()); + eb.setImage(guild.getBannerUrl()); + eb.setColor(Color.YELLOW); + + Guild.BoostTier oldBoostTier = event.getOldBoostTier(); + Guild.BoostTier newBoostTier = event.getNewBoostTier(); + + String oldTier = "**Tier:** " + oldBoostTier.name() + "\n" + + "**Max Emojis:** " + oldBoostTier.getMaxEmojis() + "\n" + + "**Max File Size:** " + oldBoostTier.getMaxFileSize() + "\n" + + "**Max Bitrate:** " + oldBoostTier.getMaxBitrate(); + + String newTier = "**Tier:** " + newBoostTier.name() + "\n" + + "**Max Emojis:** " + newBoostTier.getMaxEmojis() + "\n" + + "**Max File Size:** " + newBoostTier.getMaxFileSize() + "\n" + + "**Max Bitrate:** " + newBoostTier.getMaxBitrate(); + + eb.addField("Old Boost Tier Information", oldTier, false); + eb.addField("New Boost Tier Information", newTier, false); + + eb.setFooter(guild.getName()); + eb.setTimestamp(Instant.now()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildVoiceEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildVoiceEventHelper.java new file mode 100644 index 00000000..87fb7c7b --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/helper/guild/GuildVoiceEventHelper.java @@ -0,0 +1,62 @@ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl.helper.guild; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent; + +import java.awt.Color; +import java.time.Instant; + +@UtilityClass +@Slf4j +public class GuildVoiceEventHelper { + + public static void format(@NonNull GuildVoiceUpdateEvent event, @NonNull String channelIdToSendTo) { + + Member member = event.getMember(); + AudioChannel left = event.getOldValue(); // can be null if user joined for first time + AudioChannel joined = event.getNewValue(); // can be null if user left + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ”Š Voice Activity Log"); + + if (left == null && joined != null) { + // User has joined a vc + eb.setDescription("A Member has joined a voice channel"); + eb.setColor(Color.GREEN); + eb.addField("βœ… Member Joined", "β•°β”ˆβž€" + member.getAsMention() + " joined the voice channel " + joined.getAsMention(), false); + } + + if (left != null && joined != null) { + // Moved from one channel to another + eb.setDescription("A Member has switched voice channels"); + eb.setColor(Color.YELLOW); + eb.addField("πŸ”„ Member Switched Channels", "β•°β”ˆβž€" + member.getAsMention() + " joined the switched from channel " + left.getAsMention() + " to " + joined.getAsMention(), false); + } + + if (left != null && joined == null) { + // User disconnected voluntarily (or was disconnected by a moderator) + eb.setDescription("A Member has left a voice channel"); + eb.setColor(Color.RED); + eb.addField("❌ Member Left A Voice Channel", "β•°β”ˆβž€" + member.getAsMention() + " left the voice channel " + left.getAsMention(), false); + } + + eb.setFooter("Voice Activity Detection"); + eb.setTimestamp(Instant.now()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/package-info.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/package-info.java new file mode 100644 index 00000000..32c3b435 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/auditlogsupl/package-info.java @@ -0,0 +1,12 @@ +/** + * Contains supplementary audit-style event listeners for actions not covered + * by Discord's native audit log system. + * + *

These listeners observe events that are audit-relevant (such as guild, + * thread, or other structural changes) but cannot be derived from + * {@link net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent} entries.

+ * + *

All events in this package log to the same destination and follow the same + * formatting and conventions as standard audit log listeners and hence, no additional setup is required.

+ */ +package io.github.eggy03.papertrail.bot.listeners.auditlogsupl; \ No newline at end of file diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/event/MessageLogListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/event/MessageLogListener.java new file mode 100644 index 00000000..5a503a1d --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/event/MessageLogListener.java @@ -0,0 +1,101 @@ +package io.github.eggy03.papertrail.bot.listeners.messagelog.event; + +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import io.github.eggy03.papertrail.bot.listeners.messagelog.helper.MessageLogMessageDeleteEventHelper; +import io.github.eggy03.papertrail.bot.listeners.messagelog.helper.MessageLogMessageReceivedEventHelper; +import io.github.eggy03.papertrail.bot.listeners.messagelog.helper.MessageLogMessageUpdateEventHelper; +import io.github.eggy03.papertrail.sdk.client.MessageLogContentClient; +import io.github.eggy03.papertrail.sdk.client.MessageLogRegistrationClient; +import io.github.eggy03.papertrail.sdk.entity.MessageLogRegistrationEntity; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.events.message.MessageDeleteEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageUpdateEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +import java.util.Optional; +import java.util.concurrent.Executor; + +@Slf4j +@RequiredArgsConstructor +public class MessageLogListener extends ListenerAdapter { + + @NonNull + private static final MessageLogRegistrationClient registrationClient = new MessageLogRegistrationClient(EnvConfig.get("API_URL")); + @NonNull + private static final MessageLogContentClient contentClient = new MessageLogContentClient(EnvConfig.get("API_URL")); + @NonNull + private final Executor vThreadPool; + + @Override + public void onMessageReceived(@NonNull MessageReceivedEvent event) { + + // if the author is a bot or system, don't log + if (event.getAuthor().isBot() || event.getAuthor().isSystem()) { + return; + } + // don't register non-textual contents + if (event.getMessage().getContentRaw().isEmpty()) { + return; + } + + vThreadPool.execute(() -> { + // get the guild id for which the event was fired + String guildId = event.getGuild().getId(); + // Call the API to see if the guild is registered for Message Logging + Optional response = registrationClient.getRegisteredGuild(guildId); + response.ifPresent(success -> + MessageLogMessageReceivedEventHelper.saveMessage(event, contentClient) + ); + }); + } + + @Override + public void onMessageUpdate(@NonNull MessageUpdateEvent event) { + + if (event.getAuthor().isBot() || event.getAuthor().isSystem()) { + return; + } + + vThreadPool.execute(() -> { + // Get the guild id for which the event was fired + String guildId = event.getGuild().getId(); + // Call the API to see if the guild is registered for Message Logging + Optional response = registrationClient.getRegisteredGuild(guildId); + response.ifPresent(success -> { + + // get the message id of the message which was updated + String messageId = event.getMessageId(); + // retrieve the channel id where the logs must be sent + String channelIdToSendTo = success.getChannelId(); + // update message + MessageLogMessageUpdateEventHelper.updateMessage(event, contentClient, messageId, channelIdToSendTo); + }); + }); + } + + @Override + public void onMessageDelete(@NonNull MessageDeleteEvent event) { + + vThreadPool.execute(() -> { + + // Get the guild id for which the event was fired + String guildId = event.getGuild().getId(); + + // Call the API to see if the guild is registered for Message Logging + Optional response = registrationClient.getRegisteredGuild(guildId); + response.ifPresent(success -> { + + // get the message id of the message which was deleted + String messageId = event.getMessageId(); + // retrieve the channel id where the logs must be sent + String channelIdToSendTo = success.getChannelId(); + // delete message + MessageLogMessageDeleteEventHelper.deleteMessage(event, contentClient, messageId, channelIdToSendTo); + + }); + }); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/helper/MessageLogMessageDeleteEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/helper/MessageLogMessageDeleteEventHelper.java new file mode 100644 index 00000000..f914dc2d --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/helper/MessageLogMessageDeleteEventHelper.java @@ -0,0 +1,63 @@ +package io.github.eggy03.papertrail.bot.listeners.messagelog.helper; + +import com.google.common.base.Splitter; +import io.github.eggy03.papertrail.sdk.client.MessageLogContentClient; +import io.github.eggy03.papertrail.sdk.entity.MessageLogContentEntity; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.message.MessageDeleteEvent; + +import java.awt.Color; +import java.time.Instant; +import java.util.List; +import java.util.Optional; + +@UtilityClass +@Slf4j +public class MessageLogMessageDeleteEventHelper { + + public static void deleteMessage(@NonNull MessageDeleteEvent event, @NonNull MessageLogContentClient client, @NonNull String deletedMessageId, @NonNull String channelIdToSendTo) { + // fetch the old message object from the API + Optional oldMessageContent = client.retrieveMessage(deletedMessageId); + oldMessageContent.ifPresent(contentEntity -> { + + // retrieve the stored message and author in the database which was deleted + String deletedMessage = contentEntity.getMessageContent(); + String deletedMessageAuthorId = contentEntity.getAuthorId(); + + User author = event.getJDA().getUserById(deletedMessageAuthorId); + String mentionableAuthor = (author != null ? author.getAsMention() : deletedMessageAuthorId); + + // Splitting is required because each field in an embed can display only up-to 1024 characters + List deletedMessageSplits = Splitter.fixedLength(1024).splitToList(deletedMessage); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ—‘οΈ Message Delete Event"); + eb.setDescription("A message sent by " + mentionableAuthor + " has been deleted from " + event.getChannel().getAsMention()); + eb.setColor(Color.RED); + + deletedMessageSplits.forEach(split -> eb.addField("Deleted Message", split, false)); + + eb.setFooter(event.getGuild().getName()); + eb.setTimestamp(Instant.now()); + + // delete the message from the database + client.deleteMessage(deletedMessageId); + + // send the fetched deleted message to the logging channel + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + }); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/helper/MessageLogMessageReceivedEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/helper/MessageLogMessageReceivedEventHelper.java new file mode 100644 index 00000000..417a6bb8 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/helper/MessageLogMessageReceivedEventHelper.java @@ -0,0 +1,19 @@ +package io.github.eggy03.papertrail.bot.listeners.messagelog.helper; + +import io.github.eggy03.papertrail.sdk.client.MessageLogContentClient; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; + +@UtilityClass +public class MessageLogMessageReceivedEventHelper { + + public static void saveMessage(@NonNull MessageReceivedEvent event, @NonNull MessageLogContentClient client) { + + String messageId = event.getMessageId(); + String messageContent = event.getMessage().getContentDisplay(); + String authorId = event.getAuthor().getId(); + + client.logMessage(messageId, messageContent, authorId); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/helper/MessageLogMessageUpdateEventHelper.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/helper/MessageLogMessageUpdateEventHelper.java new file mode 100644 index 00000000..a4c02b15 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/helper/MessageLogMessageUpdateEventHelper.java @@ -0,0 +1,69 @@ +package io.github.eggy03.papertrail.bot.listeners.messagelog.helper; + +import com.google.common.base.Splitter; +import io.github.eggy03.papertrail.sdk.client.MessageLogContentClient; +import io.github.eggy03.papertrail.sdk.entity.MessageLogContentEntity; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.message.MessageUpdateEvent; + +import java.awt.Color; +import java.time.Instant; +import java.util.List; +import java.util.Optional; + +@UtilityClass +@Slf4j +public class MessageLogMessageUpdateEventHelper { + + public static void updateMessage(@NonNull MessageUpdateEvent event, @NonNull MessageLogContentClient client, @NonNull String updatedMessageId, @NonNull String channelIdToSendTo) { + + // fetch the old message object from the API + Optional oldMessageContent = client.retrieveMessage(updatedMessageId); + oldMessageContent.ifPresent(contentEntity -> { + // Fetch the old message + String oldMessage = contentEntity.getMessageContent(); + // fetch the updated message and its author from the event + String updatedMessage = event.getMessage().getContentDisplay(); + + // Ignore events where the message content wasn't edited (e.g., pin, embed resolve, thread creates and updates) + // This is required since MessageUpdateEvent is triggered in case of pins and embed resolves with no change to content + if (updatedMessage.equals(oldMessage)) { + return; + } + + // Splitting is required because each field in an embed can display only up-to 1024 characters + // A full embed can display up-to 6000 characters + List oldMessageSplits = Splitter.fixedLength(1024).splitToList(oldMessage); + List updatedMessageSplits = Splitter.fixedLength(1024).splitToList(updatedMessage); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ“ Message Edit Event"); + eb.setDescription("A message sent by " + event.getAuthor().getAsMention() + " has been edited in: " + event.getJumpUrl()); + eb.setColor(Color.YELLOW); + + oldMessageSplits.forEach(split -> eb.addField("Old Message", split, false)); + updatedMessageSplits.forEach(split -> eb.addField("New Message", split, false)); + + eb.setFooter(event.getGuild().getName()); + eb.setTimestamp(Instant.now()); + + // update the database with the new message + client.updateMessage(updatedMessageId, updatedMessage, event.getAuthor().getId()); + + if (!eb.isValidLength() || eb.isEmpty()) { + log.warn("Embed is empty or too long (current length: {}).", eb.length()); + return; + } + + // send the old and updated message to the registered channel + TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); + if (sendingChannel != null && sendingChannel.canTalk()) { + sendingChannel.sendMessageEmbeds(eb.build()).queue(); + } + }); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/setup/MessageLogSetupCommandListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/setup/MessageLogSetupCommandListener.java new file mode 100644 index 00000000..91a5c510 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/messagelog/setup/MessageLogSetupCommandListener.java @@ -0,0 +1,123 @@ +package io.github.eggy03.papertrail.bot.listeners.messagelog.setup; + +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import io.github.eggy03.papertrail.sdk.client.MessageLogRegistrationClient; +import io.github.eggy03.papertrail.sdk.entity.MessageLogRegistrationEntity; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +import java.awt.Color; +import java.util.Optional; + +@Slf4j +public class MessageLogSetupCommandListener extends ListenerAdapter { + + @NonNull + private static final MessageLogRegistrationClient client = new MessageLogRegistrationClient(EnvConfig.get("API_URL")); + + @Override + public void onSlashCommandInteraction(@NonNull SlashCommandInteractionEvent event) { + + if (!event.getName().equals("messagelog") || event.getSubcommandName() == null) { + return; + } + + switch (event.getSubcommandName()) { + case "set" -> setMessageLogging(event); + case "view" -> retrieveMessageLoggingChannel(event); + case "remove" -> unsetMessageLogging(event); + default -> { + // skip + } + } + } + + private void setMessageLogging(@NonNull SlashCommandInteractionEvent event) { + + Guild callerGuild = event.getGuild(); + GuildChannel callerChannel = event.getChannel().asTextChannel(); + if (callerGuild == null) { + log.warn("A message log set command may have been called outside of a guild. This should not happen."); + return; + } + + // Call the API to register guild for message logging + boolean success = client.registerGuild(callerGuild.getId(), callerChannel.getId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Message Log Registration Process"); + + if (success) { + eb.setColor(Color.GREEN); + eb.addField("βœ… Channel Registration Success", "β•°β”ˆβž€" + "All edited and deleted messages will be logged here", false); + } else { + eb.setColor(Color.YELLOW); + eb.addField("❌ Channel Registration Failure", "β•°β”ˆβž€" + "Channel could not be registered.\nCheck if a channel in this guild is already registered for logging.", false); + + } + + MessageEmbed mb = eb.build(); + event.replyEmbeds(mb).setEphemeral(false).queue(); + } + + private void retrieveMessageLoggingChannel(@NonNull SlashCommandInteractionEvent event) { + + Guild callerGuild = event.getGuild(); + if (callerGuild == null) { + log.warn("A message log view command may have been called outside of a guild. This should not happen."); + return; + } + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("View Existing Message Log Configuration"); + + // Call the API to check for registered guild + Optional response = client.getRegisteredGuild(callerGuild.getId()); + response.ifPresentOrElse(success -> { + + String registeredChannelId = success.getChannelId(); + GuildChannel registeredChannel = event.getJDA().getGuildChannelById(registeredChannelId); + String mentionableRegisteredChannel = registeredChannel != null ? registeredChannel.getAsMention() : registeredChannelId; + + eb.setColor(Color.CYAN); + eb.addField("βœ… Channel Registration Check", "β•°β”ˆβž€" + mentionableRegisteredChannel + " is found to be registered as the message log channel", false); + }, () -> { + eb.setColor(Color.YELLOW); + eb.addField("⚠️ Channel Registration Check", "β•°β”ˆβž€" + "No channel has been registered for message logs", false); + }); + + MessageEmbed mb = eb.build(); + event.replyEmbeds(mb).setEphemeral(false).queue(); + } + + private void unsetMessageLogging(@NonNull SlashCommandInteractionEvent event) { + + Guild callerGuild = event.getGuild(); + if (callerGuild == null) { + log.warn("A message log unset command may have been called outside of a guild. This should not happen."); + return; + } + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Message Log Un-Registration Process"); + + // Call the API to unregister guild + boolean success = client.deleteRegisteredGuild(callerGuild.getId()); + if (success) { + eb.setColor(Color.GREEN); + eb.addField("βœ… Channel Removal", "β•°β”ˆβž€" + "Channel successfully unset", false); + } else { + eb.setColor(Color.YELLOW); + eb.addField("❌ Channel Removal Failure", "β•°β”ˆβž€" + "Channel could not be unset.\nThis may be because no channel has been registered in this guild yet.", false); + } + + MessageEmbed mb = eb.build(); + event.replyEmbeds(mb).setEphemeral(false).queue(); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/ActivityUpdateListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/ActivityUpdateListener.java new file mode 100644 index 00000000..d171f563 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/ActivityUpdateListener.java @@ -0,0 +1,41 @@ +package io.github.eggy03.papertrail.bot.listeners.misc; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.Activity; +import net.dv8tion.jda.api.events.guild.GuildJoinEvent; +import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; +import net.dv8tion.jda.api.events.session.ReadyEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.sharding.ShardManager; +import org.jetbrains.annotations.NotNull; + +/* + * This class updates the number of servers the bot is in + */ +@RequiredArgsConstructor +public class ActivityUpdateListener extends ListenerAdapter { + + @NonNull + private final ShardManager manager; + + @Override + public void onReady(@NotNull ReadyEvent event) { // update on cold start + updateActivity(); + } + + @Override + public void onGuildJoin(@NotNull GuildJoinEvent event) { // update on guild join + updateActivity(); + } + + @Override + public void onGuildLeave(@NotNull GuildLeaveEvent event) { // update on guild leave + updateActivity(); + } + + private void updateActivity() { + manager.setActivity(Activity.customStatus("/setup | " + manager.getGuildCache().size() + " Servers")); + } + +} \ No newline at end of file diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/BotSetupInstructionCommandListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/BotSetupInstructionCommandListener.java new file mode 100644 index 00000000..9e355f33 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/BotSetupInstructionCommandListener.java @@ -0,0 +1,73 @@ +package io.github.eggy03.papertrail.bot.listeners.misc; + +import io.github.eggy03.papertrail.bot.commons.constant.ProjectInfo; +import lombok.NonNull; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +import java.awt.Color; +import java.time.Instant; + +public class BotSetupInstructionCommandListener extends ListenerAdapter { + + @Override + public void onSlashCommandInteraction(@NonNull SlashCommandInteractionEvent event) { + + if (event.getName().equals("setup")) { + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ› οΈ Setup Guide for " + ProjectInfo.APPNAME); + eb.setDescription("Follow the instructions below to set up the bot in your server."); + eb.setColor(Color.decode("#38e8bc")); + + eb.addField("1️⃣ Set Audit Log Channel", + "Use `/auditlog set` to **register this channel** for receiving audit log events.", + false); + + eb.addField("2️⃣ View Audit Log Channel", + "Use `/auditlog view` to **see which channel** is currently receiving audit logs.", + false); + + eb.addField("3️⃣ Remove Audit Log Channel", + "Use `/auditlog remove` to **stop logging** events and remove the registered channel.", + false); + + eb.addField("πŸ”’ Permissions", + "These three commands require the **Administrator** permission.", + false); + + eb.addBlankField(false); + + eb.addField("4️⃣ Set Message Log Channel", + "Use `/messagelog set` to **register this channel** for receiving message logs.", + false); + + eb.addField("5️⃣ View Message Log Channel", + "Use `/messagelog view` to **see which channel** is currently receiving message logs.", + false); + + eb.addField("6️⃣ Remove Message Log Channel", + "Use `/messagelog remove` to **stop logging** messages and remove the registered channel.", + false); + + eb.addField("πŸ”’ Permissions", + "These three commands require the **Administrator** permission.", + false); + + eb.addBlankField(false); + + eb.addField("7️⃣ View Server Stats", + "Use `/stats` to **view useful server information**, including member count, channel count, and more.", + false); + + eb.addField("πŸ“¬ Need help?", "Create an issue on [GitHub](" + ProjectInfo.PROJECT_ISSUE_LINK + ")", false); + eb.setFooter(ProjectInfo.APPNAME + " " + ProjectInfo.VERSION); + eb.setTimestamp(Instant.now()); + + MessageEmbed mb = eb.build(); + event.replyEmbeds(mb).setEphemeral(false).queue(); + } + } +} \ No newline at end of file diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/DebugListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/DebugListener.java new file mode 100644 index 00000000..602c1463 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/DebugListener.java @@ -0,0 +1,175 @@ +package io.github.eggy03.papertrail.bot.listeners.misc; + +import io.github.eggy03.papertrail.bot.commons.constant.ProjectInfo; +import io.github.eggy03.papertrail.bot.commons.utils.BooleanUtils; +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import io.github.eggy03.papertrail.sdk.client.HealthClient; +import io.github.eggy03.papertrail.sdk.entity.HealthEntity; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.JDA; +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.entities.channel.middleman.GuildChannel; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; + +import java.awt.Color; +import java.time.Instant; +import java.util.EnumSet; +import java.util.Optional; +import java.util.Set; + + +@Slf4j +public class DebugListener extends ListenerAdapter { + + // recommended permissions for the bot to function + private static final Set recommendedPermissions = EnumSet.of( + Permission.VIEW_CHANNEL, + Permission.VIEW_AUDIT_LOGS, + Permission.MANAGE_SERVER, + Permission.MESSAGE_SEND, + Permission.MESSAGE_SEND_IN_THREADS, + Permission.MESSAGE_EMBED_LINKS, + Permission.MESSAGE_HISTORY + ); + + @NotNull + public static String getBotPermissions(@NonNull Guild guild) { + return formatPermissions(guild.getSelfMember().getPermissions()); + } + + @NotNull + public static String getBotPermissionsInCurrentChannel(@NonNull Guild guild, @NonNull GuildChannel channel) { + return formatPermissions(guild.getSelfMember().getPermissions(channel)); + } + + @NotNull + private static String formatPermissions(@NonNull EnumSet grantedGuildOrChannelPermissions) { + // gets all the permissions granted to the bot in the server as a whole or a particular channel + EnumSet grantedPermissions = EnumSet.copyOf(grantedGuildOrChannelPermissions); + // this will + // 1) REMOVE the UNNECESSARY GRANTED PERMISSIONS + // 2) RETAIN those GRANTED PERMISSIONS that match with the RECOMMENDED ONES + // there may be cases where granted permissions is NOT a perfect superset of recommended permissions + // this indicates that some recommended permissions have been DENIED + grantedPermissions.retainAll(recommendedPermissions); + + // create a copy of recommended permissions + EnumSet deniedPermissions = EnumSet.copyOf(recommendedPermissions); + // now if you calculate recommended - granted, you will get the set of recommended permissions which are DENIED + deniedPermissions.removeAll(grantedPermissions); + + StringBuilder permString = new StringBuilder(); + grantedPermissions.forEach(permission -> + permString.append("βœ… - ") + .append(permission.getName()) + .append(System.lineSeparator()) + ); + + deniedPermissions.forEach(permission -> + permString.append("❌ - ") + .append(permission.getName()) + .append(System.lineSeparator()) + ); + + return permString.toString().trim(); + } + + @NotNull + public static String getServerInfo(@NonNull Guild guild, @NonNull GuildChannel channel) { + return "Server Name: `" + guild.getName() + "`" + System.lineSeparator() + + "Server ID: `" + guild.getId() + "`" + System.lineSeparator() + + "Channel Name: `" + channel.getName() + "`" + System.lineSeparator() + + "Channel ID: `" + channel.getId() + "`"; + } + + @NotNull + public static String getCallerInfo(@NonNull Member member) { + return "User Name: `" + member.getUser().getGlobalName() + "`" + System.lineSeparator() + + "User ID: `" + member.getId() + System.lineSeparator() + "`" + + "Is Administrator: `" + BooleanUtils.formatToYesOrNo(member.hasPermission(Permission.ADMINISTRATOR)) + "`"; + } + + @NotNull + public static String getBotInfo(@NonNull SlashCommandInteractionEvent event) { + JDA.ShardInfo shardInfo = event.getJDA().getShardInfo(); + return "Current Shard ID: `" + shardInfo.getShardId() + System.lineSeparator() + "`" + + "Total Shards: `" + shardInfo.getShardTotal() + "`"; + } + + @NotNull + public static String getApiInfo() { + Optional apiHealthEntity = new HealthClient(EnvConfig.get("API_URL")).getHealth(); + if (apiHealthEntity.isEmpty()) + return "⚠️ API Unreachable"; + + StringBuilder info = new StringBuilder(); + + HealthEntity health = apiHealthEntity.get(); + info.append("Overall API Status: ") + .append("`").append(health.getStatus()).append("`") + .append("\n"); + + HealthEntity.Components components = health.getComponents(); + if (components == null) { + info.append("⚠️ Individual Component Data Unavailable"); + return info.toString().trim(); + } + + HealthEntity.Components.Database database = components.getDb(); + HealthEntity.Components.Redis redis = components.getRedis(); + HealthEntity.Components.Ping ping = components.getPing(); + HealthEntity.Components.Ssl ssl = components.getSsl(); + + String databaseStatus = database != null ? database.getStatus() : "⚠️`DB Component Not Found`"; + String redisStatus = redis != null ? redis.getStatus() : "⚠️`Redis Component Not Found`"; + String pingStatus = ping != null ? ping.getStatus() : "⚠️`Ping Component Not Found`"; + String sslStatus = ssl != null ? ssl.getStatus() : "⚠️`SSL Component Not Found`"; + + info.append("Database: `").append(databaseStatus).append("`").append("\n") + .append("Redis: `").append(redisStatus).append("`").append("\n") + .append("Ping: `").append(pingStatus).append("`").append("\n") + .append("SSL: `").append(sslStatus).append("`"); + + return info.toString().trim(); + } + + @Override + public void onSlashCommandInteraction(@NonNull SlashCommandInteractionEvent event) { + + if (!event.getName().equals("debug")) + return; + + Guild guild = event.getGuild(); + Member member = event.getMember(); + if (guild == null || member == null) { + log.warn("command may have been called outside of a guild"); + return; + } + + GuildChannel channel = event.getGuildChannel(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("Debug Info"); + eb.setDescription("Server: " + guild.getName()); + eb.setColor(Color.GRAY); + + eb.addField("Bot Permissions", getBotPermissions(guild), true); + eb.addField("Channel Permissions", getBotPermissionsInCurrentChannel(guild, channel), true); + eb.addField("Server Info", getServerInfo(guild, channel), true); + + eb.addField("User Info", getCallerInfo(member), true); + eb.addField("Bot Info", getBotInfo(event), true); + eb.addField("API Info", getApiInfo(), true); + + eb.setFooter(ProjectInfo.APPNAME + " " + ProjectInfo.VERSION); + eb.setTimestamp(Instant.now()); + + event.replyEmbeds(eb.build()).queue(); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/SelfKickListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/SelfKickListener.java new file mode 100644 index 00000000..67a753e4 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/SelfKickListener.java @@ -0,0 +1,38 @@ +package io.github.eggy03.papertrail.bot.listeners.misc; + +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; +import io.github.eggy03.papertrail.sdk.client.MessageLogRegistrationClient; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +import java.util.concurrent.Executor; + +/* + * This class will have methods that unregister the log channels from the database after the bot has been kicked + */ +@RequiredArgsConstructor +public class SelfKickListener extends ListenerAdapter { + + @NonNull + private static final AuditLogRegistrationClient alClient = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); + + @NonNull + private static final MessageLogRegistrationClient mlClient = new MessageLogRegistrationClient(EnvConfig.get("API_URL")); + + @NonNull + private final Executor vThreadPool; + + @Override + public void onGuildLeave(@NonNull GuildLeaveEvent event) { + + Guild leftGuild = event.getGuild(); + vThreadPool.execute(() -> { + alClient.deleteRegisteredGuild(leftGuild.getId()); + mlClient.deleteRegisteredGuild(leftGuild.getId()); + }); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/ServerStatCommandListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/ServerStatCommandListener.java new file mode 100644 index 00000000..6d67a747 --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/ServerStatCommandListener.java @@ -0,0 +1,109 @@ +package io.github.eggy03.papertrail.bot.listeners.misc; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +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.MessageEmbed; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; + +import java.awt.Color; +import java.time.Instant; +import java.util.List; + +@Slf4j +public class ServerStatCommandListener extends ListenerAdapter { + + @NotNull + public static String getMemberAndBotCount(@NonNull Guild guild) { + + List memberCache = guild.getMemberCache().asList(); + int allUserCount = memberCache.size(); + int botCount = memberCache.stream().filter(member -> member.getUser().isBot()).toList().size(); + + return "Users: " + (allUserCount - botCount) + " Bots: " + botCount + " Total: " + allUserCount; + } + + @NotNull + public static String getGuildOwner(@NonNull Guild guild) { + Member owner = guild.getOwner(); + + return owner == null ? "N/A" : owner.getAsMention(); + } + + @NotNull + public static String getGuildCreationDate(@NonNull Guild guild) { + return ""; + } + + @NotNull + public static String getGuildVanityUrl(@NonNull Guild guild) { + return guild.getVanityUrl() == null ? "N/A" : guild.getVanityUrl(); + } + + @NotNull + public static String getBoosters(@NonNull Guild guild) { + StringBuilder boosterString = new StringBuilder(); + guild.getBoosters().forEach(booster -> boosterString.append(booster.getAsMention()).append(" ")); + return boosterString.toString().trim().isEmpty() ? "No Boosters" : boosterString.toString().trim(); + } + + @NotNull + public static String getBoosterRole(@NonNull Guild guild) { + return guild.getBoostRole() != null ? guild.getBoostRole().getAsMention() : "No Boost Role Found"; + } + + @NotNull + public static String getDataRequestingMember(@NonNull SlashCommandInteractionEvent event) { + Member requester = event.getMember(); + return requester != null ? requester.getEffectiveName() : "N/A"; + } + + @Override + public void onSlashCommandInteraction(@NonNull SlashCommandInteractionEvent event) { + + if (!event.getName().equals("stats")) { + return; + } + + Guild guild = event.getGuild(); + if (guild == null) { + log.warn("Command may have been called outside of a guild"); + return; + } + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ“Š Server Statistics πŸ“Š"); + eb.setDescription(guild.getName()); + eb.setThumbnail(guild.getIconUrl()); + eb.setColor(Color.PINK); + + eb.addField("Guild Owner", "β•°β”ˆβž€" + getGuildOwner(guild), false); + eb.addField("Guild Created On", "β•°β”ˆβž€" + getGuildCreationDate(guild), false); + eb.addField("Guild Vanity URL", "β•°β”ˆβž€" + getGuildVanityUrl(guild), false); + + eb.addField("Member Stats", "β•°β”ˆβž€" + getMemberAndBotCount(guild), false); + + eb.addField("Guild Boosters ", "β•°β”ˆβž€" + getBoosters(guild), false); + eb.addField("Guild Boost Count", "β•°β”ˆβž€" + guild.getBoostCount(), true); + eb.addField("Booster Role", "β•°β”ˆβž€" + getBoosterRole(guild), true); + eb.addField("Boost Tier", "β•°β”ˆβž€" + guild.getBoostTier().name(), true); + + eb.addField("Locale", "β•°β”ˆβž€" + guild.getLocale().getNativeName(), true); + eb.addField("Verification", "β•°β”ˆβž€" + guild.getVerificationLevel().name(), true); + eb.addField("Roles", "β•°β”ˆβž€" + guild.getRoles().size(), true); + eb.addField("Categories", "β•°β”ˆβž€" + guild.getCategories().size(), true); + eb.addField("Text Channels", "β•°β”ˆβž€" + guild.getTextChannels().size(), true); + eb.addField("Voice Channels", "β•°β”ˆβž€" + guild.getVoiceChannels().size(), true); + + eb.setFooter("Requested By: " + getDataRequestingMember(event)); + eb.setTimestamp(Instant.now()); + + MessageEmbed mb = eb.build(); + event.replyEmbeds(mb).setEphemeral(false).queue(); + + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/SlashCommandRegistrationListener.java b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/SlashCommandRegistrationListener.java new file mode 100644 index 00000000..918185de --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/listeners/misc/SlashCommandRegistrationListener.java @@ -0,0 +1,60 @@ +package io.github.eggy03.papertrail.bot.listeners.misc; + +import lombok.NonNull; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.events.session.ReadyEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.interactions.InteractionContextType; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.build.CommandData; +import net.dv8tion.jda.api.interactions.commands.build.Commands; +import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; + +/* + * Registers all the slash commands places throughout the code + */ +public class SlashCommandRegistrationListener extends ListenerAdapter { + + @Override + public void onReady(@NonNull ReadyEvent event) { + setAuditLogCommands(event.getJDA()); + } + + private void setAuditLogCommands(@NonNull JDA jda) { + + CommandData auditLog = Commands + .slash("auditlog", "manage audit log options") + .setContexts(InteractionContextType.GUILD) + .setDefaultPermissions(DefaultMemberPermissions.DISABLED) + .addSubcommands(new SubcommandData("set", "set audit log channel here")) + .addSubcommands(new SubcommandData("view", "view audit log channel")) + .addSubcommands(new SubcommandData("remove", "unset audit log channel")); + + CommandData messageLog = Commands + .slash("messagelog", "manage message log options") + .setContexts(InteractionContextType.GUILD) + .setDefaultPermissions(DefaultMemberPermissions.DISABLED) + .addSubcommands(new SubcommandData("set", "set message log channel here")) + .addSubcommands(new SubcommandData("view", "view message log channel")) + .addSubcommands(new SubcommandData("remove", "unset message log channel")); + + CommandData serverStats = Commands + .slash("stats", "Provides Server Statistics") + .setContexts(InteractionContextType.GUILD) + .setDefaultPermissions(DefaultMemberPermissions.ENABLED); + + CommandData setup = Commands + .slash("setup", "Provides a guide on setting up the bot") + .setContexts(InteractionContextType.GUILD) + .setDefaultPermissions(DefaultMemberPermissions.ENABLED); + + CommandData debug = Commands + .slash("debug", "Provides debug info") + .setContexts(InteractionContextType.GUILD) + .setDefaultPermissions(DefaultMemberPermissions.ENABLED); + + jda.updateCommands() + .addCommands(auditLog, messageLog, serverStats, setup, debug) + .queue(); + } +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/main/ConnectionInitializer.java b/src/main/java/io/github/eggy03/papertrail/bot/main/ConnectionInitializer.java new file mode 100644 index 00000000..e9d7307d --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/main/ConnectionInitializer.java @@ -0,0 +1,63 @@ +package io.github.eggy03.papertrail.bot.main; + +import io.github.eggy03.papertrail.bot.commons.utils.EnvConfig; +import lombok.Getter; +import lombok.NonNull; +import net.dv8tion.jda.api.OnlineStatus; +import net.dv8tion.jda.api.requests.GatewayIntent; +import net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder; +import net.dv8tion.jda.api.sharding.ShardManager; +import net.dv8tion.jda.api.utils.ChunkingFilter; +import net.dv8tion.jda.api.utils.MemberCachePolicy; +import net.dv8tion.jda.api.utils.cache.CacheFlag; + +/* + * This class initializes the connection to discord and configures all the necessary intents + */ +@Getter +public class ConnectionInitializer { + + // returns the manager that manages multiple shards (instances) of the bot + // Manages multiple shards (instances) of the bot + private final @NonNull ShardManager manager; + + public ConnectionInitializer() { + + String token = EnvConfig.get("TOKEN"); + + DefaultShardManagerBuilder builder = DefaultShardManagerBuilder.createDefault(token); + builder.enableIntents(GatewayIntent.SCHEDULED_EVENTS, + GatewayIntent.AUTO_MODERATION_EXECUTION, + GatewayIntent.AUTO_MODERATION_CONFIGURATION, + GatewayIntent.MESSAGE_CONTENT, + GatewayIntent.GUILD_MEMBERS, + GatewayIntent.GUILD_EXPRESSIONS, + GatewayIntent.GUILD_PRESENCES, + GatewayIntent.GUILD_MODERATION); + + builder.setStatus(OnlineStatus.ONLINE); + + //cache all users of the bot + builder.setMemberCachePolicy(MemberCachePolicy.ALL); + builder.setChunkingFilter(ChunkingFilter.ALL); + //you will still need builder.enableCache() to cache user activities and status + builder.enableCache(CacheFlag.ACTIVITY, + CacheFlag.CLIENT_STATUS, + CacheFlag.EMOJI, + CacheFlag.STICKER, + CacheFlag.ONLINE_STATUS, + CacheFlag.MEMBER_OVERRIDES, + CacheFlag.ROLE_TAGS, + CacheFlag.SCHEDULED_EVENTS); + + int minShardId = Integer.parseInt(EnvConfig.get("MIN_SHARD_ID")); // min for this instance + int maxShardId = Integer.parseInt(EnvConfig.get("MAX_SHARD_ID")); // max for this instance + int totalShards = Integer.parseInt(EnvConfig.get("TOTAL_SHARDS")); + + manager = builder + .setShardsTotal(totalShards) + .setShards(minShardId, maxShardId) + .build(); + } + +} diff --git a/src/main/java/io/github/eggy03/papertrail/bot/main/Start.java b/src/main/java/io/github/eggy03/papertrail/bot/main/Start.java new file mode 100644 index 00000000..660fab2d --- /dev/null +++ b/src/main/java/io/github/eggy03/papertrail/bot/main/Start.java @@ -0,0 +1,74 @@ +package io.github.eggy03.papertrail.bot.main; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import io.github.eggy03.papertrail.bot.listeners.auditlog.event.AuditLogEventListener; +import io.github.eggy03.papertrail.bot.listeners.auditlog.setup.AuditLogSetupCommandListener; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.event.guild.GuildBoostEventListener; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.event.guild.GuildMemberJoinAndLeaveEventListener; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.event.guild.GuildPollEventListener; +import io.github.eggy03.papertrail.bot.listeners.auditlogsupl.event.guild.GuildVoiceEventListener; +import io.github.eggy03.papertrail.bot.listeners.messagelog.event.MessageLogListener; +import io.github.eggy03.papertrail.bot.listeners.messagelog.setup.MessageLogSetupCommandListener; +import io.github.eggy03.papertrail.bot.listeners.misc.ActivityUpdateListener; +import io.github.eggy03.papertrail.bot.listeners.misc.BotSetupInstructionCommandListener; +import io.github.eggy03.papertrail.bot.listeners.misc.DebugListener; +import io.github.eggy03.papertrail.bot.listeners.misc.SelfKickListener; +import io.github.eggy03.papertrail.bot.listeners.misc.ServerStatCommandListener; +import io.github.eggy03.papertrail.bot.listeners.misc.SlashCommandRegistrationListener; +import lombok.NonNull; +import net.dv8tion.jda.api.sharding.ShardManager; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +/* + * The main class of the bot + */ +public class Start { + + // All I/O blocking operations run inside the vThreadPool + private static final @NonNull Executor vThreadPool = Executors.newVirtualThreadPerTaskExecutor(); + + public static void main(String[] args) throws IOException { + + ConnectionInitializer ci = new ConnectionInitializer(); + ShardManager manager = ci.getManager(); + + manager.addEventListener(new AuditLogSetupCommandListener()); + manager.addEventListener(new AuditLogEventListener(vThreadPool)); + + manager.addEventListener(new MessageLogSetupCommandListener()); + manager.addEventListener(new MessageLogListener(vThreadPool)); + + manager.addEventListener(new GuildVoiceEventListener(vThreadPool)); + manager.addEventListener(new GuildMemberJoinAndLeaveEventListener(vThreadPool)); + manager.addEventListener(new GuildPollEventListener(vThreadPool)); + manager.addEventListener(new GuildBoostEventListener(vThreadPool)); + manager.addEventListener(new SelfKickListener(vThreadPool)); + + manager.addEventListener(new ServerStatCommandListener()); + manager.addEventListener(new BotSetupInstructionCommandListener()); + manager.addEventListener(new ActivityUpdateListener(manager)); + manager.addEventListener(new DebugListener()); + // re-enable it only when adding/updating/deleting commands + manager.addEventListener(new SlashCommandRegistrationListener()); + + // Custom health check endpoint + HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); + server.createContext("/ping", new PingHandler()); + server.setExecutor(null); // creates a default executor + server.start(); + } + + static class PingHandler implements HttpHandler { + @Override + public void handle(@NonNull HttpExchange exchange) throws IOException { + exchange.sendResponseHeaders(200, -1); + } + } + +} diff --git a/src/main/java/org/papertrail/commons/constant/ProjectInfo.java b/src/main/java/org/papertrail/commons/constant/ProjectInfo.java deleted file mode 100644 index 86a7addd..00000000 --- a/src/main/java/org/papertrail/commons/constant/ProjectInfo.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.papertrail.commons.constant; - -public class ProjectInfo { - - private ProjectInfo() { - throw new IllegalStateException("Utility Class"); - } - - public static final String APPNAME = "PaperTrail"; - public static final String VERSION = "v2.5.0"; - public static final String PROJECT_ISSUE_LINK="https://github.com/eggy03/PaperTrailBot/issues"; -} diff --git a/src/main/java/org/papertrail/commons/utilities/BooleanFormatter.java b/src/main/java/org/papertrail/commons/utilities/BooleanFormatter.java deleted file mode 100644 index a73c3fa0..00000000 --- a/src/main/java/org/papertrail/commons/utilities/BooleanFormatter.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.papertrail.commons.utilities; - -import lombok.experimental.UtilityClass; -import org.jetbrains.annotations.NotNull; - -@UtilityClass -public class BooleanFormatter { - - @NotNull - public static String formatToEmoji (Object value) { - if(value==null) - return "N/A"; - - if(Boolean.TRUE.equals(value)) - return "βœ…"; - - return "❌"; - } - - @NotNull - public static String formatToYesOrNo (Object value) { - if(value==null) - return "N/A"; - - if(Boolean.TRUE.equals(value)) - return "Yes"; - - return "No"; - } - - @NotNull - public static String formatToEnabledOrDisabled (Object value) { - if(value==null) - return "N/A"; - - if(Boolean.TRUE.equals(value)) - return "Enabled"; - - return "Disabled"; - } -} diff --git a/src/main/java/org/papertrail/commons/utilities/ColorFormatter.java b/src/main/java/org/papertrail/commons/utilities/ColorFormatter.java deleted file mode 100644 index 31c9b16b..00000000 --- a/src/main/java/org/papertrail/commons/utilities/ColorFormatter.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.papertrail.commons.utilities; - -import lombok.experimental.UtilityClass; - -import java.util.IllegalFormatException; -import java.util.Map; - -@UtilityClass -public class ColorFormatter { - - public static String formatToHex(Object colorValue) { - - if(String.valueOf(colorValue).equals("null")) { - return "N/A"; - } - - try { - int color = Integer.parseInt(String.valueOf(colorValue)); - return String.format("#%06X", color); - } catch (NumberFormatException e ) { - return "No Parsable Color Integer Detected"; - } catch (IllegalFormatException e) { - return "Cannot parse color to hex"; - } - } - - // gradient is returned as a hash map in the following structure - // {"primary_color" = 123456789, "secondary_color" = 123456789, "tertiary_color" = 123456789} - public static String formatGradientColorSystemToHex(Object gradientValue) { - - if(gradientValue instanceof Map colorMap){ - - String primaryColor = "Primary Color: "+ formatToHex(colorMap.get("primary_color")); - String secondaryColor = "Secondary Color: "+ formatToHex(colorMap.get("secondary_color")); - String tertiaryColor = "Tertiary Color: "+ formatToHex(colorMap.get("tertiary_color")); - - return primaryColor+System.lineSeparator()+secondaryColor+System.lineSeparator()+tertiaryColor; - } - - return "N/A"; - - } -} diff --git a/src/main/java/org/papertrail/commons/utilities/DurationFormatter.java b/src/main/java/org/papertrail/commons/utilities/DurationFormatter.java deleted file mode 100644 index 93266c4d..00000000 --- a/src/main/java/org/papertrail/commons/utilities/DurationFormatter.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.papertrail.commons.utilities; - -import lombok.experimental.UtilityClass; - -import java.time.Duration; -import java.time.OffsetDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; - -@UtilityClass -public class DurationFormatter { - - public static String formatSeconds(Object seconds) { - if (seconds == null) { - return "ERROR: Value Returned Null"; - } - - try { - long secondsLong = Long.parseLong(seconds.toString()); - if (secondsLong == 0L) return "No Limits"; - Duration d = Duration.ofSeconds(secondsLong); - long durationDays = d.toDays(); - long durationHours = d.toHoursPart(); - long durationMinutes = d.toMinutesPart(); - long durationSeconds = d.toSecondsPart(); - - StringBuilder sb = new StringBuilder(); - - if (durationDays > 0) - sb.append(durationDays).append("d "); - if (durationHours > 0) - sb.append(durationHours).append("h "); - if (durationMinutes > 0) - sb.append(durationMinutes).append("m "); - if(durationSeconds > 0) - sb.append(durationSeconds).append("s"); - - return sb.toString().trim(); - } catch (NumberFormatException e) { - return "Duration Cannot Be Parsed"; - } - - - } - - public static String formatMinutes(Object minutes) { - if (minutes == null) { - return "ERROR: Value Returned Null"; - } - try { - long minutesLong = Long.parseLong(minutes.toString()); - if (minutesLong == 0L) return "No Limits"; - Duration d = Duration.ofMinutes(minutesLong); - long days = d.toDays(); - long hours = d.toHoursPart(); - - StringBuilder sb = new StringBuilder(); - if (days > 0) sb.append(days).append("d "); - if (hours > 0) sb.append(hours).append("h "); - return sb.toString().trim(); - } catch (NumberFormatException e) { - return "Duration Cannot Be Parsed"; - } - - - } - - public static String isoToLocalTimeCounter(Object isoTime) { - String isoTimeString = String.valueOf(isoTime); - if(isoTimeString==null || isoTimeString.equals("null") || isoTimeString.isBlank()) { - return "N/A"; - } - - try { - OffsetDateTime odt = OffsetDateTime.parse(isoTimeString, DateTimeFormatter.ISO_OFFSET_DATE_TIME); - long unixTimestamp = odt.toEpochSecond(); - return ""; - } catch (DateTimeParseException e) { - return "Could Not Parse Date And Time"; - } - - } -} diff --git a/src/main/java/org/papertrail/commons/utilities/EnvConfig.java b/src/main/java/org/papertrail/commons/utilities/EnvConfig.java deleted file mode 100644 index 4a05f636..00000000 --- a/src/main/java/org/papertrail/commons/utilities/EnvConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.papertrail.commons.utilities; - -import io.github.cdimascio.dotenv.Dotenv; -import lombok.experimental.UtilityClass; - -@UtilityClass -public class EnvConfig { - - private static final Dotenv dotenv = Dotenv.configure().ignoreIfMalformed().ignoreIfMissing().load(); - - public static String get(String key) { - - String value = dotenv.get(key); - if (value != null) { - return value; - } - - return System.getenv(key); - } -} diff --git a/src/main/java/org/papertrail/commons/utilities/GuildScheduledEventRecurrenceRuleStructureParser.java b/src/main/java/org/papertrail/commons/utilities/GuildScheduledEventRecurrenceRuleStructureParser.java deleted file mode 100644 index 5192f0a9..00000000 --- a/src/main/java/org/papertrail/commons/utilities/GuildScheduledEventRecurrenceRuleStructureParser.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.papertrail.commons.utilities; - -import lombok.experimental.UtilityClass; - -import java.util.Map; - -/** - * Parser for: Recurrence Rule Structure - */ -@UtilityClass -public class GuildScheduledEventRecurrenceRuleStructureParser { - - public static String parse(Object recurrenceRuleStructure) { - - StringBuilder stringBuilder = new StringBuilder(); - if(recurrenceRuleStructure instanceof Map recurrenceRuleMap) { - - stringBuilder - .append("**_Start Time of Interval_**") - .append(System.lineSeparator()) - .append("β•°β”ˆβž€") - .append(String.valueOf(recurrenceRuleMap.get("start"))) - .append(System.lineSeparator()); - - stringBuilder - .append("**_End Time of Interval_**") - .append(System.lineSeparator()) - .append("β•°β”ˆβž€") - .append(String.valueOf(recurrenceRuleMap.get("end"))) - .append(System.lineSeparator()); - - stringBuilder - .append("**_Frequency of Interval_**") - .append(System.lineSeparator()) - .append("β•°β”ˆβž€") - .append(String.valueOf(recurrenceRuleMap.get("frequency"))) - .append(System.lineSeparator()); - - stringBuilder - .append("**_Spacing between events_**") - .append(System.lineSeparator()) - .append("β•°β”ˆβž€") - .append(String.valueOf(recurrenceRuleMap.get("interval"))) - .append(System.lineSeparator()); - - stringBuilder - .append("**_Weekday Recurrence_**") - .append(System.lineSeparator()) - .append("β•°β”ˆβž€") - .append(String.valueOf(recurrenceRuleMap.get("by_weekday"))) - .append(System.lineSeparator()); - - stringBuilder - .append("**_Specific days within a weekday to recur on_**") - .append(System.lineSeparator()) - .append("β•°β”ˆβž€") - .append(String.valueOf(recurrenceRuleMap.get("by_n_weekday"))) - .append(System.lineSeparator()); - - stringBuilder - .append("**_Monthly Recurrence_**") - .append(System.lineSeparator()) - .append("β•°β”ˆβž€") - .append(String.valueOf(recurrenceRuleMap.get("by_month"))) - .append(System.lineSeparator()); - - stringBuilder - .append("**_Specific days within a month to recur on_**") - .append(System.lineSeparator()) - .append("β•°β”ˆβž€") - .append(String.valueOf(recurrenceRuleMap.get("by_month_day"))) - .append(System.lineSeparator()); - - stringBuilder - .append("**_Set of days within a year to recur on_**") - .append(System.lineSeparator()) - .append("β•°β”ˆβž€") - .append(String.valueOf(recurrenceRuleMap.get("by_year_day"))) - .append(System.lineSeparator()); - - stringBuilder - .append("**_Event to be repeated_**") - .append(System.lineSeparator()) - .append("β•°β”ˆβž€") - .append(String.valueOf(recurrenceRuleMap.get("count"))); - - } - return stringBuilder.toString(); - } -} diff --git a/src/main/java/org/papertrail/commons/utilities/GuildSystemChannelFlagResolver.java b/src/main/java/org/papertrail/commons/utilities/GuildSystemChannelFlagResolver.java deleted file mode 100644 index 8dd7cefc..00000000 --- a/src/main/java/org/papertrail/commons/utilities/GuildSystemChannelFlagResolver.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.papertrail.commons.utilities; - -import lombok.experimental.UtilityClass; - -import java.util.Map; - -@UtilityClass -public class GuildSystemChannelFlagResolver { - - private static final Map SYSTEM_CHANNEL_FLAG_MAP = Map.ofEntries( - Map.entry(1L, "Suppress member join notifications"), - Map.entry(1L << 1, "Suppress server boost notifications"), - Map.entry(1L << 2, "Suppress server setup tips"), - Map.entry(1L << 3, "Hide member join sticker reply buttons"), - Map.entry(1L << 4, "Suppress role subscription purchase and renewal notifications"), - Map.entry(1L << 5, "Hide role subscription sticker reply buttons") - ); - - private static String parseFlags(long bitfield){ - StringBuilder flags = new StringBuilder(); - for(Map.Entry entry: SYSTEM_CHANNEL_FLAG_MAP.entrySet()) { - if((bitfield & entry.getKey()) != 0) { - flags.append("βœ…").append(entry.getValue()).append(System.lineSeparator()); - } - } - return flags.toString(); - } - - public static String getParsedFlags(Object flagValue) { - if(flagValue==null) { - return "ERROR: Value Returned Null"; - } - - try { - return parseFlags(Long.parseLong(flagValue.toString())); - } catch (NumberFormatException e) { - return "No Parsable Flag Values Detected"; - } - - } -} - diff --git a/src/main/java/org/papertrail/commons/utilities/MessageEncryption.java b/src/main/java/org/papertrail/commons/utilities/MessageEncryption.java deleted file mode 100644 index 7fe4f40b..00000000 --- a/src/main/java/org/papertrail/commons/utilities/MessageEncryption.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.papertrail.commons.utilities; - -import lombok.experimental.UtilityClass; -import lombok.extern.slf4j.Slf4j; -import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; - -@UtilityClass -@Slf4j -public class MessageEncryption { - - private static final String SECRET = EnvConfig.get("MESSAGE_SECRET"); - private static final String ALGORITHM = "PBEWITHSHA256AND256BITAES-CBC-BC"; - - private static StandardPBEStringEncryptor getEncryptor() { - StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); - encryptor.setPassword(SECRET); - encryptor.setAlgorithm(ALGORITHM); - encryptor.setKeyObtentionIterations(100_000); - return encryptor; - } - - private static boolean isSecretEmpty() { - return SECRET == null || SECRET.isBlank(); - } - - public static String encrypt(String plainText) { - if(isSecretEmpty()) { - log.error("MESSAGE_SECRET is empty! No message will be encrypted and a null will be returned instead"); - return null; - } - StandardPBEStringEncryptor enc = getEncryptor(); - return enc.encrypt(plainText); - } - - public static String decrypt(String encryptedText) { - if(isSecretEmpty()) { - log.error("MESSAGE_SECRET is empty! No message will be decrypted and a null will be returned instead"); - return null; - } - StandardPBEStringEncryptor enc = getEncryptor(); - return enc.decrypt(encryptedText); - } - -} diff --git a/src/main/java/org/papertrail/commons/utilities/OnboardingUtils.java b/src/main/java/org/papertrail/commons/utilities/OnboardingUtils.java deleted file mode 100644 index ad2cad96..00000000 --- a/src/main/java/org/papertrail/commons/utilities/OnboardingUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.papertrail.commons.utilities; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -@UtilityClass -public class OnboardingUtils { - - @NotNull - public static String formatMode(Object value) { - if(value==null) return "N/A"; - - return switch (String.valueOf(value)) { - case "1" -> "Advanced Mode"; - case "0" -> "Regular Mode"; - default -> "N/A"; - }; - } - - @NotNull - public static String formatStatus(Object value) { - if(value==null) - return "N/A"; - - if(Boolean.TRUE.equals(value)) - return "Enabled"; - - return "Disabled"; - } - - @NotNull - public static String resolveChannelsFromList(Guild guild, Object value) { - if(value == null) return "No Resolvable Channel IDs"; - - StringBuilder sb = new StringBuilder(); - if(value instanceof List channelIdList) { - channelIdList.forEach(channelId -> { - GuildChannel channel = guild.getGuildChannelById((String) channelId); - sb.append(channel!=null ? channel.getAsMention() : channelId).append(" "); - }); - } - - return sb.toString(); - } -} diff --git a/src/main/java/org/papertrail/commons/utilities/PermissionResolver.java b/src/main/java/org/papertrail/commons/utilities/PermissionResolver.java deleted file mode 100644 index 663591ff..00000000 --- a/src/main/java/org/papertrail/commons/utilities/PermissionResolver.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.papertrail.commons.utilities; - -import lombok.experimental.UtilityClass; - -import java.util.Map; - -/** - @see Discord Permissions - */ -@UtilityClass -public class PermissionResolver { - - private static final Map PERMISSION_MAP = Map.ofEntries( - Map.entry(1L, "CREATE_INSTANT_INVITE"), - Map.entry(1L << 1, "KICK_MEMBERS"), - Map.entry(1L << 2, "BAN_MEMBERS"), - Map.entry(1L << 3, "ADMINISTRATOR"), - Map.entry(1L << 4, "MANAGE_CHANNELS"), - Map.entry(1L << 5, "MANAGE_GUILD"), - Map.entry(1L << 6, "ADD_REACTIONS"), - Map.entry(1L << 7, "VIEW_AUDIT_LOG"), - Map.entry(1L << 8, "PRIORITY_SPEAKER"), - Map.entry(1L << 9, "STREAM"), - Map.entry(1L << 10, "VIEW_CHANNEL"), - Map.entry(1L << 11, "SEND_MESSAGES"), - Map.entry(1L << 12, "SEND_TTS_MESSAGES"), - Map.entry(1L << 13, "MANAGE_MESSAGES"), - Map.entry(1L << 14, "EMBED_LINKS"), - Map.entry(1L << 15, "ATTACH_FILES"), - Map.entry(1L << 16, "READ_MESSAGE_HISTORY"), - Map.entry(1L << 17, "MENTION_EVERYONE"), - Map.entry(1L << 18, "USE_EXTERNAL_EMOJIS"), - Map.entry(1L << 19, "VIEW_GUILD_INSIGHTS"), - Map.entry(1L << 20, "CONNECT"), - Map.entry(1L << 21, "SPEAK"), - Map.entry(1L << 22, "MUTE_MEMBERS"), - Map.entry(1L << 23, "DEAFEN_MEMBERS"), - Map.entry(1L << 24, "MOVE_MEMBERS"), - Map.entry(1L << 25, "USE_VAD"), - Map.entry(1L << 26, "CHANGE_NICKNAME"), - Map.entry(1L << 27, "MANAGE_NICKNAMES"), - Map.entry(1L << 28, "MANAGE_ROLES"), - Map.entry(1L << 29, "MANAGE_WEBHOOKS"), - Map.entry(1L << 30, "MANAGE_GUILD_EXPRESSIONS"), - Map.entry(1L << 31, "USE_APPLICATION_COMMANDS"), - Map.entry(1L << 32, "REQUEST_TO_SPEAK"), - Map.entry(1L << 33, "MANAGE_EVENTS"), - Map.entry(1L << 34, "MANAGE_THREADS"), - Map.entry(1L << 35, "CREATE_PUBLIC_THREADS"), - Map.entry(1L << 36, "CREATE_PRIVATE_THREADS"), - Map.entry(1L << 37, "USE_EXTERNAL_STICKERS"), - Map.entry(1L << 38, "SEND_MESSAGES_IN_THREADS"), - Map.entry(1L << 39, "USE_EMBEDDED_ACTIVITIES"), - Map.entry(1L << 40, "MODERATE_MEMBERS"), - Map.entry(1L << 41, "VIEW_CREATOR_MONETIZATION_ANALYTICS"), - Map.entry(1L << 42, "USE_SOUNDBOARD"), - Map.entry(1L << 43, "CREATE_GUILD_EXPRESSIONS"), - Map.entry(1L << 44, "CREATE_EVENTS"), - Map.entry(1L << 45, "USE_EXTERNAL_SOUNDS"), - Map.entry(1L << 46, "SEND_VOICE_MESSAGES"), - - Map.entry(1L << 49, "SEND_POLLS"), - Map.entry(1L << 50, "USE_EXTERNAL_APPS"), - Map.entry(1L << 51, "PIN_MESSAGES"), - Map.entry(1L << 52, "BYPASS_SLOWMODE") - ); - - private static String parsePermissions(long bitfield, String emoji){ - StringBuilder permissions = new StringBuilder(); - for(Map.Entry entry: PERMISSION_MAP.entrySet()) { - if((bitfield & entry.getKey()) != 0) { - permissions.append(emoji).append(entry.getValue()).append(System.lineSeparator()); - } - } - return permissions.toString(); - } - - public static String getParsedPermissions(Object permissionValues, String emoji) { // this emoji is ❌ for denied permissions and βœ… for allowed - if(permissionValues==null) { - return "ERROR: Value Returned Null"; - } - - try { - return parsePermissions(Long.parseLong(permissionValues.toString()), emoji); - } catch (NumberFormatException e) { - return "No Parsable Permissions Detected"; - } - } -} diff --git a/src/main/java/org/papertrail/commons/utilities/RoleObjectParser.java b/src/main/java/org/papertrail/commons/utilities/RoleObjectParser.java deleted file mode 100644 index 91d132ee..00000000 --- a/src/main/java/org/papertrail/commons/utilities/RoleObjectParser.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.papertrail.commons.utilities; - -import lombok.experimental.UtilityClass; -import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.events.guild.GenericGuildEvent; - -import java.util.List; -import java.util.Map; - -@UtilityClass -@Slf4j -public class RoleObjectParser { - - // Parses an array list of map of role objects supplied by JDA - // roles are exposed as arraylists of maps [{name=role, id=1}, {name=role2, id=2}] - public static String parseRole(GenericGuildEvent event, Object roleObject) { - - if (roleObject instanceof List roleList) { - StringBuilder roleString = new StringBuilder(); - for (Object o : roleList) { - if (o instanceof Map roleMap && roleMap.containsKey("id")) { - String roleId = (String) roleMap.get("id"); - Role role = event.getGuild().getRoleById(roleId); - roleString.append(role!=null ? role.getAsMention() : roleMap.get("name")).append(" "); - } - } - return roleString.toString(); - } - - return "N/A"; - } -} diff --git a/src/main/java/org/papertrail/commons/utilities/TypeResolver.java b/src/main/java/org/papertrail/commons/utilities/TypeResolver.java deleted file mode 100644 index 0c371a1f..00000000 --- a/src/main/java/org/papertrail/commons/utilities/TypeResolver.java +++ /dev/null @@ -1,231 +0,0 @@ -package org.papertrail.commons.utilities; - -import lombok.experimental.UtilityClass; - -/* - * Resolves Object subtypes from their given IDs - * @see Discord Channel Types - */ -@UtilityClass -public class TypeResolver { - - public static String channelTypeResolver(Object channelTypeId) { - if (channelTypeId == null) { - return "ERROR: Value Returned Null"; - } - - try { - int channelType = Integer.parseInt(channelTypeId.toString()); - return switch (channelType) { - case 0 -> "Text"; - case 1 -> "DM"; - case 2 -> "Voice"; - case 3 -> "Group DM"; - case 4 -> "Category"; - case 5 -> "Announcement"; - case 10 -> "Announcement Thread"; - case 11 -> "Public Thread"; - case 12 -> "Private Thread"; - case 13 -> "Stage Voice"; - case 14 -> "Stage Directory"; - case 15 -> "Forum"; - case 16 -> "Media"; - default -> "Undocumented Type: " + channelTypeId; - }; - } catch (NumberFormatException e) { - return "Channel Type Is Not Parsable"; - } - - } - - public static String formatNumberOrUnlimited(Object limitNumber) { - if (limitNumber == null) { - return "ERROR: Value Returned Null"; - } - - try { - int limitNumberInt = Integer.parseInt(limitNumber.toString()); - if (limitNumberInt == 0) { - return "Unlimited"; - } else { - return String.valueOf(limitNumberInt); - } - } catch (NumberFormatException e) { - return "Type Cannot Be Parsed"; - } - - } - - public static String videoQualityModeResolver(Object qualityValue) { - if (qualityValue == null) { - return "ERROR: Value Returned Null"; - } - - try { - int qualityValueInt = Integer.parseInt(qualityValue.toString()); - return switch (qualityValueInt) { - case 1 -> "Auto"; - case 2 -> "720p/full"; - default -> String.valueOf(qualityValueInt); - }; - } catch (NumberFormatException e) { - return "Type Cannot Be Parsed"; - } - - } - - public static String voiceChannelBitrateResolver(Object bitrate) { - if (bitrate == null) { - return "ERROR: Value Returned Null"; - } - - try { - int bitrateInt = Integer.parseInt(bitrate.toString()); - if (bitrateInt <= 0) { - return "Unknown"; - } - - int kbps = bitrateInt / 1000; - return kbps + " kbps"; - } catch (NumberFormatException e) { - return "Type Cannot Be Parsed"; - } - - } - - public static String channelOverrideTypeResolver(Object type) { - if (type == null) { - return "ERROR: Value Returned Null"; - } - - try { - int typeInt = Integer.parseInt(type.toString()); - return switch (typeInt) { - case 0 -> "Role"; - case 1 -> "Member/Application"; - default -> "Unknown"; - }; - } catch (NumberFormatException e) { - return "Type Cannot Be Parsed"; - } - - } - - public static String automodEventTypeResolver(Object type) { - if (type == null) { - return "ERROR: Value Returned Null"; - } - - try { - int typeInt = Integer.parseInt(type.toString()); - return switch (typeInt) { - case 1 -> "Message Send"; - case 2 -> "Message Update"; - default -> "Unknown"; - }; - } catch (NumberFormatException e) { - return "Type Cannot Be Parsed"; - } - - } - - public static String automodTriggerTypeResolver(Object type) { - if (type == null) { - return "ERROR: Value Returned Null"; - } - - try { - int typeInt = Integer.parseInt(type.toString()); - return switch (typeInt) { - case 1 -> "Keyword"; - case 3 -> "Spam"; - case 4 -> "Keyword Preset"; - case 5 -> "Mention Spam"; - case 6 -> "Member Profile"; - default -> "Unknown"; - }; - } catch (NumberFormatException e) { - return "Type Cannot Be Parsed"; - } - - } - - public static String guildVerificationLevelResolver(Object type) { - if (type == null) { - return "ERROR: Value Returned Null"; - } - - try { - int t = Integer.parseInt(type.toString()); - return switch (t) { - case 0 -> "NONE"; - case 1 -> "LOW (Verified Email)"; - case 2 -> "MEDIUM (Registered on Discord for more than 5 minutes"; - case 3 -> "HIGH (Must be a member of the server for longer than 10 minutes)"; - case 4 -> "VERY_HIGH (Must have a verified phone number)"; - default -> "Unknown"; - }; - } catch (NumberFormatException e) { - return "No Parsable Type Values Detected"; - } - - } - - public static String explicitFilterTypeResolver(Object type) { - if (type == null) { - return "ERROR: Value Returned Null"; - } - - try { - int t = Integer.parseInt(type.toString()); - return switch (t) { - case 0 -> "No Filter"; - case 1 -> "Filter Messages From Server Members Without Roles"; - case 2 -> "Filter Messages From All Members"; - default -> "Unknown"; - }; - } catch (NumberFormatException e) { - return "No Parsable Type Values Detected"; - } - - } - - public static String scheduleEventTypeResolver(Object type) { - if (type == null) { - return "ERROR: Value Returned Null"; - } - - try { - int t = Integer.parseInt(type.toString()); - return switch (t) { - case 1 -> "Stage Event"; - case 2 -> "Voice Event"; - case 3 -> "Text Event"; - default -> "Unknown"; - }; - } catch (NumberFormatException e) { - return "No Parsable Type Values Detected"; - } - - } - - public static String scheduleEventStatusTypeResolver(Object type) { - if (type == null) { - return "ERROR: Value Returned Null"; - } - - try { - int t = Integer.parseInt(type.toString()); - return switch (t) { - case 1 -> "Scheduled"; - case 2 -> "Active"; - case 3 -> "Completed"; - case 4 -> "Cancelled"; - default -> "Unknown"; - }; - } catch (NumberFormatException e) { - return "No Parsable Type Values Detected"; - } - - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/event/AuditLogEventListener.java b/src/main/java/org/papertrail/listeners/audit/event/AuditLogEventListener.java deleted file mode 100644 index cb1f8577..00000000 --- a/src/main/java/org/papertrail/listeners/audit/event/AuditLogEventListener.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.papertrail.listeners.audit.event; - -import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; -import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; -import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.audit.ActionType; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.jetbrains.annotations.NotNull; -import org.papertrail.commons.utilities.EnvConfig; -import org.papertrail.listeners.audit.helper.AutoModerationFlagToChannelEventHelper; -import org.papertrail.listeners.audit.helper.AutoModerationMemberTimeoutEventHelper; -import org.papertrail.listeners.audit.helper.AutoModerationRuleBlockMessageEventHelper; -import org.papertrail.listeners.audit.helper.AutoModerationRuleCreateEventHelper; -import org.papertrail.listeners.audit.helper.AutoModerationRuleDeleteEventHelper; -import org.papertrail.listeners.audit.helper.AutoModerationRuleUpdateEventHelper; -import org.papertrail.listeners.audit.helper.BanEventHelper; -import org.papertrail.listeners.audit.helper.BotAddEventHelper; -import org.papertrail.listeners.audit.helper.ChannelCreateEventHelper; -import org.papertrail.listeners.audit.helper.ChannelDeleteEventHelper; -import org.papertrail.listeners.audit.helper.ChannelOverrideCreateEventHelper; -import org.papertrail.listeners.audit.helper.ChannelOverrideDeleteEventHelper; -import org.papertrail.listeners.audit.helper.ChannelOverrideUpdateEventHelper; -import org.papertrail.listeners.audit.helper.ChannelUpdateEventHelper; -import org.papertrail.listeners.audit.helper.EmojiCreateEventHelper; -import org.papertrail.listeners.audit.helper.EmojiDeleteEventHelper; -import org.papertrail.listeners.audit.helper.EmojiUpdateEventHelper; -import org.papertrail.listeners.audit.helper.GenericAuditLogEventHelper; -import org.papertrail.listeners.audit.helper.GuildUpdateEventHelper; -import org.papertrail.listeners.audit.helper.IntegrationCreateEventHelper; -import org.papertrail.listeners.audit.helper.IntegrationDeleteEventHelper; -import org.papertrail.listeners.audit.helper.InviteCreateEventHelper; -import org.papertrail.listeners.audit.helper.InviteDeleteEventHelper; -import org.papertrail.listeners.audit.helper.KickEventHelper; -import org.papertrail.listeners.audit.helper.MemberRoleUpdateEventHelper; -import org.papertrail.listeners.audit.helper.MemberUpdateEventHelper; -import org.papertrail.listeners.audit.helper.MemberVoiceKickEventHelper; -import org.papertrail.listeners.audit.helper.MemberVoiceMoveEventHelper; -import org.papertrail.listeners.audit.helper.MessagePinEventHelper; -import org.papertrail.listeners.audit.helper.MessageUnpinEventHelper; -import org.papertrail.listeners.audit.helper.OnboardingPromptCreateEventHelper; -import org.papertrail.listeners.audit.helper.OnboardingPromptDeleteEventHelper; -import org.papertrail.listeners.audit.helper.OnboardingPromptUpdateEventHelper; -import org.papertrail.listeners.audit.helper.OnboardingUpdateEventHelper; -import org.papertrail.listeners.audit.helper.RoleCreateEventHelper; -import org.papertrail.listeners.audit.helper.RoleDeleteEventHelper; -import org.papertrail.listeners.audit.helper.RoleUpdateEventHelper; -import org.papertrail.listeners.audit.helper.ScheduledEventCreateEventHelper; -import org.papertrail.listeners.audit.helper.ScheduledEventDeleteEventHelper; -import org.papertrail.listeners.audit.helper.ScheduledEventUpdateEventHelper; -import org.papertrail.listeners.audit.helper.SoundboardSoundCreateEventHelper; -import org.papertrail.listeners.audit.helper.SoundboardSoundDeleteEventHelper; -import org.papertrail.listeners.audit.helper.SoundboardSoundUpdateEventHelper; -import org.papertrail.listeners.audit.helper.StageInstanceCreateEventHelper; -import org.papertrail.listeners.audit.helper.StageInstanceDeleteEventHelper; -import org.papertrail.listeners.audit.helper.StageInstanceUpdateEventHelper; -import org.papertrail.listeners.audit.helper.StickerCreateEventHelper; -import org.papertrail.listeners.audit.helper.StickerDeleteEventHelper; -import org.papertrail.listeners.audit.helper.StickerUpdateEventHelper; -import org.papertrail.listeners.audit.helper.ThreadCreateEventHelper; -import org.papertrail.listeners.audit.helper.ThreadDeleteEventHelper; -import org.papertrail.listeners.audit.helper.ThreadUpdateEventHelper; -import org.papertrail.listeners.audit.helper.UnbanEventHelper; -import org.papertrail.listeners.audit.helper.VoiceChannelStatusDeleteEventHelper; -import org.papertrail.listeners.audit.helper.VoiceChannelStatusUpdateEventHelper; -import org.papertrail.listeners.audit.helper.WebhookCreateEventHelper; -import org.papertrail.listeners.audit.helper.WebhookRemoveEventHelper; -import org.papertrail.listeners.audit.helper.WebhookUpdateEventHelper; - -import java.util.Optional; -import java.util.concurrent.Executor; - -@Slf4j -public class AuditLogEventListener extends ListenerAdapter { - - private final Executor vThreadPool; - private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); - - public AuditLogEventListener(Executor vThreadPool) { - this.vThreadPool = vThreadPool; - } - - @Override - public void onGuildAuditLogEntryCreate(@NotNull GuildAuditLogEntryCreateEvent event) { - vThreadPool.execute(() -> { - // Call the API and see if the event came from a registered Guild - Optional response = client.getRegisteredGuild(event.getGuild().getId()); - response.ifPresent(success -> auditLogParser(event, success.getChannelId())); - }); - } - - private void auditLogParser(GuildAuditLogEntryCreateEvent event, String channelIdToSendTo) { - AuditLogEntry ale = event.getEntry(); - ActionType action = ale.getType(); - switch (action) { - - case AUTO_MODERATION_FLAG_TO_CHANNEL -> AutoModerationFlagToChannelEventHelper.format(event, ale, channelIdToSendTo); - case AUTO_MODERATION_MEMBER_TIMEOUT -> AutoModerationMemberTimeoutEventHelper.format(event, ale, channelIdToSendTo); - case AUTO_MODERATION_RULE_BLOCK_MESSAGE -> AutoModerationRuleBlockMessageEventHelper.format(event, ale, channelIdToSendTo); - case AUTO_MODERATION_RULE_CREATE -> AutoModerationRuleCreateEventHelper.format(event, ale, channelIdToSendTo); - case AUTO_MODERATION_RULE_UPDATE -> AutoModerationRuleUpdateEventHelper.format(event, ale, channelIdToSendTo); - case AUTO_MODERATION_RULE_DELETE -> AutoModerationRuleDeleteEventHelper.format(event, ale, channelIdToSendTo); - - case KICK -> KickEventHelper.format(event, ale, channelIdToSendTo); - case BAN -> BanEventHelper.format(event, ale, channelIdToSendTo); - case UNBAN -> UnbanEventHelper.format(event, ale, channelIdToSendTo); - case BOT_ADD -> BotAddEventHelper.format(event, ale, channelIdToSendTo); - // PRUNE has generic formatting - - case CHANNEL_CREATE -> ChannelCreateEventHelper.format(event, ale, channelIdToSendTo); - case CHANNEL_UPDATE -> ChannelUpdateEventHelper.format(event, ale, channelIdToSendTo); - case CHANNEL_DELETE -> ChannelDeleteEventHelper.format(event, ale, channelIdToSendTo); - case CHANNEL_OVERRIDE_CREATE -> ChannelOverrideCreateEventHelper.format(event, ale, channelIdToSendTo); - case CHANNEL_OVERRIDE_UPDATE -> ChannelOverrideUpdateEventHelper.format(event, ale, channelIdToSendTo); - case CHANNEL_OVERRIDE_DELETE -> ChannelOverrideDeleteEventHelper.format(event, ale, channelIdToSendTo); - - case ROLE_CREATE -> RoleCreateEventHelper.format(event, ale, channelIdToSendTo); - case ROLE_UPDATE -> RoleUpdateEventHelper.format(event, ale, channelIdToSendTo); - case ROLE_DELETE -> RoleDeleteEventHelper.format(event, ale, channelIdToSendTo); - - case EMOJI_CREATE -> EmojiCreateEventHelper.format(event, ale, channelIdToSendTo); - case EMOJI_UPDATE -> EmojiUpdateEventHelper.format(event, ale, channelIdToSendTo); - case EMOJI_DELETE -> EmojiDeleteEventHelper.format(event, ale, channelIdToSendTo); - - case STICKER_CREATE -> StickerCreateEventHelper.format(event, ale, channelIdToSendTo); - case STICKER_UPDATE -> StickerUpdateEventHelper.format(event, ale, channelIdToSendTo); - case STICKER_DELETE -> StickerDeleteEventHelper.format(event, ale, channelIdToSendTo); - - case GUILD_UPDATE -> GuildUpdateEventHelper.format(event, ale, channelIdToSendTo); - - case INTEGRATION_CREATE -> IntegrationCreateEventHelper.format(event, ale, channelIdToSendTo); - case INTEGRATION_DELETE -> IntegrationDeleteEventHelper.format(event, ale, channelIdToSendTo); - // INTEGRATION_UPDATE has generic formatting - - case INVITE_CREATE -> InviteCreateEventHelper.format(event, ale, channelIdToSendTo); - case INVITE_DELETE -> InviteDeleteEventHelper.format(event, ale, channelIdToSendTo); - // INVITE_UPDATE has generic formatting - - case MEMBER_ROLE_UPDATE -> MemberRoleUpdateEventHelper.format(event, ale, channelIdToSendTo); - case MEMBER_UPDATE -> MemberUpdateEventHelper.format(event, ale, channelIdToSendTo); - - case MEMBER_VOICE_KICK -> MemberVoiceKickEventHelper.format(event, ale, channelIdToSendTo); - case MEMBER_VOICE_MOVE -> MemberVoiceMoveEventHelper.format(event, ale, channelIdToSendTo); - - case MESSAGE_PIN -> MessagePinEventHelper.format(event, ale, channelIdToSendTo); - case MESSAGE_UNPIN -> MessageUnpinEventHelper.format(event, ale, channelIdToSendTo); - - case SCHEDULED_EVENT_CREATE -> ScheduledEventCreateEventHelper.format(event, ale, channelIdToSendTo); - case SCHEDULED_EVENT_UPDATE -> ScheduledEventUpdateEventHelper.format(event, ale, channelIdToSendTo); - case SCHEDULED_EVENT_DELETE -> ScheduledEventDeleteEventHelper.format(event, ale, channelIdToSendTo); - - case STAGE_INSTANCE_CREATE -> StageInstanceCreateEventHelper.format(event, ale, channelIdToSendTo); - case STAGE_INSTANCE_UPDATE -> StageInstanceUpdateEventHelper.format(event, ale, channelIdToSendTo); - case STAGE_INSTANCE_DELETE -> StageInstanceDeleteEventHelper.format(event, ale, channelIdToSendTo); - - case THREAD_CREATE -> ThreadCreateEventHelper.format(event, ale, channelIdToSendTo); - case THREAD_UPDATE -> ThreadUpdateEventHelper.format(event, ale, channelIdToSendTo); - case THREAD_DELETE -> ThreadDeleteEventHelper.format(event, ale, channelIdToSendTo); - - case VOICE_CHANNEL_STATUS_DELETE -> VoiceChannelStatusDeleteEventHelper.format(event, ale, channelIdToSendTo); - case VOICE_CHANNEL_STATUS_UPDATE -> VoiceChannelStatusUpdateEventHelper.format(event, ale, channelIdToSendTo); - - case WEBHOOK_CREATE -> WebhookCreateEventHelper.format(event, ale, channelIdToSendTo); - case WEBHOOK_UPDATE -> WebhookUpdateEventHelper.format(event, ale, channelIdToSendTo); - case WEBHOOK_REMOVE -> WebhookRemoveEventHelper.format(event, ale, channelIdToSendTo); - - case SOUNDBOARD_SOUND_CREATE -> SoundboardSoundCreateEventHelper.format(event, ale, channelIdToSendTo); - case SOUNDBOARD_SOUND_UPDATE -> SoundboardSoundUpdateEventHelper.format(event, ale, channelIdToSendTo); - case SOUNDBOARD_SOUND_DELETE -> SoundboardSoundDeleteEventHelper.format(event, ale, channelIdToSendTo); - - case ONBOARDING_UPDATE -> OnboardingUpdateEventHelper.format(event, channelIdToSendTo); - case ONBOARDING_PROMPT_CREATE -> OnboardingPromptCreateEventHelper.format(event, channelIdToSendTo); - case ONBOARDING_PROMPT_UPDATE -> OnboardingPromptUpdateEventHelper.format(event, channelIdToSendTo); - case ONBOARDING_PROMPT_DELETE -> OnboardingPromptDeleteEventHelper.format(event, channelIdToSendTo); - - case HOME_SETTINGS_CREATE, HOME_SETTINGS_UPDATE -> { - // might come back later and implement it - // but for now, don't send these events - } - - // these seemingly don't trigger properly, or are unreliable - case MESSAGE_BULK_DELETE, - MESSAGE_CREATE, - MESSAGE_DELETE, - MESSAGE_UPDATE -> GenericAuditLogEventHelper.format(event, ale, channelIdToSendTo); - - // except UNKNOWN, the rest have never been seen to be triggered - case APPLICATION_COMMAND_PRIVILEGES_UPDATE, PRUNE, INTEGRATION_UPDATE, - INVITE_UPDATE, ONBOARDING_CREATE, - UNKNOWN -> GenericAuditLogEventHelper.format(event, ale, channelIdToSendTo); - - default -> { - GenericAuditLogEventHelper.format(event, ale, channelIdToSendTo); - log.warn("The following event is either not covered by JDA's UNKNOWN type or is not implemented by me yet {}", ale.getType().name()); - } - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/event/GuildBoostEventListener.java b/src/main/java/org/papertrail/listeners/audit/event/GuildBoostEventListener.java deleted file mode 100644 index a07ca290..00000000 --- a/src/main/java/org/papertrail/listeners/audit/event/GuildBoostEventListener.java +++ /dev/null @@ -1,158 +0,0 @@ -package org.papertrail.listeners.audit.event; - -import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; -import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; -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.MessageEmbed; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateBoostTimeEvent; -import net.dv8tion.jda.api.events.guild.update.GuildUpdateBoostCountEvent; -import net.dv8tion.jda.api.events.guild.update.GuildUpdateBoostTierEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.jspecify.annotations.NonNull; -import org.papertrail.commons.utilities.EnvConfig; - -import java.awt.Color; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.util.Optional; -import java.util.concurrent.Executor; - -// Experimental -public class GuildBoostEventListener extends ListenerAdapter { - - private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); - private final Executor vThreadPool; - - public GuildBoostEventListener(Executor vThreadPool) { - this.vThreadPool = vThreadPool; - } - - @Override - public void onGuildUpdateBoostTier(@NonNull GuildUpdateBoostTierEvent event) { - - vThreadPool.execute(() -> { - Optional response = client.getRegisteredGuild(event.getGuild().getId()); - response.ifPresent(auditLogObject -> { - - String registeredChannelId = auditLogObject.getChannelId(); - - Guild guild = event.getGuild(); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Server Boost Tier Update"); - eb.setDescription(guild.getName() + " has had it's boost tier updated"); - - eb.setThumbnail(guild.getIconUrl()); - eb.setImage(guild.getBannerUrl()); - eb.setColor(Color.YELLOW); - - Guild.BoostTier oldBoostTier = event.getOldBoostTier(); - Guild.BoostTier newBoostTier = event.getNewBoostTier(); - - String oldTier = "**Tier:** " + oldBoostTier.name() + "\n" + - "**Max Emojis:** " + oldBoostTier.getMaxEmojis() + "\n" + - "**Max File Size:** " + oldBoostTier.getMaxFileSize() + "\n" + - "**Max Bitrate:** " + oldBoostTier.getMaxBitrate(); - - String newTier = "**Tier:** " + newBoostTier.name() + "\n" + - "**Max Emojis:** " + newBoostTier.getMaxEmojis() + "\n" + - "**Max File Size:** " + newBoostTier.getMaxFileSize() + "\n" + - "**Max Bitrate:** " + newBoostTier.getMaxBitrate(); - - eb.addField("Old Boost Tier Information", oldTier, false); - eb.addField("New Boost Tier Information", newTier, false); - - eb.setFooter(guild.getName()); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(registeredChannelId); - if (sendingChannel != null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - }); - }); - } - - @Override - public void onGuildUpdateBoostCount(@NonNull GuildUpdateBoostCountEvent event) { - - vThreadPool.execute(() -> { - Optional response = client.getRegisteredGuild(event.getGuild().getId()); - response.ifPresent(success -> { - String registeredChannelId = success.getChannelId(); - - Guild guild = event.getGuild(); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Server Boost Event"); - eb.setDescription("**" + guild.getName() + "** has had it's boost count updated!"); - - eb.setThumbnail(guild.getIconUrl()); - eb.setImage(guild.getBannerUrl()); - - eb.setColor(Color.YELLOW); - - eb.addField("Old Boost Count", "β•°β”ˆβž€" + event.getOldBoostCount(), false); - eb.addField("New Boost Count", "β•°β”ˆβž€" + event.getNewBoostCount(), false); - - eb.setFooter(guild.getName()); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(registeredChannelId); - if (sendingChannel != null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - }); - }); - } - - @Override - public void onGuildMemberUpdateBoostTime(@NonNull GuildMemberUpdateBoostTimeEvent event) { - - vThreadPool.execute(() -> { - Optional response = client.getRegisteredGuild(event.getGuild().getId()); - response.ifPresent(success -> { - String registeredChannelId = success.getChannelId(); - - Member member = event.getMember(); - Guild guild = event.getGuild(); - - String mentionableMember = member.getAsMention(); - - OffsetDateTime newBoostTime = event.getNewTimeBoosted(); // Will be null if the member stopped boosting - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Server Boost Event"); - eb.setThumbnail(guild.getIconUrl()); - eb.setImage(guild.getBannerUrl()); - - if (newBoostTime != null) { - eb.setDescription("**" + guild.getName() + "** has been boosted!"); - eb.setColor(Color.PINK); - eb.addField("Booster Gained", "β•°β”ˆβž€" + mentionableMember + " has applied their first boost to your server", false); - } else { - eb.setDescription("**" + guild.getName() + "** has lost a boost."); - eb.setColor(Color.GRAY); - eb.addField("Booster Lost", "β•°β”ˆβž€" + mentionableMember + " has removed their boost from your server", false); - } - - eb.setFooter(guild.getName()); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(registeredChannelId); - if (sendingChannel != null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - }); - }); - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/event/GuildMemberJoinAndLeaveEventListener.java b/src/main/java/org/papertrail/listeners/audit/event/GuildMemberJoinAndLeaveEventListener.java deleted file mode 100644 index 607c0469..00000000 --- a/src/main/java/org/papertrail/listeners/audit/event/GuildMemberJoinAndLeaveEventListener.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.papertrail.listeners.audit.event; - -import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; -import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; -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.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -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 org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.DurationFormatter; -import org.papertrail.commons.utilities.EnvConfig; - -import java.awt.Color; -import java.time.Instant; -import java.util.Optional; -import java.util.concurrent.Executor; - -// this event is not properly logged in the audit logs, hence the usage of JDA's listener is preferred -// this event is logged in the same channel where the audit log events are logged -public class GuildMemberJoinAndLeaveEventListener extends ListenerAdapter { - - private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); - private final Executor vThreadPool; - - public GuildMemberJoinAndLeaveEventListener(Executor vThreadPool) { - this.vThreadPool = vThreadPool; - } - - @Override - public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) { - - vThreadPool.execute(()->{ - // guild member join and leave events are mapped to audit log table - // Call the API and see if the event came from a registered Guild - Optional response = client.getRegisteredGuild(event.getGuild().getId()); - response.ifPresent(success -> { - - String registeredChannelId = success.getChannelId(); - - Guild guild = event.getGuild(); - User user = event.getUser(); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ›¬ Member Join Event"); - eb.setDescription("A Member has joined "+guild.getName()); - eb.setColor(Color.GREEN); - - eb.addField("🏷️ Member Name", "β•°β”ˆβž€"+user.getName(), false); - eb.setThumbnail(user.getEffectiveAvatarUrl()); - eb.addField("ℹ️ Member Mention", "β•°β”ˆβž€"+user.getAsMention(), false); - eb.addField("πŸ†” Member ID", "β•°β”ˆβž€"+user.getId(), false); - eb.addField("πŸ“… Account Created", "β•°β”ˆβž€"+DurationFormatter.isoToLocalTimeCounter(user.getTimeCreated()), false); - eb.addField("πŸ€– Bot Account", "β•°β”ˆβž€"+ BooleanFormatter.formatToYesOrNo(user.isBot()), false); - - eb.setFooter("Member Join Detection"); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(registeredChannelId); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - }); - }); - } - - @Override - public void onGuildMemberRemove(@NotNull GuildMemberRemoveEvent event) { - - vThreadPool.execute(() -> { - // Call the API and see if the event came from a registered Guild - Optional response = client.getRegisteredGuild(event.getGuild().getId()); - response.ifPresent(success -> { - - String registeredChannelId = success.getChannelId(); - - Guild guild = event.getGuild(); - User user = event.getUser(); - Member member = event.getMember(); - - String memberJoinDate = "Member Not Cached"; - boolean memberJoinDateTrustable = false; - if(member!=null){ - memberJoinDate = ""; - memberJoinDateTrustable = member.hasTimeJoined(); - } - String memberLeaveDate = ""; - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ›« Member Leave Event"); - eb.setDescription("A Member has left "+guild.getName()); - eb.setColor(Color.RED); - - eb.addField("🏷️ Member Name", "β•°β”ˆβž€"+user.getName(), false); - eb.setThumbnail(user.getEffectiveAvatarUrl()); - eb.addField("πŸ†” Member ID", "β•°β”ˆβž€"+user.getId(), false); - eb.addField("βŒ› Member Joined The Server On","β•°β”ˆβž€"+memberJoinDate, false); - eb.addField("βŒ› Member Left The Server On","β•°β”ˆβž€"+memberLeaveDate, false); - eb.addField("βŒ› Member Join Date Validity", memberJoinDateTrustable ? "β•°β”ˆβž€Valid" : "β•°β”ˆβž€Invalid" , false); - - eb.setFooter("If the member was loaded via lazy loading, join date will be identical to the guild creation date."); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(registeredChannelId); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - }); - - }); - } - -} diff --git a/src/main/java/org/papertrail/listeners/audit/event/GuildPollEventListener.java b/src/main/java/org/papertrail/listeners/audit/event/GuildPollEventListener.java deleted file mode 100644 index 59f99bfa..00000000 --- a/src/main/java/org/papertrail/listeners/audit/event/GuildPollEventListener.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.papertrail.listeners.audit.event; - -import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; -import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.messages.MessagePoll; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.jspecify.annotations.NonNull; -import org.papertrail.commons.utilities.EnvConfig; - -import java.awt.Color; -import java.time.Instant; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.Executor; - -public class GuildPollEventListener extends ListenerAdapter { - - private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); - private final Executor vThreadPool; - - public GuildPollEventListener(Executor vThreadPool) { - this.vThreadPool = vThreadPool; - } - - @Override - public void onMessageReceived(@NonNull MessageReceivedEvent event) { - - if(!event.isFromGuild()) - return; - - MessagePoll messagePoll = event.getMessage().getPoll(); - if(messagePoll==null) - return; - - vThreadPool.execute(()-> { - - // guild poll events are mapped to audit log table - // Call the API and see if the event came from a registered Guild - Optional response = client.getRegisteredGuild(event.getGuild().getId()); - response.ifPresent(success -> { - - String registeredChannelId = success.getChannelId(); - - StringBuilder answers = new StringBuilder(); - List answerList = messagePoll.getAnswers(); - answerList.forEach(answer -> answers - .append("*Answer: * ") - .append(answer.getText()) - .append(" *Emoji: * ") - .append(answer.getEmoji()==null ? "N/A" : answer.getEmoji().getFormatted()) - .append(System.lineSeparator()) - ); - - String expiryTime = messagePoll.getTimeExpiresAt()!=null ? - "" : - "N/A"; - - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("\uD83D\uDCCA Poll Creation Log"); - eb.setColor(Color.PINK); - eb.setDescription("A Poll has been created"); - eb.addField("Poll Creator", event.getAuthor().getAsMention(), false); - eb.addField("Question", messagePoll.getQuestion().getText(), false); - eb.addField("Answers", answers.toString(), false); - eb.addField("Poll Expiry Time", expiryTime, false); - eb.addField("Accepts Multiple Answers", messagePoll.isMultiAnswer() ? "Yes" : "No", false); - eb.addField("Channel", event.getChannel().getAsMention(), false); - - eb.setFooter("Poll Activity Detection"); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(registeredChannelId); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - - }); - }); - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/event/GuildVoiceEventListener.java b/src/main/java/org/papertrail/listeners/audit/event/GuildVoiceEventListener.java deleted file mode 100644 index 6b0f142d..00000000 --- a/src/main/java/org/papertrail/listeners/audit/event/GuildVoiceEventListener.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.papertrail.listeners.audit.event; - -import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; -import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel; -import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.jetbrains.annotations.NotNull; -import org.papertrail.commons.utilities.EnvConfig; - -import java.awt.Color; -import java.time.Instant; -import java.util.Optional; -import java.util.concurrent.Executor; - -// this event is not properly logged in the audit logs, hence the usage of JDA's listener is preferred -// this event is logged in the same channel where the audit log events are logged -public class GuildVoiceEventListener extends ListenerAdapter { - - private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); - private final Executor vThreadPool; - - public GuildVoiceEventListener(Executor vThreadPool) { - this.vThreadPool = vThreadPool; - } - - @Override - public void onGuildVoiceUpdate(@NotNull GuildVoiceUpdateEvent event) { - - vThreadPool.execute(()->{ - - // guild voice events are mapped to audit log table - // Call the API and see if the event came from a registered Guild - Optional response = client.getRegisteredGuild(event.getGuild().getId()); - response.ifPresent(success -> { - - String registeredChannelId = success.getChannelId(); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ”Š Voice Activity Log"); - - Member member = event.getMember(); - AudioChannel left = event.getOldValue(); // can be null if user joined for first time - AudioChannel joined = event.getNewValue(); // can be null if user left - - if(left==null && joined!=null) { - // User has joined a vc - eb.setDescription("A Member has joined a voice channel"); - eb.setColor(Color.GREEN); - eb.addField("βœ… Member Joined", "β•°β”ˆβž€"+member.getAsMention()+" joined the voice channel "+joined.getAsMention(), false); - } - - if (left != null && joined != null) { - // Moved from one channel to another - eb.setDescription("A Member has switched voice channels"); - eb.setColor(Color.YELLOW); - eb.addField("πŸ”„ Member Switched Channels", "β•°β”ˆβž€"+member.getAsMention()+" joined the switched from channel "+left.getAsMention()+ " to "+joined.getAsMention(), false); - } - - if (left!=null && joined==null) { - // User disconnected voluntarily (or was disconnected by a moderator) - eb.setDescription("A Member has left a voice channel"); - eb.setColor(Color.RED); - eb.addField("❌ Member Left A Voice Channel", "β•°β”ˆβž€"+member.getAsMention()+" left the voice channel "+left.getAsMention(), false); - } - - eb.setFooter("Voice Activity Detection"); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(registeredChannelId); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - }); - - }); - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleCreateEventHelper.java deleted file mode 100644 index 44eaff49..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleCreateEventHelper.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.List; -import java.util.Map; - -@UtilityClass -public class AutoModerationRuleCreateEventHelper { - - public static void format (GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | AutoMod Rule Create"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following AutoMod rule was created"); - eb.setColor(Color.GREEN); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "exempt_roles": - StringBuilder mentionableRoles = new StringBuilder(); - if(newValue instanceof List exemptRoleList) { - exemptRoleList.forEach(roleId -> { - Role r = ale.getGuild().getRoleById((String) roleId); - mentionableRoles.append(r!=null ? r.getAsMention() : roleId).append(", "); - }); - mentionableRoles.delete(mentionableRoles.length()-2, mentionableRoles.length()); - } - eb.addField("βœ”οΈ Exempt Roles: ", "β•°β”ˆβž€"+ mentionableRoles, false); - break; - - case "enabled": - eb.addField("❔ Enabled", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(newValue), false); - break; - - case "trigger_type": - eb.addField("⚑ Trigger Type", "β•°β”ˆβž€"+ TypeResolver.automodTriggerTypeResolver(newValue), false); - break; - - case "actions": - eb.addField("⚑ Actions", "β•°β”ˆβž€"+newValue, false); - break; - - case "exempt_channels": - StringBuilder mentionableChannels = new StringBuilder(); - if(newValue instanceof List exemptChannelList) { - exemptChannelList.forEach(channelId -> { - GuildChannel r = ale.getGuild().getGuildChannelById((String) channelId); - mentionableChannels.append(r!=null ? r.getAsMention() : channelId).append(", "); - }); - mentionableChannels.delete(mentionableChannels.length()-2, mentionableChannels.length()); - } - eb.addField("βœ”οΈ Exempt Channels: ", "β•°β”ˆβž€"+ mentionableChannels, false); - break; - - case "event_type": - eb.addField("🧭 Event Type", "β•°β”ˆβž€"+TypeResolver.automodEventTypeResolver(newValue), false); - break; - - case "trigger_metadata": - eb.addField("πŸ“Š Trigger Metadata", "β•°β”ˆβž€"+newValue, false); - break; - - case "name": - eb.addField("🏷️ AutoMod Rule Name ", "β•°β”ˆβž€"+newValue, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleDeleteEventHelper.java deleted file mode 100644 index 060a6cb8..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleDeleteEventHelper.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class AutoModerationRuleDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | AutoMod Rule Delete"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following AutoMod rule was deleted"); - eb.setColor(Color.RED); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "exempt_roles", "enabled", "trigger_type", "actions", "exempt_channels", "event_type", "trigger_metadata": - break; - - case "name": - eb.addField("🏷️ AutoMod Rule Name ", "β•°β”ˆβž€"+oldValue, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleUpdateEventHelper.java deleted file mode 100644 index c1799008..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/AutoModerationRuleUpdateEventHelper.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.automod.AutoModRule; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.List; -import java.util.Map; - -@UtilityClass -public class AutoModerationRuleUpdateEventHelper { - - public static void format (GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | AutoMod Rule Update"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following AutoMod rule was updated"); - eb.setColor(Color.YELLOW); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "exempt_roles": - StringBuilder mentionableRoles = new StringBuilder(); - if(newValue instanceof List exemptRoleList) { - exemptRoleList.forEach(roleId -> { - Role r = ale.getGuild().getRoleById((String) roleId); - mentionableRoles.append(r!=null ? r.getAsMention() : roleId).append(", "); - }); - mentionableRoles.delete(mentionableRoles.length()-2, mentionableRoles.length()); - } - eb.addField("βœ”οΈ New Exempt Roles: ", "β•°β”ˆβž€"+ mentionableRoles, false); - break; - - - case "actions": - eb.addField("⚑ New Actions", "β•°β”ˆβž€"+newValue, false); - break; - - case "exempt_channels": - StringBuilder mentionableChannels = new StringBuilder(); - if(newValue instanceof List exemptChannelList) { - exemptChannelList.forEach(channelId -> { - GuildChannel r = ale.getGuild().getGuildChannelById((String) channelId); - mentionableChannels.append(r!=null ? r.getAsMention() : channelId).append(", "); - }); - mentionableChannels.delete(mentionableChannels.length()-2, mentionableChannels.length()); - } - eb.addField("βœ”οΈ New Exempt Channels: ", "β•°β”ˆβž€"+ mentionableChannels, false); - break; - - - case "trigger_metadata": - eb.addField("πŸ“Š New Trigger Metadata", "β•°β”ˆβž€"+newValue, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - // add name of the rule which got updated - AutoModRule rule = ale.getGuild().retrieveAutoModRuleById(ale.getTargetId()).complete(); - eb.addField("🏷️ AutoMod Rule Name ", "β•°β”ˆβž€"+rule.getName(), false); - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/BanEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/BanEventHelper.java deleted file mode 100644 index c599029b..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/BanEventHelper.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; - -@UtilityClass -public class BanEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Ban Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: " + mentionableExecutor + "\nℹ️ The following user was banned"); - eb.setColor(Color.RED); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - String moderatorId = ale.getUserId(); - String targetId = ale.getTargetId(); - String reason = ale.getReason(); - - // FIXME -> see if there is a way to not invoke a rest action, possibly since all the members are cached already - event.getJDA().retrieveUserById(moderatorId).queue(moderator -> - event.getJDA().retrieveUserById(targetId).queue(target -> { - // if user objects are null we cannot use their mention so we instead use their IDs instead since they will never be null - eb.addField("🚫 A member has been banned", "β•°β”ˆβž€" + (moderator != null ? moderator.getAsMention() : moderatorId) + " has banned " + (target != null ? target.getAsMention() : targetId), false); - eb.addField("πŸ“ With Reason", "β•°β”ˆβž€" + (reason != null ? reason : "No Reason Provided"), false); - - eb.setFooter("Audit Log Entry ID: " + ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if (sendingChannel != null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - }) - ); - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ChannelCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ChannelCreateEventHelper.java deleted file mode 100644 index c8774ee5..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ChannelCreateEventHelper.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.DurationFormatter; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class ChannelCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Channel Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - GuildChannel targetChannel = ale.getGuild().getGuildChannelById(ale.getTargetId()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTargetChannel = (targetChannel !=null ? targetChannel.getAsMention() : ale.getTargetId()); - - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following channel was created"); - eb.setColor(Color.GREEN); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "user_limit": - eb.addField("πŸ‘₯ User Limit", "β•°β”ˆβž€"+ TypeResolver.formatNumberOrUnlimited(newValue), false); - break; - - case "rate_limit_per_user": - eb.addField("πŸ•“ Slowmode", "β•°β”ˆβž€"+ DurationFormatter.formatSeconds(newValue), false); - break; - - case "type": - eb.addField("πŸ—¨οΈ Channel Type", "β•°β”ˆβž€"+TypeResolver.channelTypeResolver(newValue), false); - break; - - case "nsfw": - eb.addField("πŸ”ž NSFW", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(newValue), false); - break; - - case "permission_overwrites", "flags": - break; - - case "name": - eb.addField("🏷️ Channel Name", "β•°β”ˆβž€"+newValue, false); - // provide a channel link next to its name. This mentionable channel can be obtained via the target ID of ALE - eb.addField("πŸ”— Channel Link", "β•°β”ˆβž€"+mentionableTargetChannel, true); - break; - - case "bitrate": - eb.addField("🎚️ Voice Channel Bitrate", "β•°β”ˆβž€"+TypeResolver.voiceChannelBitrateResolver(newValue), false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ChannelDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ChannelDeleteEventHelper.java deleted file mode 100644 index 4a02c712..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ChannelDeleteEventHelper.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class ChannelDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Channel Delete Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - GuildChannel targetChannel = ale.getJDA().getGuildChannelById(ale.getTargetIdLong()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTargetChannel = (targetChannel !=null ? targetChannel.getAsMention() : ale.getTargetId()); // this will return only the ID cause the channel with the ID has been deleted - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following channel was deleted"); - eb.setColor(Color.RED); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "name": - eb.addField("🏷️ Name", "β•°β”ˆβž€"+oldValue, false); - break; - - case "type": - eb.addField("πŸ—¨οΈ Type", "β•°β”ˆβž€"+ TypeResolver.channelTypeResolver(oldValue), false); - break; - - case "user_limit", "rate_limit_per_user", "nsfw", "permission_overwrites", "video_quality_mode", "flags", "bitrate", "rtc_region": - break; // they're null during channel delete events - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.addField("πŸ†” Deleted Channel ID", "β•°β”ˆβž€"+mentionableTargetChannel, false); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ChannelOverrideCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ChannelOverrideCreateEventHelper.java deleted file mode 100644 index 763432cf..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ChannelOverrideCreateEventHelper.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.PermissionResolver; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class ChannelOverrideCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Channel Override Create"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - GuildChannel targetChannel = event.getGuild().getGuildChannelById(ale.getTargetId()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTargetChannel = (targetChannel !=null ? targetChannel.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following channel overrides were created"); - eb.setColor(Color.GREEN); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "type": - eb.addField("🧩 Override Type", "β•°β”ˆβž€"+ TypeResolver.channelOverrideTypeResolver(newValue), false); - break; - - case "deny": - // the oldValue will return null if a new channel is over-riden for the first time but we're not concerned with oldValue - // the new value contains the list of denied permissions the moderator sets when creating overrides for the first time - eb.addField("Denied Permissions", PermissionResolver.getParsedPermissions(newValue, "❌"), false); - break; - - case "allow": - // the oldValue will return null if a new channel is over-riden for the first time but we're not concerned with oldValue - // the new value contains the list of allowed permissions the moderator sets when creating overrides for the first time - eb.addField("Allowed Permissions", PermissionResolver.getParsedPermissions(newValue, "βœ…"), false); - break; - - case "id": - // id exposes the member/role id which for which the channel permissions are over-riden - // only one member/role permissions can be over-riden at a time - Member mb = event.getGuild().getMemberById(String.valueOf(newValue)); - Role r = event.getGuild().getRoleById(String.valueOf(newValue)); - - String mentionableRoleOrMember = ""; - if(mb!=null) { - mentionableRoleOrMember = mb.getAsMention(); - } else if (r!=null) { - mentionableRoleOrMember = r.getAsMention(); - } - eb.addField("🎭 Target", "β•°β”ˆβž€"+mentionableRoleOrMember, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - // add the target channel whose permissions were overridden - // exposed via ALE's TargetID - eb.addField("πŸ—¨οΈ Target Channel", "β•°β”ˆβž€"+mentionableTargetChannel, false); - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ChannelOverrideDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ChannelOverrideDeleteEventHelper.java deleted file mode 100644 index a89c0014..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ChannelOverrideDeleteEventHelper.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.PermissionResolver; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class ChannelOverrideDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Channel Override Delete"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - GuildChannel targetChannel = event.getGuild().getGuildChannelById(ale.getTargetId()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTargetChannel = (targetChannel !=null ? targetChannel.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following channel overrides were deleted"); - eb.setColor(Color.RED); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "type": - eb.addField("🧩 Override Type", "β•°β”ˆβž€"+ TypeResolver.channelOverrideTypeResolver(oldValue), false); - break; - - case "deny": - // the newValue will return null if an over-ride is deleted but we're not concerned with newValue - // the oldValue returns the permissions the channel was previously denied - eb.addField("Previously Denied Permissions", PermissionResolver.getParsedPermissions(oldValue, "❌"), false); - break; - - case "allow": - // the newValue will return null if an over-ride is deleted but we're not concerned with newValue - // the oldValue returns the permissions the channel was previously allowed - eb.addField("Previously Allowed Permissions", PermissionResolver.getParsedPermissions(oldValue, "βœ…"), false); - break; - - case "id": - // id exposes the member/role id which for which the channel permissions are over-riden - Member mb = event.getGuild().getMemberById(String.valueOf(oldValue)); - Role r = event.getGuild().getRoleById(String.valueOf(oldValue)); - - String mentionableRoleOrMember = ""; - if(mb!=null) { - mentionableRoleOrMember = mb.getAsMention(); - } else if (r!=null) { - mentionableRoleOrMember = r.getAsMention(); - } - eb.addField("🎭 Deleted Target", "β•°β”ˆβž€"+mentionableRoleOrMember, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - // add the target channel whose permissions were over-riden - // can be retrieved via ALE's TargetID - eb.addField("πŸ—¨οΈ Target Channel", "β•°β”ˆβž€"+mentionableTargetChannel, false); - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ChannelOverrideUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ChannelOverrideUpdateEventHelper.java deleted file mode 100644 index 4089d7fd..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ChannelOverrideUpdateEventHelper.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.PermissionResolver; - -import java.awt.Color; -import java.util.Map; -import java.util.Objects; - -@UtilityClass -public class ChannelOverrideUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Channel Override Update"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - GuildChannel targetChannel = event.getGuild().getGuildChannelById(ale.getTargetId()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTargetChannel = (targetChannel !=null ? targetChannel.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following channel overrides were updated"); - eb.setColor(Color.YELLOW); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - // changes do not expose the id and type keys in case of override updates - String overriddenId = ale.getOptionByName("id"); - String overriddenType = ale.getOptionByName("type"); - - String mentionableOverrideTarget = overriddenId; - if ("0".equals(overriddenType)) { - // It’s a role - Role role = event.getGuild().getRoleById(Objects.requireNonNull(overriddenId)); - if (role != null) { - mentionableOverrideTarget = role.getAsMention(); - } - } else if ("1".equals(overriddenType)) { - // It’s a member - Member member = event.getGuild().getMemberById(Objects.requireNonNull(overriddenId)); - if (member != null) { - mentionableOverrideTarget = member.getAsMention(); - } - } - - eb.addField("🎭 Permissions Overridden For", "β•°β”ˆβž€"+mentionableOverrideTarget, false); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "deny": - String deniedPerms = PermissionResolver.getParsedPermissions(newValue, "❌"); - // if a channel is synchronized with it's category, the permission list will be blank and the StringBuilder will return a blank string - eb.addField("Denied Permissions", (deniedPerms.isBlank() ? "Permissions Synced With Category" : deniedPerms), false); - break; - - case "allow": - String allowedPerms = PermissionResolver.getParsedPermissions(newValue, "βœ…"); - // if a channel is synchronized with it's category, the permission list will be blank and the StringBuilder will return a blank string - eb.addField("Allowed Permissions", (allowedPerms.isBlank() ? "Permissions Synced With Category" : allowedPerms), false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - // add the target channel whose permissions were overridden - // can be retrieved via ALE's TargetID - eb.addField("πŸ—¨οΈ Target Channel", "β•°β”ˆβž€"+mentionableTargetChannel, false); - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ChannelUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ChannelUpdateEventHelper.java deleted file mode 100644 index c68c9874..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ChannelUpdateEventHelper.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.DurationFormatter; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class ChannelUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Channel Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - GuildChannel targetChannel = event.getGuild().getGuildChannelById(ale.getTargetId()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTargetChannel = (targetChannel !=null ? targetChannel.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following channel was updated"); - eb.setColor(Color.YELLOW); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.addBlankField(true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "user_limit": - eb.addField("πŸ‘₯ Old User Limit", "β•°β”ˆβž€"+ TypeResolver.formatNumberOrUnlimited(oldValue), true); - eb.addField("πŸ‘₯ New User Limit", "β•°β”ˆβž€"+TypeResolver.formatNumberOrUnlimited(newValue), true); - eb.addBlankField(true); - break; - - case "rate_limit_per_user": - eb.addField("πŸ•“ Old Slowmode Value", "β•°β”ˆβž€"+ DurationFormatter.formatSeconds(oldValue), true); - eb.addField("πŸ•“ New Slowmode Value", "β•°β”ˆβž€"+DurationFormatter.formatSeconds(newValue), true); - eb.addBlankField(true); - break; - - case "nsfw": - eb.addField("πŸ”ž Old NSFW Settings", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(oldValue), true); - eb.addField("πŸ”ž New NSFW Settings", "β•°β”ˆβž€"+BooleanFormatter.formatToEmoji(newValue), true); - eb.addBlankField(true); - break; - - case "video_quality_mode": - eb.addField("πŸŽ₯ Old Video Quality Mode", "β•°β”ˆβž€"+TypeResolver.videoQualityModeResolver(oldValue), true); - eb.addField("πŸŽ₯ New Video Quality Mode", "β•°β”ˆβž€"+TypeResolver.videoQualityModeResolver(newValue), true); - eb.addBlankField(true); - break; - - case "name": - eb.addField("🏷️ Old Channel Name", "β•°β”ˆβž€"+oldValue, true); - eb.addField("🏷️ New Channel Name", "β•°β”ˆβž€"+newValue, true); - eb.addBlankField(true); - break; - - case "bitrate": - eb.addField("🎚️ Old Voice Channel Bitrate", "β•°β”ˆβž€"+TypeResolver.voiceChannelBitrateResolver(oldValue), true); - eb.addField("🎚️ New Voice Channel Bitrate", "β•°β”ˆβž€"+TypeResolver.voiceChannelBitrateResolver(newValue), true); - eb.addBlankField(true); - break; - - case "rtc_region": - eb.addField("🌐 Old Region", "β•°β”ˆβž€"+oldValue, true); - eb.addField("🌐 New Region", "β•°β”ˆβž€"+newValue, true); - eb.addBlankField(true); - break; - - case "topic": - eb.addField("πŸ—’οΈ Old Topic", "β•°β”ˆβž€"+oldValue, true); - eb.addField("πŸ—’οΈ New topic", "β•°β”ˆβž€"+newValue, true); - eb.addBlankField(true); - break; - - case "default_auto_archive_duration": - eb.addField("πŸ•’ Old Hide After Inactivity Timer", "β•°β”ˆβž€"+DurationFormatter.formatMinutes(oldValue), true); - eb.addField("πŸ•’ New Hide After Inactivity Timer", "β•°β”ˆβž€"+DurationFormatter.formatMinutes(newValue), true); - eb.addBlankField(true); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - // mention the channel that got updated, id can be exposed via ALE's TargetID - eb.addField("πŸ’¬ Target Channel", "β•°β”ˆβž€"+mentionableTargetChannel, false); - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/EmojiCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/EmojiCreateEventHelper.java deleted file mode 100644 index fc33b8a2..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/EmojiCreateEventHelper.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class EmojiCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Emoji Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following emoji was created"); - eb.setColor(Color.GREEN); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "name": - eb.addField("🏷️ Emoji Name", "β•°β”ˆβž€"+newValue, false); - eb.addField("ℹ️ Emoji", "β•°β”ˆβž€"+"<:"+newValue+":"+ale.getTargetId()+">", false); // ale's TargetID retrieves the ID of the created emoji - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/EmojiDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/EmojiDeleteEventHelper.java deleted file mode 100644 index 45d538a3..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/EmojiDeleteEventHelper.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class EmojiDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Emoji Delete Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following emoji was deleted"); - eb.setColor(Color.RED); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "name": - eb.addField("♻️ Deleted Emoji", "β•°β”ˆβž€ "+":"+oldValue+":", false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.addField("♻️ Deleted Emoji ID", "β•°β”ˆβž€"+ale.getTargetId(), false); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/EmojiUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/EmojiUpdateEventHelper.java deleted file mode 100644 index e6683ee8..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/EmojiUpdateEventHelper.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class EmojiUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Emoji Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following emoji was updated"); - eb.setColor(Color.YELLOW); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "name": - eb.addField("🏷️ Emoji Name Updated", "β•°β”ˆβž€"+"From "+oldValue+" to "+newValue, false); - eb.addField("ℹ️ Target Emoji", "β•°β”ˆβž€"+"<:"+newValue+":"+ale.getTargetId()+">", false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/GenericAuditLogEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/GenericAuditLogEventHelper.java deleted file mode 100644 index b9f933d1..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/GenericAuditLogEventHelper.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -// for events not defined by JDA yet -@UtilityClass -public class GenericAuditLogEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Generic Event"); - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - - eb.setDescription((executor != null ? executor.getAsMention() : ale.getUserId())+" has executed the following action:"); - eb.setColor(Color.LIGHT_GRAY); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/GuildUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/GuildUpdateEventHelper.java deleted file mode 100644 index 360b6fdd..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/GuildUpdateEventHelper.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.GuildSystemChannelFlagResolver; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class GuildUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Guild Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following guild updates were recorded"); - eb.setColor(Color.MAGENTA); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "description": - eb.addField("Description Change", "from `"+oldValue+"` to `"+newValue+"`", false); - break; - - case "icon_hash": - eb.addField("Icon Hash Change", "from `"+oldValue+"` to `"+newValue+"`", false); - break; - - case "name": - eb.addField("Guild Name Change", "from `"+oldValue+"` to `"+newValue+"`", false); - break; - - case "afk_channel_id": - eb.addField("AFK Channel Changed To", "`"+newValue+"`", false); - break; - - case "default_message_notifications": - eb.addField("Default Message Notifications Update", "`"+newValue+"`", false); - break; - - case "afk_timeout": - eb.addField("AFK Channel Timeout Change", "`"+newValue+"s`", false); - break; - - case "system_channel_id": - eb.addField("Community Updates Channel Changed To", "`"+newValue+"`", false); - break; - - case "widget_enabled": - eb.addField("Widget Enabled", "`"+newValue+"`", false); - break; - - case "widget_channel_id": - eb.addField("Widget Channel Changed To", "`"+newValue+"`", false); - break; - - case "premium_progress_bar_enabled": - eb.addField("Server Boost Progress Bar Enabled", "`"+newValue+"`", false); - break; - - case "mfa_level": - eb.addField("MFA Requirement", "`"+newValue+"`", false); - break; - - case "verification_level": - eb.addField("Verification Level", "`"+ TypeResolver.guildVerificationLevelResolver(newValue)+"`", false); - break; - - case "owner_id": - User oldOwner = ale.getJDA().getUserById(String.valueOf(oldValue)); - User newOwner = ale.getJDA().getUserById(String.valueOf(newValue)); - String mentionableOldOwner = (oldOwner!=null ? oldOwner.getAsMention() : String.valueOf(oldValue)); - String mentionableNewOwner = (newOwner!=null ? newOwner.getAsMention() : String.valueOf(newValue)); - eb.addField("Ownership Change", "from "+mentionableOldOwner+" to "+mentionableNewOwner, false); - break; - - case "public_updates_channel_id": - eb.addField("Announcements Channel Changed To", "`"+newValue+"`", false); - break; - - case "rules_channel_id": - eb.addField("Rules Channel Changed To", "`"+newValue+"`", false); - break; - - - case "system_channel_flags": - eb.addField("System Channel Flags", GuildSystemChannelFlagResolver.getParsedFlags(newValue), false); - break; - - case "explicit_content_filter": - eb.addField("Explicit Content Filter", TypeResolver.explicitFilterTypeResolver(newValue), false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/IntegrationCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/IntegrationCreateEventHelper.java deleted file mode 100644 index 98e2123c..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/IntegrationCreateEventHelper.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class IntegrationCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Integration Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following integration was created"); - eb.setColor(Color.PINK); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "type": - eb.addField("Integration Type","β•°β”ˆβž€"+newValue, false); - break; - - case "name": - eb.addField("Integration Name", "β•°β”ˆβž€"+newValue, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/IntegrationDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/IntegrationDeleteEventHelper.java deleted file mode 100644 index 2f240e4b..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/IntegrationDeleteEventHelper.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class IntegrationDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Integration Delete Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following integration was deleted"); - eb.setColor(Color.RED); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "type": - eb.addField("βš™οΈ Integration Type", "β•°β”ˆβž€"+oldValue, false); - break; - - case "name": - eb.addField("🏷️ Integration Name", "β•°β”ˆβž€"+oldValue, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/InviteCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/InviteCreateEventHelper.java deleted file mode 100644 index 3cd4e8c1..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/InviteCreateEventHelper.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.DurationFormatter; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class InviteCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale , String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Invite Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following invite was created"); - eb.setColor(Color.CYAN); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "code": - eb.addField("πŸ”— Invite Code", "β•°β”ˆβž€"+newValue, false); - break; - - case "inviter_id": - User inviter = ale.getJDA().getUserById(String.valueOf(newValue)); - eb.addField("πŸ‘€ Invite Created By", "β•°β”ˆβž€"+(inviter != null ? inviter.getAsMention() : ale.getUserId()), false); - break; - - case "temporary": - eb.addField("πŸ•’ Temporary Invite", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(newValue), false); - break; - - case "max_uses": - int maxUses = Integer.parseInt(String.valueOf(newValue)); - eb.addField("πŸ”’ Max Uses", "β•°β”ˆβž€"+(maxUses == 0 ? "Unlimited" : String.valueOf(maxUses)), false); - break; - - case "uses", "flags": - break; - - case "max_age": - eb.addField("⏳ Expires After", "β•°β”ˆβž€"+ DurationFormatter.formatSeconds(newValue), false); - break; - - case "channel_id": - GuildChannel channel = ale.getGuild().getGuildChannelById(String.valueOf(newValue)); - eb.addField("πŸ’¬ Invite Channel", "β•°β”ˆβž€"+(channel != null ? channel.getAsMention() : "`"+newValue+"`"), false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/InviteDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/InviteDeleteEventHelper.java deleted file mode 100644 index e8f76ecc..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/InviteDeleteEventHelper.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.Channel; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class InviteDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Invite Delete Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following invite has been deleted"); - eb.setColor(Color.BLUE); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "code": - eb.addField("πŸ”— Deleted Invite Code", "β•°β”ˆβž€"+oldValue, false); - break; - - case "inviter_id": - User inviter = ale.getJDA().getUserById(String.valueOf(oldValue)); - eb.addField("πŸ‘€ Invite Originally Created By", "β•°β”ˆβž€"+(inviter != null ? inviter.getAsMention() : "`Unknown`"), false); - break; - - case "temporary": - eb.addField("πŸ•’ Temporary Invite", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(oldValue), false); - break; - - case "max_uses", "flags", "max_age": - break; - - case "uses": - eb.addField("πŸ”’ Number of times the invite was used", "β•°β”ˆβž€"+oldValue, false); - break; - - case "channel_id": - Channel channel = ale.getGuild().getGuildChannelById(String.valueOf(oldValue)); - eb.addField("πŸ’¬ Invite Channel", "β•°β”ˆβž€"+(channel != null ? channel.getAsMention() : "`"+oldValue+"`"), false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/KickEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/KickEventHelper.java deleted file mode 100644 index 9d38f13b..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/KickEventHelper.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; - -@UtilityClass -public class KickEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Kick Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: " + mentionableExecutor + "\nℹ️ The following member was kicked"); - eb.setColor(Color.ORANGE); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - String moderatorId = ale.getUserId(); - String targetId = ale.getTargetId(); - String reason = ale.getReason(); - - // fixme -> find a way to not use REST Action - // A REST Action is required here because kicked members are not cached - event.getJDA().retrieveUserById(moderatorId).queue(moderator -> - event.getJDA().retrieveUserById(targetId).queue(target -> { - // if user objects are null we cannot use their mention so we instead use their IDs instead since they will never be null - eb.addField("πŸ‘’ A member/application has been kicked", "β•°β”ˆβž€" + (moderator != null ? moderator.getAsMention() : moderatorId) + " has kicked " + (target != null ? target.getAsMention() : targetId), false); - eb.addField("πŸ“ With Reason", "β•°β”ˆβž€" + (reason != null ? reason : "No Reason Provided"), false); - - eb.setFooter("Audit Log Entry ID: " + ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if (sendingChannel != null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - }) - ); - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/MemberRoleUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/MemberRoleUpdateEventHelper.java deleted file mode 100644 index 675688aa..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/MemberRoleUpdateEventHelper.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.RoleObjectParser; - -import java.awt.Color; -import java.util.Map; -import java.util.Objects; - -@UtilityClass -public class MemberRoleUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Member Role Update"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - User target = ale.getJDA().getUserById(ale.getTargetIdLong()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTarget = (target !=null ? target.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following member role was updated"); - eb.setThumbnail(Objects.requireNonNull(event.getGuild().getMemberById(ale.getTargetIdLong())).getEffectiveAvatarUrl()); - eb.setColor(Color.YELLOW); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "$add": - eb.addField("🏷️Target Member", "β•°β”ˆβž€"+mentionableTarget, false); - eb.addField("βœ…Role(s) Added", "β•°β”ˆβž€"+RoleObjectParser.parseRole(event, newValue), false); - break; - - case "$remove": - eb.addField("🏷️Target Member", "β•°β”ˆβž€"+mentionableTarget, false); - eb.addField("❌Role(s) Removed", "β•°β”ˆβž€"+RoleObjectParser.parseRole(event, newValue), false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/MemberUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/MemberUpdateEventHelper.java deleted file mode 100644 index 7eab103a..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/MemberUpdateEventHelper.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.DurationFormatter; - -import java.awt.Color; -import java.util.Map; -import java.util.Objects; - -@UtilityClass -public class MemberUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Member Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - User target = ale.getJDA().getUserById(ale.getTargetIdLong()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTarget = (target !=null ? target.getAsMention() : ale.getTargetId()); - - Member targetMember = ale.getGuild().getMemberById(ale.getTargetId()); - String mentionableTargetEffectiveName = targetMember!=null ? targetMember.getEffectiveName() : "Name could not be fetched"; - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following member was updated"); - eb.setThumbnail(Objects.requireNonNull(event.getGuild().getMemberById(ale.getTargetId())).getEffectiveAvatarUrl()); - eb.setColor(Color.CYAN); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "communication_disabled_until": - if(newValue==null) { - eb.setColor(Color.GREEN); - eb.addField("🟒 Timeout Lifted", "β•°β”ˆβž€ Timeout for "+mentionableTarget+ " has been removed", false); - } else { - eb.setColor(Color.YELLOW); - eb.addField("β›” Timeout Received", "β•°β”ˆβž€"+mentionableTarget+ " has received a timeout", false); - eb.addField("⏱️ Till", "β•°β”ˆβž€"+ DurationFormatter.isoToLocalTimeCounter(newValue), false); - eb.addField("πŸ“ Reason", "β•°β”ˆβž€"+(ale.getReason()!=null ? ale.getReason() : "No Reason Provided"), false); - } - - break; - - case "nick": - if(oldValue!=null && newValue==null) { // resetting to default nickname - eb.addField("🏷️ Target", "β•°β”ˆβž€"+mentionableTarget, false); - eb.addField("🏷️ Old Nickname", "β•°β”ˆβž€"+oldValue, false); - eb.addField("🏷️ Reset Name To", "β•°β”ˆβž€"+mentionableTargetEffectiveName, false); - } else if(oldValue != null) { // changing from one nickname to another - eb.addField("🏷️ Target", "β•°β”ˆβž€"+mentionableTarget, false); - eb.addField("🏷️ Old Nickname", "β•°β”ˆβž€"+oldValue, false); - eb.addField("🏷️ New Nickname", "β•°β”ˆβž€"+newValue, false); - } else if(newValue != null) { // changing from default nickname to a new nickname - eb.addField("🏷️ Target", "β•°β”ˆβž€"+mentionableTarget, false); - eb.addField("🏷️ Nickname Added", "β•°β”ˆβž€"+ newValue, false); - } - break; - - case "mute": - eb.addField("πŸŽ™οΈ Is Muted", "β•°β”ˆβž€Set "+mentionableTarget+"'s Mute Status as "+ BooleanFormatter.formatToEmoji(newValue), false); - break; - - case "deaf": - eb.addField("πŸ”‡ Is Deafened", "β•°β”ˆβž€Set "+mentionableTarget+"'s Deafened Status as "+ BooleanFormatter.formatToEmoji(newValue), false); - break; - - case "bypasses_verification": - eb.addField("πŸ›‘οΈ Bypass Verification", "β•°β”ˆβž€Set "+mentionableTarget+"'s verification bypass status as "+ BooleanFormatter.formatToEmoji(newValue), false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/MessagePinEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/MessagePinEventHelper.java deleted file mode 100644 index 53da6f42..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/MessagePinEventHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; - -@UtilityClass -public class MessagePinEventHelper { - - // this audit log event does not expose anything other than the executor of the event - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Message Pin Event"); - - User executor = ale.getJDA().getUserById(ale.getTargetId()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **A message from **: "+mentionableExecutor+" was pinned"); - eb.setColor(Color.PINK); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } - -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/MessageUnpinEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/MessageUnpinEventHelper.java deleted file mode 100644 index 38017952..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/MessageUnpinEventHelper.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; - -@UtilityClass -public class MessageUnpinEventHelper { - - // this audit log event does not expose anything other than the executor of the event - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Message Unpin Event"); - - User executor = ale.getJDA().getUserById(ale.getTargetId()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **A message from **: "+mentionableExecutor+" un-pinned"); - eb.setColor(Color.MAGENTA); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/OnboardingPromptCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/OnboardingPromptCreateEventHelper.java deleted file mode 100644 index d6779a16..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/OnboardingPromptCreateEventHelper.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; - -import java.awt.Color; - -@UtilityClass -public class OnboardingPromptCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, String channelIdToSendTo) { - - AuditLogEntry ale = event.getEntry(); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Onboarding Prompt Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserId()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ " + mentionableExecutor + "has created an Onboarding Prompt"); - eb.setColor(Color.GREEN); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - ale.getChanges().forEach((changeKey, changeValue) -> { - - Object oldValue = changeValue.getOldValue(); - Object newValue = changeValue.getNewValue(); - - switch (changeKey){ - case "single_select": - eb.addField("Single Selection Mode", BooleanFormatter.formatToYesOrNo(newValue), false); - break; - - case "required": - eb.addField("Required", BooleanFormatter.formatToYesOrNo(newValue), false); - break; - - case "type", "id": - break; - - case "title": - eb.addField("Question Title", String.valueOf(newValue), false); - break; - - case "options": - eb.addField("Question Options", "Review the options in Onboarding Settings", false); - break; - - case "in_onboarding": - eb.addField("Is a Pre-Join Question", BooleanFormatter.formatToYesOrNo(newValue), false); - break; - - default: - eb.addField(changeKey, "OLD_VALUE: "+oldValue, false); - eb.addField(changeKey, "NEW_VALUE: "+newValue, false); - } - - }); - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/OnboardingPromptDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/OnboardingPromptDeleteEventHelper.java deleted file mode 100644 index 43b1dffc..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/OnboardingPromptDeleteEventHelper.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; - -import java.awt.Color; - -@UtilityClass -public class OnboardingPromptDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, String channelIdToSendTo) { - - AuditLogEntry ale = event.getEntry(); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Onboarding Prompt Delete Event"); - - User executor = ale.getJDA().getUserById(ale.getUserId()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ " + mentionableExecutor + "has made deleted an Onboarding Prompt"); - eb.setColor(Color.RED); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - ale.getChanges().forEach((changeKey, changeValue) -> { - - Object oldValue = changeValue.getOldValue(); - Object newValue = changeValue.getNewValue(); - - switch (changeKey){ - case "single_select": - eb.addField("Single Selection Mode", BooleanFormatter.formatToYesOrNo(oldValue), false); - break; - - case "required": - eb.addField("Was Required", BooleanFormatter.formatToYesOrNo(oldValue), false); - break; - - case "type", "id", "options": - break; - - case "title": - eb.addField("Question Title", String.valueOf(oldValue), false); - break; - - case "in_onboarding": - eb.addField("Was a Pre-Join Question", BooleanFormatter.formatToYesOrNo(oldValue), false); - break; - - default: - eb.addField(changeKey, "OLD_VALUE: "+oldValue, false); - eb.addField(changeKey, "NEW_VALUE: "+newValue, false); - } - - }); - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } - -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/OnboardingUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/OnboardingUpdateEventHelper.java deleted file mode 100644 index 5374e42a..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/OnboardingUpdateEventHelper.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.OnboardingUtils; - -import java.awt.Color; - -@UtilityClass -public class OnboardingUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, String channelIdToSendTo) { - - AuditLogEntry ale = event.getEntry(); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Onboarding Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserId()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getTargetId()); - - Guild guild = event.getGuild(); - - eb.setDescription("πŸ‘€ " + mentionableExecutor + "has made changes to Onboarding"); - eb.setColor(Color.MAGENTA); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - ale.getChanges().forEach((changeKey, changeValue) -> { - Object oldValue = changeValue.getOldValue(); - Object newValue = changeValue.getNewValue(); - - switch (changeKey){ - case "enabled": - eb.addField("Old Onboarding Status", OnboardingUtils.formatStatus(oldValue), false); - eb.addField("New Onboarding Status", OnboardingUtils.formatStatus(newValue), true); - break; - - case "mode": - eb.addField("Old Onboarding Mode", OnboardingUtils.formatMode(oldValue), false); - eb.addField("New Onboarding Mode", OnboardingUtils.formatMode(newValue), true); - break; - - case "default_channel_ids": - eb.addField("Old Default Channels", OnboardingUtils.resolveChannelsFromList(guild, oldValue), false); - eb.addField("New Default Channels", OnboardingUtils.resolveChannelsFromList(guild, newValue), false); - break; - - case "prompts": // unknown as to exactly why this is triggered - eb.addField("Prompt Updates", "Overall Pre-join/Post-join questions may have been updated.\n Review changes manually.", false); - break; - - default: - eb.addField(changeKey, "from: "+oldValue+" to: "+newValue, false); - } - - }); - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/RoleCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/RoleCreateEventHelper.java deleted file mode 100644 index 8970be98..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/RoleCreateEventHelper.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class RoleCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Role Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserId()); - Role targetRole = ale.getJDA().getRoleById(ale.getTargetId()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTargetRole = (targetRole !=null ? targetRole.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\n The following role was created"); - eb.setColor(Color.GREEN); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - eb.addField("Target Role", mentionableTargetRole, false); - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "name": - eb.addField("🏷️ Role Name", "β•°β”ˆβž€"+newValue, false); - break; - - /* - * discord for some reason shows the following to be default/null even - * when you set them during the creation of the role itself - * and delegates them to ROLE_UPDATE event - */ - case "colors", "hoist", "color", "permissions", "mentionable": - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/RoleDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/RoleDeleteEventHelper.java deleted file mode 100644 index 0f4f4766..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/RoleDeleteEventHelper.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.ColorFormatter; -import org.papertrail.commons.utilities.PermissionResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class RoleDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Role Delete Event"); - - User executor = ale.getJDA().getUserById(ale.getUserId()); - Role targetRole = ale.getJDA().getRoleById(ale.getTargetId()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTargetRole = (targetRole !=null ? targetRole.getAsMention() : ale.getTargetId()); // this will always return the ID only - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following role was deleted"); - eb.setColor(Color.RED); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "name": - eb.addField("🏷️ Role Name", "β•°β”ˆβž€"+oldValue, false); - break; - - case "hoist": - eb.addField("πŸ“‚ Display Seperately", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(oldValue), false); - break; - - case "color": - eb.addField("🎨 Color", "β•°β”ˆβž€"+ ColorFormatter.formatToHex(oldValue), false); - break; - - case "permissions": - eb.addField("Role Permissions", PermissionResolver.getParsedPermissions(oldValue, "βœ…"), false); - break; - - case "mentionable": - eb.addField("πŸ”— Mentionable", "β•°β”ˆβž€"+BooleanFormatter.formatToEmoji(oldValue), false); - break; - - case "colors": - eb.addField("🌈 Gradient Color System", "β•°β”ˆβž€"+ColorFormatter.formatGradientColorSystemToHex(oldValue), false); - break; - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.addField("πŸ†” Deleted Role ID", "β•°β”ˆβž€"+mentionableTargetRole, false); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/RoleUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/RoleUpdateEventHelper.java deleted file mode 100644 index 2406e1d9..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/RoleUpdateEventHelper.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.ColorFormatter; -import org.papertrail.commons.utilities.PermissionResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class RoleUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Role Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserId()); - Role targetRole = ale.getJDA().getRoleById(ale.getTargetId()); - - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - String mentionableTargetRole = (targetRole !=null ? targetRole.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following member role was updated"); - eb.setColor(Color.YELLOW); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - eb.addField("Target Role", mentionableTargetRole, false); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "name": - eb.addField("🏷️ Old Role Name", "β•°β”ˆβž€"+oldValue, true); - eb.addField("🏷️ New Role Name", "β•°β”ˆβž€"+newValue, true); - eb.addBlankField(true); - break; - - case "hoist": - eb.addField("πŸ“‚ Old Display Seperately", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(oldValue), true); - eb.addField("πŸ“‚ New Display Seperately", "β•°β”ˆβž€"+BooleanFormatter.formatToEmoji(newValue), true); - eb.addBlankField(true); - break; - - case "color": - eb.addField("🎨 Old Color", "β•°β”ˆβž€"+ ColorFormatter.formatToHex(oldValue), true); - eb.addField("🎨 New Color", "β•°β”ˆβž€"+ColorFormatter.formatToHex(newValue), true); - eb.addBlankField(true); - break; - - case "permissions": - eb.addField("Old Role Permissions", PermissionResolver.getParsedPermissions(oldValue, "βœ…"), true); - eb.addField("New Role Permissions", PermissionResolver.getParsedPermissions(newValue, "βœ…"), true); - eb.addBlankField(true); - break; - - case "mentionable": - eb.addField("πŸ”— Old Mentionable", "β•°β”ˆβž€"+BooleanFormatter.formatToEmoji(oldValue), true); - eb.addField("πŸ”— New Mentionable", "β•°β”ˆβž€"+BooleanFormatter.formatToEmoji(newValue), true); - eb.addBlankField(true); - break; - - case "colors": - eb.addField("🌈 Old Gradient Color System", "β•°β”ˆβž€"+ColorFormatter.formatGradientColorSystemToHex(oldValue), true); - eb.addField("🌈 New Gradient Color System", "β•°β”ˆβž€"+ColorFormatter.formatGradientColorSystemToHex(newValue), true); - eb.addBlankField(true); - break; - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ScheduledEventCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ScheduledEventCreateEventHelper.java deleted file mode 100644 index 228ff587..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ScheduledEventCreateEventHelper.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.GuildScheduledEventRecurrenceRuleStructureParser; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class ScheduledEventCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Scheduled Event Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A scheduled event was created"); - eb.setColor(Color.GREEN); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "entity_type": - eb.addField("πŸ“‚ Event Type", "β•°β”ˆβž€"+ TypeResolver.scheduleEventTypeResolver(newValue), false); - break; - - case "privacy_level", "image_hash": - break; - - case "name": - eb.addField("🏷️ Event Name", "β•°β”ˆβž€"+newValue, false); - break; - - case "description": - eb.addField("πŸ“ Event Description", "β•°β”ˆβž€"+newValue, false); - break; - - case "status": - eb.addField("πŸ“Š Event Status", "β•°β”ˆβž€"+TypeResolver.scheduleEventStatusTypeResolver(newValue), false); - break; - - case "location": - eb.addField("πŸ“ Event Location", "β•°β”ˆβž€"+newValue, false); - break; - - case "channel_id": - GuildChannel eventChannel = event.getGuild().getGuildChannelById(String.valueOf(newValue)); - eb.addField("πŸ’¬ Event Channel", "β•°β”ˆβž€"+(eventChannel!=null ? eventChannel.getAsMention() : String.valueOf(newValue)), false); - break; - - case "recurrence_rule": - eb.addField("πŸ“Š Recurrence Rule", GuildScheduledEventRecurrenceRuleStructureParser.parse(newValue), false); - break; - - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ScheduledEventDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ScheduledEventDeleteEventHelper.java deleted file mode 100644 index 204cc9aa..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ScheduledEventDeleteEventHelper.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.GuildScheduledEventRecurrenceRuleStructureParser; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class ScheduledEventDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Scheduled Event Delete Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A scheduled event has been deleted"); - eb.setColor(Color.RED); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "entity_type": - eb.addField("πŸ“‚ Event Type", "β•°β”ˆβž€"+ TypeResolver.scheduleEventTypeResolver(oldValue), false); - break; - - case "privacy_level", "image_hash": - break; - - case "name": - eb.addField("🏷️ Event Name", "β•°β”ˆβž€"+oldValue, false); - break; - - case "description": - eb.addField("πŸ“ Event Description", "β•°β”ˆβž€"+newValue, false); - break; - - case "status": - eb.addField("πŸ“Š Event Status", "β•°β”ˆβž€"+TypeResolver.scheduleEventStatusTypeResolver(oldValue), false); - break; - - case "location": - eb.addField("πŸ“ Event Location", "β•°β”ˆβž€"+oldValue, false); - break; - - case "channel_id": - GuildChannel eventChannel = event.getGuild().getGuildChannelById(String.valueOf(oldValue)); - eb.addField("πŸ’¬ Event Channel", "β•°β”ˆβž€"+(eventChannel!=null ? eventChannel.getAsMention() : String.valueOf(oldValue)), false); - break; - - case "recurrence_rule": - eb.addField("πŸ“Š Recurrence Rule", GuildScheduledEventRecurrenceRuleStructureParser.parse(oldValue), false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ScheduledEventUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ScheduledEventUpdateEventHelper.java deleted file mode 100644 index 1aea5700..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ScheduledEventUpdateEventHelper.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.ScheduledEvent; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.GuildScheduledEventRecurrenceRuleStructureParser; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; -import java.util.Objects; - -@UtilityClass -public class ScheduledEventUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Scheduled Event Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - ScheduledEvent targetEvent = event.getGuild().getScheduledEventById(ale.getTargetId()); - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following scheduled event was updated: "+ Objects.requireNonNull(targetEvent).getName()); - eb.setColor(Color.YELLOW); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "entity_type": - eb.addField("πŸ“‚ Old Event Type", "β•°β”ˆβž€"+ TypeResolver.scheduleEventTypeResolver(oldValue), false); - eb.addField("πŸ“‚ New Event Type", "β•°β”ˆβž€"+TypeResolver.scheduleEventTypeResolver(newValue), false); - break; - - case "privacy_level", "image_hash": - break; - - case "name": - eb.addField("🏷️ Old Event Name", "β•°β”ˆβž€"+oldValue, false); - eb.addField("🏷️ New Event Name","β•°β”ˆβž€"+newValue, false); - break; - - case "description": - eb.addField("πŸ“ Old Event Description", "β•°β”ˆβž€"+oldValue, false); - eb.addField("πŸ“ New Event Description", "β•°β”ˆβž€"+newValue, false); - break; - - case "status": - eb.addField("πŸ“Š Old Event Status", "β•°β”ˆβž€"+TypeResolver.scheduleEventStatusTypeResolver(oldValue), false); - eb.addField("πŸ“Š New Event Status", "β•°β”ˆβž€"+TypeResolver.scheduleEventStatusTypeResolver(newValue), false); - break; - - case "location": - eb.addField("πŸ“ Event Location", "β•°β”ˆβž€"+oldValue, false); - eb.addField("πŸ“ Event Location", "β•°β”ˆβž€"+newValue, false); - break; - - case "channel_id": - GuildChannel eventChannel = event.getGuild().getGuildChannelById(String.valueOf(oldValue)); - eb.addField("πŸ’¬ Old Event Channel", "β•°β”ˆβž€"+(eventChannel!=null ? eventChannel.getAsMention() : String.valueOf(oldValue)), false); - eventChannel = event.getGuild().getGuildChannelById(String.valueOf(newValue)); - eb.addField("πŸ’¬ New Event Channel", "β•°β”ˆβž€"+(eventChannel!=null ? eventChannel.getAsMention() : String.valueOf(newValue)), false); - break; - - case "recurrence_rule": - eb.addField("πŸ“Š Old Recurrence Rule", GuildScheduledEventRecurrenceRuleStructureParser.parse(oldValue), false); - eb.addField("πŸ“Š New Recurrence Rule", GuildScheduledEventRecurrenceRuleStructureParser.parse(newValue), false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/SoundboardSoundCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/SoundboardSoundCreateEventHelper.java deleted file mode 100644 index 659a1913..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/SoundboardSoundCreateEventHelper.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class SoundboardSoundCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Soundboard Sound Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A sound item was added to the soundboard"); - eb.setColor(Color.GREEN); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "user_id", "sound_id", "id", "guild_id", "available": - break; - - case "volume": - eb.addField("Volume", "β•°β”ˆβž€"+newValue, false); - break; - - case "emoji_name": - eb.addField("Related Emoji", "β•°β”ˆβž€"+newValue, false); - break; - - case "emoji_id": - eb.addField("Related Emoji ID", "β•°β”ˆβž€"+newValue, false); - break; - - case "name": - eb.addField("Sound Item Name", "β•°β”ˆβž€"+newValue, false); - break; - - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/SoundboardSoundDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/SoundboardSoundDeleteEventHelper.java deleted file mode 100644 index cb30fec9..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/SoundboardSoundDeleteEventHelper.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class SoundboardSoundDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Soundboard Sound Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A sound item was deleted from the soundboard"); - eb.setColor(Color.RED); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "user_id", "sound_id", "id", "guild_id", "available": - break; - - case "volume": - eb.addField("Volume", "β•°β”ˆβž€"+oldValue, false); - break; - - case "emoji_name": - eb.addField("Related Emoji", "β•°β”ˆβž€"+oldValue, false); - break; - - case "emoji_id": - eb.addField("Related Emoji ID", "β•°β”ˆβž€"+oldValue, false); - break; - - case "name": - eb.addField("Sound Item Name", "β•°β”ˆβž€"+oldValue, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/SoundboardSoundUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/SoundboardSoundUpdateEventHelper.java deleted file mode 100644 index 398c7e5c..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/SoundboardSoundUpdateEventHelper.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class SoundboardSoundUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Soundboard Sound Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A sound item in the soundboard was updated"); - eb.setColor(Color.YELLOW); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "user_id", "sound_id", "id", "guild_id", "available": - break; - - case "volume": - eb.addField("Old Volume", "β•°β”ˆβž€"+oldValue, false); - eb.addField("New Volume", "β•°β”ˆβž€"+newValue, false); - break; - - case "emoji_name": - eb.addField("Old Related Emoji", "β•°β”ˆβž€"+oldValue, false); - eb.addField("New Related Emoji", "β•°β”ˆβž€"+newValue, false); - break; - - case "emoji_id": - eb.addField("Old Related Emoji ID", "β•°β”ˆβž€"+oldValue, false); - eb.addField("New Related Emoji ID", "β•°β”ˆβž€"+newValue, false); - break; - - case "name": - eb.addField("Old Sound Item Name", "β•°β”ˆβž€"+oldValue, false); - eb.addField("New Sound Item Name", "β•°β”ˆβž€"+newValue, false); - break; - - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/StageInstanceCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/StageInstanceCreateEventHelper.java deleted file mode 100644 index 15fcda2a..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/StageInstanceCreateEventHelper.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class StageInstanceCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Stage Instance Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A stage instance was created"); - eb.setColor(Color.GREEN); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "topic": - eb.addField("πŸ“ Stage Topic", "β•°β”ˆβž€"+newValue, false); - break; - - case "privacy_level": - eb.addField("🌐 Stage Privacy", "β•°β”ˆβž€"+newValue, false); - eb.addField("Stage Privacy Result Inference", "-# A value of 1 means PUBLIC (deprecated) and 2 means GUILD_ONLY", false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/StageInstanceDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/StageInstanceDeleteEventHelper.java deleted file mode 100644 index 358f9040..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/StageInstanceDeleteEventHelper.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class StageInstanceDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Stage Instance Delete Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A stage instance was deleted"); - eb.setColor(Color.RED); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "topic": - eb.addField("πŸ“ Deleted Stage Topic", "β•°β”ˆβž€"+oldValue, false); - break; - - case "privacy_level": - eb.addField("🌐 Deleted Stage Privacy", "β•°β”ˆβž€"+oldValue, false); - eb.addField("Stage Privacy Result Inference", "-# A value of 1 means PUBLIC (deprecated) and 2 means GUILD_ONLY", false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/StageInstanceUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/StageInstanceUpdateEventHelper.java deleted file mode 100644 index fb46132c..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/StageInstanceUpdateEventHelper.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class StageInstanceUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Stage Instance Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A stage instance was updated"); - eb.setColor(Color.YELLOW); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "topic": - eb.addField("πŸ“ OldStage Topic", "β•°β”ˆβž€"+oldValue, false); - eb.addField("πŸ“ New Stage Topic", "β•°β”ˆβž€"+newValue, false); - break; - - case "privacy_level": - eb.addField("🌐 Old Stage Privacy","β•°β”ˆβž€"+oldValue, false); - eb.addField("🌐 New Stage Privacy", "β•°β”ˆβž€"+newValue, false); - eb.addField("Stage Privacy Result Inference", "-# A value of 1 means PUBLIC (deprecated) and 2 means GUILD_ONLY", false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/StickerCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/StickerCreateEventHelper.java deleted file mode 100644 index e50202b3..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/StickerCreateEventHelper.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.sticker.GuildSticker; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class StickerCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Sticker Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following sticker was created"); - eb.setColor(Color.GREEN); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "format_type", "type", "asset", "available", "guild_id": - break; - - case "id": - eb.addField("πŸ†” Sticker ID", "β•°β”ˆβž€"+newValue, false); - GuildSticker sticker = event.getGuild().getStickerById(String.valueOf(newValue)); - eb.addField("πŸ”— Sticker Link", "β•°β”ˆβž€"+(sticker!=null ? sticker.getIconUrl() : "N/A"), false); - break; - - case "tags": - eb.addField("ℹ️ Related Emoji", "β•°β”ˆβž€"+newValue, false); - break; - - case "description": - eb.addField("πŸ“ Description", "β•°β”ˆβž€"+newValue, false); - break; - - case "name": - eb.addField("🏷️ Sticker Name", "β•°β”ˆβž€"+newValue, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/StickerDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/StickerDeleteEventHelper.java deleted file mode 100644 index 7a42e032..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/StickerDeleteEventHelper.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class StickerDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Sticker Delete Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following sticker was deleted"); - eb.setColor(Color.RED); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "format_type", "type", "asset", "available", "guild_id": - break; - - case "id": - eb.addField("πŸ†” Sticker ID", "β•°β”ˆβž€"+oldValue, false); - break; - - case "tags": - eb.addField("ℹ️ Related Emoji", "β•°β”ˆβž€"+oldValue, false); - break; - - case "description": - eb.addField("πŸ“ Description", "β•°β”ˆβž€"+oldValue, false); - break; - - case "name": - eb.addField("🏷️ Sticker Name", "β•°β”ˆβž€"+oldValue, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/StickerUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/StickerUpdateEventHelper.java deleted file mode 100644 index a2f3103d..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/StickerUpdateEventHelper.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.sticker.GuildSticker; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; -import java.util.Objects; - -@UtilityClass -public class StickerUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Sticker Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - GuildSticker targetSticker = event.getGuild().getStickerById(ale.getTargetId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following sticker was updated"); - eb.setColor(Color.YELLOW); - - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - eb.addField("🏷️ Target Sticker Name", Objects.requireNonNull(targetSticker).getName(), false); - eb.addField("πŸ”— Target Sticker Url", targetSticker.getIconUrl(), false); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - - case "format_type", "type", "asset", "available", "guild_id", "id": - break; - - case "tags": - eb.addField("ℹ️ Related Emoji", "β•°β”ˆβž€"+"from "+oldValue+" to "+newValue, false); - break; - - case "description": - eb.addField("πŸ“ Description", "β•°β”ˆβž€"+"from `"+oldValue+"` to `"+newValue+"`", false); - break; - - case "name": - eb.addField("🏷️ Sticker Name", "β•°β”ˆβž€"+"from `"+oldValue+"` to `"+newValue+"`", false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - } - - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ThreadCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ThreadCreateEventHelper.java deleted file mode 100644 index 7525285c..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ThreadCreateEventHelper.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.DurationFormatter; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class ThreadCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Thread Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - ThreadChannel targetThread = event.getGuild().getThreadChannelById(ale.getTargetId()); - String mentionableTargetThread = (targetThread !=null ? targetThread.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A thread has been created"); - eb.setColor(Color.GREEN); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "locked": - eb.addField("πŸ”’ Locked", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(newValue), false); - break; - - case "auto_archive_duration": - eb.addField("πŸ•’ Auto Archive Duration", "β•°β”ˆβž€"+ DurationFormatter.formatMinutes(newValue), false); - break; - - case "rate_limit_per_user": - eb.addField("🐌 Slowmode Limit", "β•°β”ˆβž€"+DurationFormatter.formatSeconds(newValue), false); - break; - - case "type": - eb.addField("πŸ“ Thread Type", "β•°β”ˆβž€"+ TypeResolver.channelTypeResolver(newValue), false); - break; - - case "archived": - eb.addField("πŸ—„οΈ Archived", "β•°β”ˆβž€"+BooleanFormatter.formatToEmoji(newValue), false); - break; - - case "flags": - eb.addField("🚩 Flags", "β•°β”ˆβž€"+newValue, false); - break; - - case "name": - eb.addField("🏷️ Thread Name", "β•°β”ˆβž€"+newValue, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - eb.addField("🧡 Target Thread", "β•°β”ˆβž€"+mentionableTargetThread, false); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ThreadDeleteEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ThreadDeleteEventHelper.java deleted file mode 100644 index d2c3d002..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ThreadDeleteEventHelper.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.DurationFormatter; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class ThreadDeleteEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Thread Delete Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A thread has been deleted"); - eb.setColor(Color.RED); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "πŸ”’ locked": - eb.addField("Locked", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(oldValue), false); - break; - - case "πŸ•’ auto_archive_duration": - eb.addField("Auto Archive Duration", "β•°β”ˆβž€"+ DurationFormatter.formatMinutes(oldValue), false); - break; - - case "rate_limit_per_user": - eb.addField("🐌 Slowmode Limit", "β•°β”ˆβž€"+DurationFormatter.formatSeconds(oldValue), false); - break; - - case "type": - eb.addField("πŸ“ Thread Type", "β•°β”ˆβž€"+ TypeResolver.channelTypeResolver(oldValue), false); - break; - - case "archived": - eb.addField("πŸ—„οΈ Archived", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(oldValue), false); - break; - - case "flags": - eb.addField("🚩 Flags", "β•°β”ˆβž€"+oldValue, false); - break; - - case "name": - eb.addField("🏷️ Thread Name", "β•°β”ˆβž€"+oldValue, false); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/ThreadUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/ThreadUpdateEventHelper.java deleted file mode 100644 index a78fdcb2..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/ThreadUpdateEventHelper.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; -import org.papertrail.commons.utilities.BooleanFormatter; -import org.papertrail.commons.utilities.DurationFormatter; -import org.papertrail.commons.utilities.TypeResolver; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class ThreadUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Thread Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - ThreadChannel targetThread = event.getGuild().getThreadChannelById(ale.getTargetId()); - String mentionableTargetThread = (targetThread !=null ? targetThread.getAsMention() : ale.getTargetId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A thread has been updated"); - eb.setColor(Color.YELLOW); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.addBlankField(true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "locked": - eb.addField("πŸ”’ Old Lock Status", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(oldValue), true); - eb.addField("πŸ”’ New Lock Status", "β•°β”ˆβž€"+ BooleanFormatter.formatToEmoji(newValue), true); - eb.addBlankField(true); - break; - - case "auto_archive_duration": - eb.addField("πŸ•’ Old Auto Archive Duration", "β•°β”ˆβž€"+ DurationFormatter.formatMinutes(oldValue), true); - eb.addField("πŸ•’ New Auto Archive Duration", "β•°β”ˆβž€"+DurationFormatter.formatMinutes(newValue), true); - eb.addBlankField(true); - break; - - case "rate_limit_per_user": - eb.addField("🐌 Old Slowmode Limit", "β•°β”ˆβž€"+DurationFormatter.formatSeconds(oldValue), true); - eb.addField("🐌 New Slowmode Limit", "β•°β”ˆβž€"+DurationFormatter.formatSeconds(newValue), true); - eb.addBlankField(true); - break; - - case "type": - eb.addField("πŸ“ Old Thread Type", "β•°β”ˆβž€"+ TypeResolver.channelTypeResolver(oldValue), true); - eb.addField("πŸ“ New Thread Type", "β•°β”ˆβž€"+TypeResolver.channelTypeResolver(newValue), true); - eb.addBlankField(true); - break; - - case "archived": - eb.addField("πŸ—„οΈ Old Archive Status", "β•°β”ˆβž€"+BooleanFormatter.formatToEmoji(oldValue), true); - eb.addField("πŸ—„οΈ New Archive Status", "β•°β”ˆβž€"+BooleanFormatter.formatToEmoji(newValue), true); - eb.addBlankField(true); - break; - - case "flags": - eb.addField("🚩 Old Flag Value", "β•°β”ˆβž€"+oldValue, true); - eb.addField("🚩 New Flag Value", "β•°β”ˆβž€"+newValue, true); - eb.addBlankField(true); - break; - - case "name": - eb.addField("🏷️ Old Thread Name", "β•°β”ˆβž€"+oldValue, true); - eb.addField("🏷️ New Thread Name", "β•°β”ˆβž€"+newValue, true); - eb.addBlankField(true); - break; - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - eb.addField("🧡 Target Thread", "β•°β”ˆβž€"+mentionableTargetThread, false); - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/UnbanEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/UnbanEventHelper.java deleted file mode 100644 index 4fd18a74..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/UnbanEventHelper.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; - -@UtilityClass -public class UnbanEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Member Unban Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: " + mentionableExecutor + "\nℹ️ The following user was un-banned"); - eb.setColor(Color.GREEN); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - String moderatorId = ale.getUserId(); - String targetId = ale.getTargetId(); - - event.getJDA().retrieveUserById(moderatorId).queue(moderator -> - event.getJDA().retrieveUserById(targetId).queue(target -> { - // if user objects are null we cannot use their mention so we instead use their IDs instead since they will never be null - eb.addField("πŸ”“ A member has been un-banned", "β•°β”ˆβž€" + (moderator != null ? moderator.getAsMention() : moderatorId) + " has un-banned " + (target != null ? target.getAsMention() : targetId), false); - - eb.setFooter("Audit Log Entry ID: " + ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - MessageEmbed mb = eb.build(); - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if (sendingChannel != null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - }) - ); - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/WebhookCreateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/WebhookCreateEventHelper.java deleted file mode 100644 index 2203fdfb..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/WebhookCreateEventHelper.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class WebhookCreateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Webhook Create Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A webhook has been created"); - eb.setColor(Color.GREEN); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "type": - eb.addField("Webhook Type", "β•°β”ˆβž€"+newValue, false); - eb.addField("Webhook Type Explanation", "-# 0 for PING; 1 for Event", false); - break; - - case "avatar_Hash": - eb.addField("Avatar Hash", "β•°β”ˆβž€"+newValue, false); - break; - - case "channel_id": - GuildChannel targetChannel = event.getGuild().getGuildChannelById(String.valueOf(newValue)); - String mentionableTargetChannel = (targetChannel !=null ? targetChannel.getAsMention() : String.valueOf(newValue)); - eb.addField("Channel", "β•°β”ˆβž€"+mentionableTargetChannel, false); - break; - - case "name": - eb.addField("Webhook Name", "β•°β”ˆβž€"+newValue, false); - break; - - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/WebhookRemoveEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/WebhookRemoveEventHelper.java deleted file mode 100644 index a9ff6b12..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/WebhookRemoveEventHelper.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class WebhookRemoveEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Webhook Remove Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A webhook has been removed"); - eb.setColor(Color.RED); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "type": - eb.addField("πŸ“‘ Webhook Type", "β•°β”ˆβž€"+oldValue, false); - break; - - case "avatar_hash": - eb.addField("πŸ–ΌοΈ Avatar Hash", "β•°β”ˆβž€"+oldValue, false); - break; - - case "channel_id": - GuildChannel targetChannel = event.getGuild().getGuildChannelById(String.valueOf(oldValue)); - String mentionableTargetChannel = (targetChannel !=null ? targetChannel.getAsMention() : String.valueOf(oldValue)); - eb.addField("πŸ’¬ Channel", "β•°β”ˆβž€"+mentionableTargetChannel, false); - break; - - case "name": - eb.addField("🏷️ Webhook Name", "β•°β”ˆβž€"+oldValue, false); - break; - - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/audit/helper/WebhookUpdateEventHelper.java b/src/main/java/org/papertrail/listeners/audit/helper/WebhookUpdateEventHelper.java deleted file mode 100644 index 03e72cb0..00000000 --- a/src/main/java/org/papertrail/listeners/audit/helper/WebhookUpdateEventHelper.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.papertrail.listeners.audit.helper; - -import lombok.experimental.UtilityClass; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.audit.AuditLogChange; -import net.dv8tion.jda.api.audit.AuditLogEntry; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent; - -import java.awt.Color; -import java.util.Map; - -@UtilityClass -public class WebhookUpdateEventHelper { - - public static void format(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Audit Log Entry | Webhook Update Event"); - - User executor = ale.getJDA().getUserById(ale.getUserIdLong()); - String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); - - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ A webhook has been updated"); - eb.setColor(Color.YELLOW); - eb.addField("Action Type", String.valueOf(ale.getType()), true); - eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - - for(Map.Entry changes: ale.getChanges().entrySet()) { - String change = changes.getKey(); - Object oldValue = changes.getValue().getOldValue(); - Object newValue = changes.getValue().getNewValue(); - - switch(change) { - case "type": - eb.addField("πŸ“‘ Webhook Type", "β•°β”ˆβž€ " + newValue, false); - break; - - case "avatar_hash": - eb.addField("πŸ–ΌοΈ Avatar Hash", "β•°β”ˆβž€"+"from `"+oldValue+"` to `"+newValue+"`", false); - break; - - case "channel_id": - GuildChannel targetChannel = event.getGuild().getGuildChannelById(String.valueOf(newValue)); - String mentionableTargetChannel = (targetChannel !=null ? targetChannel.getAsMention() : String.valueOf(newValue)); - eb.addField("πŸ’¬ New Channel", "β•°β”ˆβž€"+mentionableTargetChannel, false); - break; - - case "name": - eb.addField("🏷️ Webhook Name", "β•°β”ˆβž€"+"from "+oldValue+" to "+newValue, false); - break; - - - default: - eb.addField(change, "from "+oldValue+" to "+newValue, false); - } - - } - eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); - - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - } - -} diff --git a/src/main/java/org/papertrail/listeners/audit/setup/AuditLogSetupCommandListener.java b/src/main/java/org/papertrail/listeners/audit/setup/AuditLogSetupCommandListener.java deleted file mode 100644 index 11dbb0ee..00000000 --- a/src/main/java/org/papertrail/listeners/audit/setup/AuditLogSetupCommandListener.java +++ /dev/null @@ -1,174 +0,0 @@ -package org.papertrail.listeners.audit.setup; - -import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; -import io.github.eggy03.papertrail.sdk.entity.AuditLogRegistrationEntity; -import net.dv8tion.jda.api.EmbedBuilder; -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.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.channel.Channel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.papertrail.commons.utilities.EnvConfig; - -import java.awt.Color; -import java.util.Optional; - -public class AuditLogSetupCommandListener extends ListenerAdapter { - - private static final AuditLogRegistrationClient client = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); - - @Override - public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { - - if(!event.getName().equals("auditlog")){ - return; - } - - if(event.getSubcommandName()==null) { - return; - } - - switch(event.getSubcommandName()) { - - case "set": - setAuditLogging(event); - break; - - case "view": - retrieveAuditLoggingChannel(event); - break; - - case "remove": - unsetAuditLogging(event); - break; - - default: - break; - } - } - - - private void setAuditLogging(SlashCommandInteractionEvent event) { - - // Only members in a guild with MANAGE_SERVER permissions should be able to use this command - Member callerMember = event.getMember(); - Guild callerGuild = event.getGuild(); - Channel callerChannel = event.getChannel().asTextChannel(); - - if (callerMember == null || callerGuild == null) { - event.reply("❌ You can only use this command in a guild.").setEphemeral(true).queue(); - return; - } - - if (!callerMember.hasPermission(Permission.MANAGE_SERVER)) { - event.reply("❌ You don't have the permission required to use this command.").setEphemeral(true).queue(); - return; - } - - // Call the API to register the guild and the channel - boolean success = client.registerGuild(callerGuild.getId(), callerChannel.getId()); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“ Audit Log Configuration"); - - if (success) { - eb.addField("βœ… Channel Registration Success", "β•°β”ˆβž€" + "All audit log info will be logged here", false); - eb.setColor(Color.GREEN); - - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - } else { - eb.addField("❌ Channel Registration Failure", "β•°β”ˆβž€" + "Channel could not be registered.\nCheck if a channel in this guild is already registered for logging.", false); - eb.setColor(Color.YELLOW); - - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - } - - } - - private void retrieveAuditLoggingChannel(SlashCommandInteractionEvent event) { - - // Only members in a guild with MANAGE_SERVER permissions should be able to use this command - Member callerMember = event.getMember(); - Guild callerGuild = event.getGuild(); - - if (callerMember == null || callerGuild == null) { - event.reply("❌ You can only use this command in a guild.").setEphemeral(true).queue(); - return; - } - - if (!callerMember.hasPermission(Permission.MANAGE_SERVER)) { - event.reply("❌ You don't have the permission required to use this command.").setEphemeral(true).queue(); - return; - } - - - // Call the API to retrieve the registered channel - Optional response = client.getRegisteredGuild(callerGuild.getId()); - - // if there is no channel_id for the given guild_id returned by the API, then inform - // the user of the same, else link the channel that has been registered - response.ifPresentOrElse(success -> { - - String registeredChannelId = success.getChannelId(); - GuildChannel registeredChannel = event.getJDA().getGuildChannelById(registeredChannelId); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“ Audit Log Configuration"); - eb.setColor(Color.CYAN); - eb.addField("βœ… Channel Registration Check", "β•°β”ˆβž€"+(registeredChannel!=null ? registeredChannel.getAsMention() : registeredChannelId)+ " is found to be registered as the audit log channel", false); - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - - }, () -> { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“ Audit Log Configuration"); - eb.addField("⚠️ Channel Registration Check", "β•°β”ˆβž€"+"No channel has been registered for audit logs", false); - eb.setColor(Color.YELLOW); - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - }); - } - - private void unsetAuditLogging(SlashCommandInteractionEvent event) { - - // Only members in a guild with MANAGE_SERVER permissions should be able to use this command - Member callerMember = event.getMember(); - Guild callerGuild = event.getGuild(); - - if (callerMember == null || callerGuild == null) { - event.reply("❌ You can only use this command in a guild.").setEphemeral(true).queue(); - return; - } - - if (!callerMember.hasPermission(Permission.MANAGE_SERVER)) { - event.reply("❌ You don't have the permission required to use this command.").setEphemeral(true).queue(); - return; - } - - // Call the API to unregister guild - boolean success = client.deleteRegisteredGuild(callerGuild.getId()); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“ Audit Log Configuration"); - - if (success) { - eb.addField("βœ… Channel Removal", "β•°β”ˆβž€"+"Channel successfully unset", false); - eb.setColor(Color.GREEN); - - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - } else { - eb.addField("❌ Channel Removal Failure", "β•°β”ˆβž€"+"Channel could not be unset.\nThis may be because no channel has been registered in this guild yet.", false); - eb.setColor(Color.YELLOW); - - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - } - - } -} diff --git a/src/main/java/org/papertrail/listeners/message/event/MessageLogListener.java b/src/main/java/org/papertrail/listeners/message/event/MessageLogListener.java deleted file mode 100644 index 025d1bf1..00000000 --- a/src/main/java/org/papertrail/listeners/message/event/MessageLogListener.java +++ /dev/null @@ -1,186 +0,0 @@ -package org.papertrail.listeners.message.event; - -import com.google.common.base.Splitter; -import io.github.eggy03.papertrail.sdk.client.MessageLogContentClient; -import io.github.eggy03.papertrail.sdk.client.MessageLogRegistrationClient; -import io.github.eggy03.papertrail.sdk.entity.MessageLogContentEntity; -import io.github.eggy03.papertrail.sdk.entity.MessageLogRegistrationEntity; -import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.message.MessageDeleteEvent; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.events.message.MessageUpdateEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.jetbrains.annotations.NotNull; -import org.papertrail.commons.utilities.EnvConfig; - -import java.awt.Color; -import java.time.Instant; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.Executor; - -@Slf4j -public class MessageLogListener extends ListenerAdapter { - - private static final MessageLogRegistrationClient registrationClient = new MessageLogRegistrationClient(EnvConfig.get("API_URL")); - private static final MessageLogContentClient contentClient = new MessageLogContentClient(EnvConfig.get("API_URL")); - - private final Executor vThreadPool; - - public MessageLogListener(Executor vThreadPool) { - this.vThreadPool = vThreadPool; - } - - @Override - public void onMessageReceived(MessageReceivedEvent event) { - - // if the author is a bot or system, don't log - if(event.getAuthor().isBot() || event.getAuthor().isSystem()) { - return; - } - // don't register non-textual contents - if(event.getMessage().getContentRaw().isEmpty()) { - return; - } - - vThreadPool.execute(()-> { - - // get the guild id for which the event was fired - String guildId = event.getGuild().getId(); - // Call the API to see if the guild is registered for Message Logging - Optional response = registrationClient.getRegisteredGuild(guildId); - response.ifPresent(success -> { - String messageId = event.getMessageId(); - String messageContent = event.getMessage().getContentDisplay(); - String authorId = event.getAuthor().getId(); - - contentClient.logMessage(messageId, messageContent, authorId); - }); - }); - } - - @Override - public void onMessageUpdate(MessageUpdateEvent event) { - - if(event.getAuthor().isBot() || event.getAuthor().isSystem()) { - return; - } - - vThreadPool.execute(()->{ - - // Get the guild id for which the event was fired - String guildId = event.getGuild().getId(); - // get the message id of the message which was updated - String messageId = event.getMessageId(); - // Call the API to see if the guild is registered for Message Logging - Optional response = registrationClient.getRegisteredGuild(guildId); - response.ifPresent(success -> { - - // retrieve the channel id where the logs must be sent - String channelIdToSendTo = success.getChannelId(); - - // fetch the old message object from the API - Optional oldMessageContent = contentClient.retrieveMessage(messageId); - oldMessageContent.ifPresent(contentEntity -> { - // Fetch the old message - String oldMessage = contentEntity.getMessageContent(); - // fetch the updated message and its author from the event - String updatedMessage = event.getMessage().getContentDisplay(); - - // Ignore events where the message content wasn't edited (e.g., pin, embed resolve, thread creates and updates) - // This is required since MessageUpdateEvent is triggered in case of pins and embed resolves with no change to content - if(updatedMessage.equals(oldMessage)) { - return; - } - - // Splitting is required because each field in an embed can display only up-to 1024 characters - // A full embed can display up-to 6000 characters - List oldMessageSplits = Splitter.fixedLength(1024).splitToList(oldMessage); - List updatedMessageSplits = Splitter.fixedLength(1024).splitToList(updatedMessage); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“ Message Edit Event"); - eb.setDescription("A message sent by "+event.getAuthor().getAsMention()+" has been edited in: "+event.getJumpUrl()); - eb.setColor(Color.YELLOW); - - oldMessageSplits.forEach(split -> eb.addField("Old Message", split, false)); - updatedMessageSplits.forEach(split -> eb.addField("New Message", split, false)); - - eb.setFooter(event.getGuild().getName()); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - // send the old and updated message to the registered channel - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - - // update the database with the new message - contentClient.updateMessage(messageId, updatedMessage, event.getAuthor().getId()); - }); - }); - }); - } - - @Override - public void onMessageDelete(@NotNull MessageDeleteEvent event) { - - vThreadPool.execute(()-> { - - // Get the guild id for which the event was fired - String guildId = event.getGuild().getId(); - // get the message id of the message which was deleted - String messageId = event.getMessageId(); - - // Call the API to see if the guild is registered for Message Logging - Optional response = registrationClient.getRegisteredGuild(guildId); - response.ifPresent(success -> { - - // retrieve the channel id where the logs must be sent - String channelIdToSendTo = success.getChannelId(); - - // fetch the old message object from the API - Optional oldMessageContent = contentClient.retrieveMessage(messageId); - oldMessageContent.ifPresent(contentEntity -> { - - // retrieve the stored message and author in the database which was deleted - String deletedMessage = contentEntity.getMessageContent(); - String deletedMessageAuthorId = contentEntity.getAuthorId(); - - User author = event.getJDA().getUserById(deletedMessageAuthorId); - String mentionableAuthor = (author !=null ? author.getAsMention() : deletedMessageAuthorId); - - // Splitting is required because each field in an embed can display only up-to 1024 characters - List deletedMessageSplits = Splitter.fixedLength(1024).splitToList(deletedMessage); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ—‘οΈ Message Delete Event"); - eb.setDescription("A message sent by "+mentionableAuthor+" has been deleted from "+ event.getChannel().getAsMention()); - eb.setColor(Color.RED); - - deletedMessageSplits.forEach(split-> eb.addField("Deleted Message", split, false)); - - eb.setFooter(event.getGuild().getName()); - eb.setTimestamp(Instant.now()); - - // send the fetched deleted message to the logging channel - MessageEmbed mb = eb.build(); - - TextChannel sendingChannel = event.getGuild().getTextChannelById(channelIdToSendTo); - if(sendingChannel!=null && sendingChannel.canTalk()) { - sendingChannel.sendMessageEmbeds(mb).queue(); - } - - // delete the message from the database - contentClient.deleteMessage(messageId); - }); - }); - }); - } -} diff --git a/src/main/java/org/papertrail/listeners/message/setup/MessageLogSetupCommandListener.java b/src/main/java/org/papertrail/listeners/message/setup/MessageLogSetupCommandListener.java deleted file mode 100644 index 0eced335..00000000 --- a/src/main/java/org/papertrail/listeners/message/setup/MessageLogSetupCommandListener.java +++ /dev/null @@ -1,168 +0,0 @@ -package org.papertrail.listeners.message.setup; - -import io.github.eggy03.papertrail.sdk.client.MessageLogRegistrationClient; -import io.github.eggy03.papertrail.sdk.entity.MessageLogRegistrationEntity; -import net.dv8tion.jda.api.EmbedBuilder; -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.entities.MessageEmbed; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel; -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.papertrail.commons.utilities.EnvConfig; - -import java.awt.Color; -import java.util.Optional; - -public class MessageLogSetupCommandListener extends ListenerAdapter { - - private static final MessageLogRegistrationClient client = new MessageLogRegistrationClient(EnvConfig.get("API_URL")); - - @Override - public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { - - if(!event.getName().equals("messagelog")){ - return; - } - - if(event.getSubcommandName()==null) { - return; - } - - switch(event.getSubcommandName()) { - - case "set": - setMessageLogging(event); - break; - - case "view": - retrieveMessageLoggingChannel(event); - break; - - case "remove": - unsetMessageLogging(event); - break; - - default: - break; - } - } - - private void setMessageLogging(SlashCommandInteractionEvent event) { - - // Only members in a guild with ADMINISTRATOR permissions should be able to use this command - Member callerMember = event.getMember(); - Guild callerGuild = event.getGuild(); - TextChannel callerChannel = event.getChannel().asTextChannel(); - - if (callerMember == null || callerGuild == null) { - event.reply("❌ You can only use this command in a guild.").setEphemeral(true).queue(); - return; - } - - if (!callerMember.hasPermission(Permission.ADMINISTRATOR)) { - event.reply("❌ You don't have the permission required to use this command.").setEphemeral(true).queue(); - return; - } - - // Call the API to register guild for message logging - boolean success = client.registerGuild(callerGuild.getId(), callerChannel.getId()); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("Message Log Registration"); - - if (success) { - eb.addField("βœ… Channel Registration Success","β•°β”ˆβž€"+"All edited and deleted messages will be logged here", false); - eb.setColor(Color.GREEN); - - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - } else { - eb.addField("❌ Channel Registration Failure", "β•°β”ˆβž€" + "Channel could not be registered.\nCheck if a channel in this guild is already registered for logging.", false); - eb.setColor(Color.YELLOW); - - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - } - - } - - private void retrieveMessageLoggingChannel(SlashCommandInteractionEvent event) { - - // Only members in a guild with ADMINISTRATOR permissions should be able to use this command - Member callerMember = event.getMember(); - Guild callerGuild = event.getGuild(); - - if (callerMember == null || callerGuild == null) { - event.reply("❌ You can only use this command in a guild.").setEphemeral(true).queue(); - return; - } - - if (!callerMember.hasPermission(Permission.ADMINISTRATOR)) { - event.reply("❌ You don't have the permission required to use this command.").setEphemeral(true).queue(); - return; - } - - // Call the API to check for registered guild - Optional response = client.getRegisteredGuild(callerGuild.getId()); - response.ifPresentOrElse(success -> { - - String registeredChannelId = success.getChannelId(); - GuildChannel registeredChannel = event.getJDA().getGuildChannelById(registeredChannelId); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“ Message Log Configuration"); - eb.setColor(Color.CYAN); - eb.addField("βœ… Channel Registration Check", "β•°β”ˆβž€"+(registeredChannel!=null ? registeredChannel.getAsMention() : registeredChannelId)+ " is found to be registered as the message log channel", false); - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - - }, () -> { - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“ Message Log Configuration"); - eb.addField("⚠️ Channel Registration Check", "β•°β”ˆβž€"+"No channel has been registered for message logs", false); - eb.setColor(Color.YELLOW); - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - }); - } - - private void unsetMessageLogging(SlashCommandInteractionEvent event) { - - // Only members in a guild with ADMINISTRATOR permissions should be able to use this command - Member callerMember = event.getMember(); - Guild callerGuild = event.getGuild(); - - if (callerMember == null || callerGuild == null) { - event.reply("❌ You can only use this command in a guild.").setEphemeral(true).queue(); - return; - } - - if (!callerMember.hasPermission(Permission.ADMINISTRATOR)) { - event.reply("❌ You don't have the permission required to use this command.").setEphemeral(true).queue(); - return; - } - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“ Message Log Configuration"); - - - // Call the API to unregister guild - boolean success = client.deleteRegisteredGuild(callerGuild.getId()); - if (success) { - eb.addField("βœ… Channel Removal", "β•°β”ˆβž€" + "Channel successfully unset", false); - eb.setColor(Color.GREEN); - - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - } else { - eb.addField("❌ Channel Removal Failure", "β•°β”ˆβž€"+"Channel could not be unset.\nThis may be because no channel has been registered in this guild yet.", false); - eb.setColor(Color.YELLOW); - MessageEmbed mb = eb.build(); - - event.replyEmbeds(mb).setEphemeral(false).queue(); - } - } -} diff --git a/src/main/java/org/papertrail/listeners/misc/ActivityUpdateListener.java b/src/main/java/org/papertrail/listeners/misc/ActivityUpdateListener.java deleted file mode 100644 index 2aa21e13..00000000 --- a/src/main/java/org/papertrail/listeners/misc/ActivityUpdateListener.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.papertrail.listeners.misc; - -import net.dv8tion.jda.api.entities.Activity; -import net.dv8tion.jda.api.events.guild.GuildJoinEvent; -import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; -import net.dv8tion.jda.api.events.session.ReadyEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import net.dv8tion.jda.api.sharding.ShardManager; -import org.jetbrains.annotations.NotNull; - -/* - * This class updates the number of servers the bot is in - */ -public class ActivityUpdateListener extends ListenerAdapter { - - private final ShardManager manager; - - public ActivityUpdateListener(ShardManager manager) { - this.manager = manager; - } - - @Override - public void onReady(@NotNull ReadyEvent event) { // update on cold start - updateActivity(); - } - - @Override - public void onGuildJoin(@NotNull GuildJoinEvent event) { // update on guild join - updateActivity(); - } - - @Override - public void onGuildLeave(@NotNull GuildLeaveEvent event) { // update on guild leave - updateActivity(); - } - - private void updateActivity() { - manager.setActivity(Activity.customStatus("Monitoring In: "+manager.getGuildCache().size() + " Servers")); - } - -} diff --git a/src/main/java/org/papertrail/listeners/misc/BotSetupInstructionCommandListener.java b/src/main/java/org/papertrail/listeners/misc/BotSetupInstructionCommandListener.java deleted file mode 100644 index 423b1700..00000000 --- a/src/main/java/org/papertrail/listeners/misc/BotSetupInstructionCommandListener.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.papertrail.listeners.misc; - -import net.dv8tion.jda.api.EmbedBuilder; -import net.dv8tion.jda.api.entities.MessageEmbed; -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.papertrail.commons.constant.ProjectInfo; - -import java.awt.Color; -import java.time.Instant; - -public class BotSetupInstructionCommandListener extends ListenerAdapter { - - @Override - public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { - - if (event.getName().equals("setup")) { - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ› οΈ Setup Guide for " + ProjectInfo.APPNAME); - eb.setDescription("Welcome to **" + ProjectInfo.APPNAME + "**!\nHere's how to get started using the bot in your server."); - eb.setColor(Color.decode("#38e8bc")); - - eb.addField("1️⃣ Register Audit Log Channel", - "- Use `/auditlog set` to **register the current channel** for receiving audit log updates.\nβ•°β”ˆβž€ User must have `Manage Server` permission.", - false); - - eb.addField("2️⃣ View Registered Audit Log Channel", - "- Use `/auditlog view` to **check which channel** is currently registered for audit logs.\nThis is helpful if you're unsure where the audit logs are going.\nβ•°β”ˆβž€ User must have `Manage Server` permission.", - false); - - eb.addField("3️⃣ Unregister Audit Log Channel", - "- Use `/auditlog remove` to **unset the audit log channel** if you wish to stop logging or switch to another one.\nβ•°β”ˆβž€ User must have `Manage Server` permission.", - false); - - eb.addBlankField(false); - - eb.addField("4️⃣ Register Message Log Channel", - "- Use `/messagelog set` to **register the current channel** for receiving message logs.\nβ•°β”ˆβž€ User must have the `Administrator` permission.", - false); - - eb.addField("5️⃣ View Registered Message Log Channel", - "- Use `/messagelog view` to **check which channel** is currently registered for message logs.\nThis is helpful if you're unsure where the message logs are going.\nβ•°β”ˆβž€ User must have `Administrator` permission.", - false); - - eb.addField("6️⃣ Unregister Message Log Channel", - "- Use `/messagelog remove` to **unset the message log channel** if you wish to stop logging or switch to another one.\nβ•°β”ˆβž€ User must have `Administrator` permission.", - false); - - eb.addBlankField(false); - - eb.addField("7️⃣ View Server Stats", - "- Use `/stats` to **get useful server information** like member count, channel count, and more.", - false); - - eb.addField("πŸ“¬ Need help?", "Create an issue on [GitHub](" + ProjectInfo.PROJECT_ISSUE_LINK+")", false); - eb.setFooter(ProjectInfo.APPNAME+" "+ProjectInfo.VERSION); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - } - } -} - diff --git a/src/main/java/org/papertrail/listeners/misc/SelfKickListener.java b/src/main/java/org/papertrail/listeners/misc/SelfKickListener.java deleted file mode 100644 index f876a38a..00000000 --- a/src/main/java/org/papertrail/listeners/misc/SelfKickListener.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.papertrail.listeners.misc; - -import io.github.eggy03.papertrail.sdk.client.AuditLogRegistrationClient; -import io.github.eggy03.papertrail.sdk.client.MessageLogRegistrationClient; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.jetbrains.annotations.NotNull; -import org.papertrail.commons.utilities.EnvConfig; - -import java.util.concurrent.Executor; - -/* - * This class will have methods that unregister the log channels from the database after the bot has been kicked - */ -public class SelfKickListener extends ListenerAdapter { - - private static final AuditLogRegistrationClient alClient = new AuditLogRegistrationClient(EnvConfig.get("API_URL")); - private static final MessageLogRegistrationClient mlClient = new MessageLogRegistrationClient(EnvConfig.get("API_URL")); - - private final Executor vThreadPool; - - public SelfKickListener(Executor vThreadPool) { - this.vThreadPool = vThreadPool; - } - - @Override - public void onGuildLeave(@NotNull GuildLeaveEvent event) { - - Guild leftGuild = event.getGuild(); - vThreadPool.execute(()->{ - alClient.deleteRegisteredGuild(leftGuild.getId()); - mlClient.deleteRegisteredGuild(leftGuild.getId()); - }); - } -} diff --git a/src/main/java/org/papertrail/listeners/misc/ServerStatCommandListener.java b/src/main/java/org/papertrail/listeners/misc/ServerStatCommandListener.java deleted file mode 100644 index 7e031346..00000000 --- a/src/main/java/org/papertrail/listeners/misc/ServerStatCommandListener.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.papertrail.listeners.misc; - -import net.dv8tion.jda.api.EmbedBuilder; -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.entities.MessageEmbed; -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.papertrail.commons.utilities.DurationFormatter; - -import java.awt.Color; -import java.time.Instant; -import java.util.List; -import java.util.Objects; - -public class ServerStatCommandListener extends ListenerAdapter{ - - @Override - public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { - - if(event.getName().equals("stats")) { - - Guild guild = event.getGuild(); - if (guild == null) { - event.reply("You can only use this command in Guilds").setEphemeral(true).queue(); - return; - } - - List members = guild.getMemberCache().asList(); - int botCount = 0; - int userCount = 0; - int onlineUserCount = 0; - for(Member member: members) { - if(member.getUser().isBot()) { - botCount++; - } - - else { - OnlineStatus status = member.getOnlineStatus(); - if(status.equals(OnlineStatus.DO_NOT_DISTURB) || status.equals(OnlineStatus.IDLE) || status.equals(OnlineStatus.ONLINE)) { - onlineUserCount++; - } - userCount++; - } - } - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“Š Server Statistics πŸ“Š"); - eb.setDescription("πŸ“ Server Statistics For: **"+guild.getName()+"**"); - eb.setThumbnail(guild.getIconUrl()); - eb.setColor(Color.PINK); - - eb.addField("🏠 Guild Name", "β•°β”ˆβž€"+guild.getName(), false); - eb.addField("πŸ‘‘ Guild Owner", "β•°β”ˆβž€"+ Objects.requireNonNull(guild.getMemberById(guild.getOwnerId())).getAsMention(), false); - eb.addField("πŸ“… Guild Created On", "β•°β”ˆβž€"+DurationFormatter.isoToLocalTimeCounter(guild.getTimeCreated()), false); - eb.addField("πŸ”— Guild Vanity URL", "β•°β”ˆβž€"+(guild.getVanityUrl() !=null ? guild.getVanityUrl() : "Not Set"), false); - - eb.addField("πŸ‘₯ Member Count", "β•°β”ˆβž€"+userCount, true); - eb.addField("πŸ€– Bot Count", "β•°β”ˆβž€"+botCount, true); - eb.addField("🟒 Members Online", "β•°β”ˆβž€"+onlineUserCount+"/"+userCount, true); - - List boosters = guild.getBoosters(); - StringBuilder mentionableBoosters = new StringBuilder(); - for(Member booster: boosters) { - mentionableBoosters.append(booster.getAsMention()).append(" "); - } - eb.addField("πŸš€ Guild Boosters ", "β•°β”ˆβž€"+mentionableBoosters, false); - eb.addField("πŸ’– Guild Boost Count", "β•°β”ˆβž€"+guild.getBoostCount(), false); - eb.addField("πŸ“Ž Booster Role", "β•°β”ˆβž€"+(guild.getBoostRole() !=null ? guild.getBoostRole().getAsMention() : "No Boost Role Found"), false); - eb.addField("πŸ—Ό Boost Tier", "β•°β”ˆβž€"+ guild.getBoostTier(), false); - - eb.addField("🌐 Locale", "β•°β”ˆβž€"+guild.getLocale().getNativeName(), true); - eb.addField("πŸ”’ Verification", "β•°β”ˆβž€"+guild.getVerificationLevel().name(), true); - eb.addField("🧱 Roles", "β•°β”ˆβž€"+guild.getRoles().size(), true); - eb.addField("πŸ—‚οΈ Categories", "β•°β”ˆβž€"+guild.getCategories().size(), true); - eb.addField("πŸ’¬ Text Channels", "β•°β”ˆβž€"+guild.getTextChannels().size(), true); - eb.addField("πŸ”Š Voice Channels", "β•°β”ˆβž€"+guild.getVoiceChannels().size(), true); - - eb.addField("πŸ“‹ Data Requested By", "β•°β”ˆβž€"+ Objects.requireNonNull(event.getMember()).getAsMention(), false); - eb.setFooter("πŸ“‹ Stats By: PaperTrail πŸ“‹"); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - event.replyEmbeds(mb).setEphemeral(false).queue(); - } - - } -} diff --git a/src/main/java/org/papertrail/listeners/misc/SlashCommandRegistrationListener.java b/src/main/java/org/papertrail/listeners/misc/SlashCommandRegistrationListener.java deleted file mode 100644 index a192567c..00000000 --- a/src/main/java/org/papertrail/listeners/misc/SlashCommandRegistrationListener.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.papertrail.listeners.misc; - -import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.events.session.ReadyEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import net.dv8tion.jda.api.interactions.commands.build.CommandData; -import net.dv8tion.jda.api.interactions.commands.build.Commands; -import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; -import org.jetbrains.annotations.NotNull; - -/* - * Registers all the slash commands places throughout the code - */ -public class SlashCommandRegistrationListener extends ListenerAdapter { - - @Override - public void onReady(@NotNull ReadyEvent event) { - setAuditLogCommands(event.getJDA()); - } - - private void setAuditLogCommands(JDA jda) { - - CommandData auditLog = Commands.slash("auditlog", "manage audit log options") - .addSubcommands(new SubcommandData("set", "set audit log channel here")) - .addSubcommands(new SubcommandData("view", "view audit log channel")) - .addSubcommands(new SubcommandData("remove", "unset audit log channel")); - - CommandData messageLog = Commands.slash("messagelog", "manage message log options") - .addSubcommands(new SubcommandData("set", "set message log channel here")) - .addSubcommands(new SubcommandData("view", "view message log channel")) - .addSubcommands(new SubcommandData("remove", "unset message log channel")); - - CommandData serverStats = Commands.slash("stats", - "Provides Server Statistics"); - - CommandData setup = Commands.slash("setup", "Provides a guide on setting up the bot"); - - jda.updateCommands() - .addCommands(auditLog, - messageLog, - serverStats, - setup) - .queue(); - } -} diff --git a/src/main/java/org/papertrail/main/ConnectionInitializer.java b/src/main/java/org/papertrail/main/ConnectionInitializer.java deleted file mode 100644 index bbc08a72..00000000 --- a/src/main/java/org/papertrail/main/ConnectionInitializer.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.papertrail.main; - -import lombok.Getter; -import net.dv8tion.jda.api.OnlineStatus; -import net.dv8tion.jda.api.requests.GatewayIntent; -import net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder; -import net.dv8tion.jda.api.sharding.ShardManager; -import net.dv8tion.jda.api.utils.ChunkingFilter; -import net.dv8tion.jda.api.utils.MemberCachePolicy; -import net.dv8tion.jda.api.utils.cache.CacheFlag; -import org.papertrail.commons.utilities.EnvConfig; -import org.papertrail.listeners.misc.ActivityUpdateListener; - -/* - * This class initializes the connection to discord and configures all the necessary intents - */ -@Getter -public class ConnectionInitializer { - - // returns the manager that manages multiple shards (instances) of the bot - // Manages multiple shards (instances) of the bot - private final ShardManager manager; - - public ConnectionInitializer() { - - String token = EnvConfig.get("TOKEN"); - - DefaultShardManagerBuilder builder = DefaultShardManagerBuilder.createDefault(token); - builder.enableIntents(GatewayIntent.SCHEDULED_EVENTS, - GatewayIntent.AUTO_MODERATION_EXECUTION, - GatewayIntent.AUTO_MODERATION_CONFIGURATION, - GatewayIntent.MESSAGE_CONTENT, - GatewayIntent.GUILD_MEMBERS, - GatewayIntent.GUILD_EXPRESSIONS, - GatewayIntent.GUILD_PRESENCES, - GatewayIntent.GUILD_MODERATION); - - builder.setStatus(OnlineStatus.ONLINE); - - //cache all users of the bot - builder.setMemberCachePolicy(MemberCachePolicy.ALL); - builder.setChunkingFilter(ChunkingFilter.ALL); - //you will still need builder.enableCache() to cache user activities and status - builder.enableCache(CacheFlag.ACTIVITY, - CacheFlag.CLIENT_STATUS, - CacheFlag.EMOJI, - CacheFlag.STICKER, - CacheFlag.ONLINE_STATUS, - CacheFlag.MEMBER_OVERRIDES, - CacheFlag.ROLE_TAGS, - CacheFlag.SCHEDULED_EVENTS); - - manager = builder.build(); - manager.addEventListener(new ActivityUpdateListener(manager)); - //manager.addEventListener(new SlashCommandRegistrationListener()); - // re-enable it only when adding/updating/deleting commands - } - -} diff --git a/src/main/java/org/papertrail/main/Start.java b/src/main/java/org/papertrail/main/Start.java deleted file mode 100644 index 699dfcf8..00000000 --- a/src/main/java/org/papertrail/main/Start.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.papertrail.main; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; -import net.dv8tion.jda.api.sharding.ShardManager; -import org.papertrail.listeners.audit.event.AuditLogEventListener; -import org.papertrail.listeners.audit.event.GuildBoostEventListener; -import org.papertrail.listeners.audit.event.GuildMemberJoinAndLeaveEventListener; -import org.papertrail.listeners.audit.event.GuildPollEventListener; -import org.papertrail.listeners.audit.event.GuildVoiceEventListener; -import org.papertrail.listeners.audit.setup.AuditLogSetupCommandListener; -import org.papertrail.listeners.message.event.MessageLogListener; -import org.papertrail.listeners.message.setup.MessageLogSetupCommandListener; -import org.papertrail.listeners.misc.BotSetupInstructionCommandListener; -import org.papertrail.listeners.misc.SelfKickListener; -import org.papertrail.listeners.misc.ServerStatCommandListener; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -/* - * The main class of the bot - */ -public class Start { - - // All I/O blocking operations run inside the vThreadPool - private static final Executor vThreadPool = Executors.newVirtualThreadPerTaskExecutor(); - - public static void main(String[] args) throws IOException { - - ConnectionInitializer ci = new ConnectionInitializer(); - ShardManager manager = ci.getManager(); - - manager.addEventListener(new AuditLogSetupCommandListener()); - manager.addEventListener(new AuditLogEventListener(vThreadPool)); - - manager.addEventListener(new MessageLogSetupCommandListener()); - manager.addEventListener(new MessageLogListener(vThreadPool)); - - manager.addEventListener(new GuildVoiceEventListener(vThreadPool)); - manager.addEventListener(new GuildMemberJoinAndLeaveEventListener(vThreadPool)); - manager.addEventListener(new GuildPollEventListener(vThreadPool)); - manager.addEventListener(new GuildBoostEventListener(vThreadPool)); - manager.addEventListener(new SelfKickListener(vThreadPool)); - - manager.addEventListener(new ServerStatCommandListener()); - manager.addEventListener(new BotSetupInstructionCommandListener()); - - // Custom health check endpoint - HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); - server.createContext("/ping", new PingHandler()); - server.setExecutor(null); // creates a default executor - server.start(); - } - - static class PingHandler implements HttpHandler { - @Override - public void handle(HttpExchange exchange) throws IOException { - exchange.sendResponseHeaders(200, -1); - } - } - -} diff --git a/src/main/resources/tinylog.properties b/src/main/resources/tinylog.properties index 22ba864e..a9bf9fa4 100644 --- a/src/main/resources/tinylog.properties +++ b/src/main/resources/tinylog.properties @@ -1,5 +1,4 @@ -writer = console -writer.format = {level}: {class}.{method}()\n{message} -writer.level = info - -writingthread = true \ No newline at end of file +writer=console +writer.format={level}: {class}.{method}()\n{message} +writer.level=info +writingthread=true \ No newline at end of file