Compare commits

...

86 Commits

Author SHA1 Message Date
ded6513a02
Merge tag '2.0.3' into develop
Hotfix
2023-03-29 22:27:48 +02:00
dedc26a68c
Merge branch 'hotfix/2.0.3' 2023-03-29 22:27:24 +02:00
64d88a8af4
Fix audio bug with jda update 2023-03-29 22:27:18 +02:00
4c892abf88
🔨 Add daily member cache 2022-09-27 11:32:33 +02:00
renovate[bot]
b414dc1df5
⬆️ Update dependency org.apache.logging.log4j:log4j-bom to v2.18.0 (#203)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-03 09:36:04 +02:00
renovate[bot]
2db7a47b79
⬆️ Update dependency net.dv8tion:JDA to v4.4.0_352 (#204)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-03 09:35:50 +02:00
renovate[bot]
d639dff533
⬆️ Update dependency org.liquibase:liquibase-core to v4.14.0 (#205)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-03 09:35:34 +02:00
renovate[bot]
06e22fdf86
⬆️ Update dependency io.micrometer:micrometer-registry-prometheus to v1.9.2 (#206)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-03 09:35:14 +02:00
renovate[bot]
868efc6091
⬆️ Update dependency org.liquibase.ext:liquibase-hibernate5 to v4.14.0 (#207)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-03 09:34:57 +02:00
renovate[bot]
a2664203a1
⬆️ Update dependency gradle to v7.5 (#208)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-03 09:34:44 +02:00
renovate[bot]
5db205a4b6
⬆️ Update plugin org.springframework.boot to v2.7.2 (#210)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-03 09:34:26 +02:00
renovate[bot]
ed20f7ca9a
⬆️ Update dependency mysql:mysql-connector-java to v8.0.30 (#211)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-03 09:33:24 +02:00
b785f40e4f
🔨 Allow invite link without login 2022-07-04 15:44:22 +02:00
renovate[bot]
b0e479f247
⬆️ Update plugin io.spring.dependency-management to v1.0.12.RELEASE (#200)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-01 09:41:50 +02:00
renovate[bot]
ddc2fcda0a
⬆️ Update tj-actions/branch-names action to v5.4 (#202)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-01 09:40:57 +02:00
renovate[bot]
39c0af917c
⬆️ Update plugin org.springframework.boot to v2.7.1 (#201)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-01 09:40:37 +02:00
9d3a2a7866
Readme 2022-06-30 18:42:47 +02:00
3c0d848abe
Ui Rebuild (#199)
* Cleanup

* Build auth provider

* Implement discord login

* Add jwt service + add liquibase

* 🔨 Add jwt filter

* 🔨 Update user info in db on login

* 🔨 Add swagger

* 🔨 Add dev container

* 🔨 Add dev container

* 🔨 Fix changelog ?

* 🔨 Fix openApi

* 🔨 Add guildcontroller with getMutualGuilds

* 🔨 Change multual guilds url

* 🔨 Add invite link api

* 🔨 migrate env to config prop

* 🔒 Add security expression for guild

* 🔒 Add dev mode to auth

* 🔨 Add textchannel and voicechannel endpoint

* 🔨 Add setting description endpoint

* 🔨 Add getRole endpoint

* 🔨 Return only visible voice/text channels

* 🔨 Add value endpoint

* 🤖 Change ci

* 🔨 Add canManage to guild list

* 🚑 Load user of guild on load + fetch on api call for mutuals guilds

* 🚑 Fix auto_voice_channel_title type

* 🚑 Fix swagger url

* 🚑 Fix setting type

* 🔨 Add setting post

* Fix blanck string in db

* 🔨 Add music status api enpoint

* 🚑 Fix permission

* 🔨 Change interact condition

* 🔨 Add connect api command

* 🔨 Add disconnect endpoint

* 🔨 Audio refracto

* 🔨 Big refracto

* 🔨 Refracto libs

* 🔨 Rebuild http request with new client

* 🔨 Refracto + add skip, pause, resume, stop endpoint

* 🔨 Add endpoint

* 🚑 Fix permission

* Update build.yml

* Update plugin org.liquibase.gradle to v2.1.1 [skip ci] (#186)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update plugin nebula.lint to v16.26.0 [skip ci] (#185)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update dependency org.liquibase:liquibase-core to v4.12.0 [skip ci] (#184)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update dependency org.liquibase.ext:liquibase-hibernate5 to v4.12.0 [skip ci] (#183)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update actions/checkout action to v3 [skip ci] (#187)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update actions/download-artifact action to v3 [skip ci] (#188)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* 🚑 Fix permission

* Update tj-actions/branch-names action to v5.3 [skip ci] (#195)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update plugin nebula.lint to v17 [skip ci] (#194)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update docker/setup-buildx-action action to v2 [skip ci] (#193)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update docker/login-action action to v2 [skip ci] (#192)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update docker/build-push-action action to v3 [skip ci] (#191)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update dependency openjdk to v18 [skip ci] (#190)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update actions/setup-java action to v3 [skip ci] (#189)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Clean for release

* ⬆️ Update dependency org.apache.logging.log4j:log4j-bom to v2.17.2 (#198)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* ⬆️ Update dependency com.sedmelluq:lavaplayer to v1.3.78 (#197)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-06-30 18:36:21 +02:00
7965a42ee5
Update build.yml 2022-06-29 16:43:29 +02:00
c376d376dd
Force build 2022-06-20 09:54:38 +02:00
92c30173cb
Migrate and disable other over18 commands 2022-05-16 18:32:03 +02:00
a41b4c76f1
Migrate madame command to slash 2022-05-16 18:25:00 +02:00
02b19c98d2
Migrate rank command to slash 2022-05-16 17:14:31 +02:00
97ac19873d
Remove invite command 2022-05-16 17:12:59 +02:00
fc3b89af9c
Add music control via button 2022-05-16 14:13:10 +02:00
32ba05bf99
Change music message 2022-05-16 12:14:07 +02:00
79c6f1b5ae
Change add music + music info display 2022-05-15 22:44:38 +02:00
d9d5e5d880
Migrate invite to slash command 2022-05-15 19:06:55 +02:00
872dde7695
Migrate clear slashcommand 2022-05-15 18:39:46 +02:00
9517a0a318
Format 2022-05-15 16:54:34 +02:00
12230218df
Disable plain jar 2022-05-15 16:49:55 +02:00
35093a1bd1
Fix build 2022-05-15 16:40:00 +02:00
4118116ee9
Migrate music to slash command 2022-05-15 14:37:20 +02:00
9d50e4c95f First Slash command + Move to java 17 2022-05-13 17:55:22 +02:00
e67e2ecda3
Delete dependabot.yml 2022-05-04 11:14:47 +02:00
renovate[bot]
13f9183106
Add renovate.json (#168)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-05-04 11:14:31 +02:00
103381e5ac
Delete Pipe.java 2022-01-20 21:33:32 +01:00
7f25b9ba7b
Update build.gradle 2022-01-20 21:26:32 +01:00
dependabot[bot]
f4b6ef20b4
Bump JDA from 4.2.1_264 to 4.2.1_266 (#80)
Bumps JDA from 4.2.1_264 to 4.2.1_266.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-31 10:56:16 +02:00
dependabot[bot]
1746f3d19d
Bump lavaplayer from 1.3.76 to 1.3.77 (#79)
Bumps lavaplayer from 1.3.76 to 1.3.77.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-31 10:53:54 +02:00
dependabot[bot]
005d9e68cf
Bump google-api-client from 1.31.4 to 1.31.5 (#74)
Bumps [google-api-client](https://github.com/googleapis/google-api-java-client) from 1.31.4 to 1.31.5.
- [Release notes](https://github.com/googleapis/google-api-java-client/releases)
- [Changelog](https://github.com/googleapis/google-api-java-client/blob/master/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-java-client/compare/v1.31.4...v1.31.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-18 09:35:02 +02:00
dependabot[bot]
ff6bbecde2
Bump spring-security-web from 5.4.6 to 5.5.0 (#75)
Bumps [spring-security-web](https://github.com/spring-projects/spring-security) from 5.4.6 to 5.5.0.
- [Release notes](https://github.com/spring-projects/spring-security/releases)
- [Changelog](https://github.com/spring-projects/spring-security/blob/main/RELEASE.adoc)
- [Commits](https://github.com/spring-projects/spring-security/compare/5.4.6...5.5.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-18 09:34:53 +02:00
dependabot[bot]
2ea09339b7
Bump JDA from 4.2.1_262 to 4.2.1_264 (#76)
Bumps JDA from 4.2.1_262 to 4.2.1_264.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-18 09:34:42 +02:00
Alexandre64
3a9eb35eb4 Added new command
//TODO do the help about it
2021-05-05 22:54:41 +02:00
dependabot[bot]
1b0f169d93
Bump JDA from 4.2.0_247 to 4.2.1_262 (#73)
Bumps JDA from 4.2.0_247 to 4.2.1_262.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-29 21:09:37 +02:00
dependabot[bot]
b7c4ed8eb3
Bump groovy-all from 3.0.7 to 3.0.8 (#72)
Bumps [groovy-all](https://github.com/apache/groovy) from 3.0.7 to 3.0.8.
- [Release notes](https://github.com/apache/groovy/releases)
- [Commits](https://github.com/apache/groovy/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-29 21:08:47 +02:00
dependabot[bot]
15e1f13514
Bump org.springframework.boot from 2.4.4 to 2.4.5 (#71)
Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.4.4 to 2.4.5.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.4.4...v2.4.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-29 21:08:35 +02:00
dependabot[bot]
243c4139be
Bump google-api-services-youtube (#70)
Bumps google-api-services-youtube from v3-rev20210210-1.31.0 to v3-rev20210410-1.31.0.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-29 21:08:06 +02:00
dependabot[bot]
af56df949c
Bump spring-security-web from 5.4.5 to 5.4.6 (#69)
Bumps [spring-security-web](https://github.com/spring-projects/spring-security) from 5.4.5 to 5.4.6.
- [Release notes](https://github.com/spring-projects/spring-security/releases)
- [Changelog](https://github.com/spring-projects/spring-security/blob/master/RELEASE.adoc)
- [Commits](https://github.com/spring-projects/spring-security/compare/5.4.5...5.4.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-29 19:35:26 +02:00
dependabot[bot]
9d63f03b89
Bump google-api-client from 1.31.3 to 1.31.4 (#67)
Bumps [google-api-client](https://github.com/googleapis/google-api-java-client) from 1.31.3 to 1.31.4.
- [Release notes](https://github.com/googleapis/google-api-java-client/releases)
- [Changelog](https://github.com/googleapis/google-api-java-client/blob/master/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-java-client/compare/v1.31.3...v1.31.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-29 19:35:10 +02:00
2bfe22bb87
Update Lavaplayer 2021-04-29 19:03:47 +02:00
dependabot[bot]
2969e29797
Bump JDA from 4.2.0_231 to 4.2.0_247 (#65)
Bumps JDA from 4.2.0_231 to 4.2.0_247.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-23 14:23:07 +01:00
dependabot[bot]
3834a3e39b
Bump org.springframework.boot from 2.4.3 to 2.4.4 (#63)
Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.4.3 to 2.4.4.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.4.3...v2.4.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-23 14:22:35 +01:00
dependabot[bot]
cbd311d87f
Bump json from 20201115 to 20210307 (#60)
Bumps [json](https://github.com/douglascrockford/JSON-java) from 20201115 to 20210307.
- [Release notes](https://github.com/douglascrockford/JSON-java/releases)
- [Commits](https://github.com/douglascrockford/JSON-java/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-23 14:20:06 +01:00
dependabot[bot]
2e45f8be43
Bump lavaplayer from 1.3.72 to 1.3.73 (#57)
Bumps lavaplayer from 1.3.72 to 1.3.73.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-23 14:19:54 +01:00
cdce2e836f Fix loading issue in stats page 2021-03-06 17:00:22 +01:00
eb0c1cf083 Fix issue if auto voice channel title is not defined 2021-03-06 16:14:33 +01:00
74f8fb2306 Remove useless code used by "Visible voice channel" Setting 2021-03-06 16:14:03 +01:00
25374821e1 Show only channel where the user can conect in music web page 2021-03-06 16:13:15 +01:00
dependabot[bot]
1dd98ae419
Bump lavaplayer from 1.3.71 to 1.3.72 (#55)
Bumps lavaplayer from 1.3.71 to 1.3.72.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-04 09:50:28 +01:00
dependabot[bot]
068091b091
Bump google-api-client from 1.31.2 to 1.31.3 (#51)
Bumps [google-api-client](https://github.com/googleapis/google-api-java-client) from 1.31.2 to 1.31.3.
- [Release notes](https://github.com/googleapis/google-api-java-client/releases)
- [Changelog](https://github.com/googleapis/google-api-java-client/blob/master/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-api-java-client/compare/v1.31.2...v1.31.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-04 09:50:17 +01:00
dependabot[bot]
93a8943e31
Bump org.springframework.boot from 2.4.2 to 2.4.3 (#49)
Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.4.2 to 2.4.3.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.4.2...v2.4.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-04 09:50:04 +01:00
dependabot[bot]
ae1bd6dc98
Bump spring-security-web from 5.4.4 to 5.4.5 (#48)
Bumps [spring-security-web](https://github.com/spring-projects/spring-security) from 5.4.4 to 5.4.5.
- [Release notes](https://github.com/spring-projects/spring-security/releases)
- [Commits](https://github.com/spring-projects/spring-security/compare/5.4.4...5.4.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-04 09:21:21 +01:00
dependabot[bot]
f9656d407b
Bump commons-lang3 from 3.11 to 3.12.0 (#52)
Bumps commons-lang3 from 3.11 to 3.12.0.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-04 09:21:03 +01:00
dependabot[bot]
bf48c0b1b7
Bump JDA from 4.2.0_228 to 4.2.0_231 (#54)
Bumps JDA from 4.2.0_228 to 4.2.0_231.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-04 09:20:45 +01:00
7a31b4f645 Fix channel not decrement 2021-02-18 18:09:42 +01:00
Sebastien Clement
1a4899c1cf Fix channel position 2021-02-18 17:07:35 +01:00
Sebastien Clement
023afb7323 Remove build id in ci 2021-02-18 16:35:31 +01:00
Sebastien Clement
e36bd805ea Switch to github cr 2021-02-18 15:21:59 +01:00
Sebastien Clement
b8a12a061f Add description on setting page 2021-02-18 14:58:06 +01:00
Sebastien Clement
2ddf973299 Add auto create voice channels 2021-02-18 14:48:58 +01:00
dependabot[bot]
dbf4f43019
Bump reflections from 0.9.11 to 0.9.12 (#46)
Bumps [reflections](https://github.com/ronmamo/reflections) from 0.9.11 to 0.9.12.
- [Release notes](https://github.com/ronmamo/reflections/releases)
- [Commits](https://github.com/ronmamo/reflections/compare/0.9.11...0.9.12)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-17 13:42:46 +01:00
dependabot[bot]
daad4bdbc2
Bump spring-security-web from 5.0.1.RELEASE to 5.4.4 (#47)
Bumps [spring-security-web](https://github.com/spring-projects/spring-security) from 5.0.1.RELEASE to 5.4.4.
- [Release notes](https://github.com/spring-projects/spring-security/releases)
- [Commits](https://github.com/spring-projects/spring-security/compare/5.0.1.RELEASE...5.4.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-17 13:42:11 +01:00
96d40814b1 Update youtube api 2021-02-17 13:37:55 +01:00
dependabot[bot]
26f6edfee7
Bump json from 20160810 to 20201115 (#42)
Bumps [json](https://github.com/douglascrockford/JSON-java) from 20160810 to 20201115.
- [Release notes](https://github.com/douglascrockford/JSON-java/releases)
- [Commits](https://github.com/douglascrockford/JSON-java/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-17 11:04:22 +01:00
dependabot[bot]
cbc4231907
Bump io.spring.dependency-management (#44)
Bumps io.spring.dependency-management from 1.0.9.RELEASE to 1.0.11.RELEASE.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-17 11:02:12 +01:00
dependabot[bot]
150aae4ff5
Bump JDA from 4.2.0_214 to 4.2.0_228 (#45)
Bumps JDA from 4.2.0_214 to 4.2.0_228.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-17 11:01:54 +01:00
dependabot[bot]
b6546a8a08
Bump org.springframework.boot from 2.3.5.RELEASE to 2.4.2 (#40)
Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 2.3.5.RELEASE to 2.4.2.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.5.RELEASE...v2.4.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-16 12:32:38 +01:00
dependabot[bot]
ac0258c7d2
Bump jsoup from 1.12.1 to 1.13.1 (#39)
Bumps [jsoup](https://github.com/jhy/jsoup) from 1.12.1 to 1.13.1.
- [Release notes](https://github.com/jhy/jsoup/releases)
- [Changelog](https://github.com/jhy/jsoup/blob/master/CHANGES)
- [Commits](https://github.com/jhy/jsoup/compare/jsoup-1.12.1...jsoup-1.13.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-16 12:32:21 +01:00
dependabot[bot]
ea66b856d8
Bump lavaplayer from 1.3.61 to 1.3.71 (#38)
Bumps lavaplayer from 1.3.61 to 1.3.71.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-16 12:32:03 +01:00
dependabot[bot]
bf6ae21961
Bump groovy-all from 2.4.15 to 3.0.7 (#37)
Bumps [groovy-all](https://github.com/apache/groovy) from 2.4.15 to 3.0.7.
- [Release notes](https://github.com/apache/groovy/releases)
- [Commits](https://github.com/apache/groovy/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-16 12:31:47 +01:00
dependabot[bot]
1a7dc4e197
Bump commons-lang3 from 3.7 to 3.11 (#36)
Bumps commons-lang3 from 3.7 to 3.11.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-16 12:31:25 +01:00
3d758304a0 Docker push only from master 2021-02-16 12:30:37 +01:00
617048afa3
Create dependabot.yml 2021-02-16 12:25:45 +01:00
Alexandre64
d131d55aee Added args to send back only before a date in channelsreview 2021-01-09 16:00:54 +01:00
Alexandre64
f03cfbc7ba Merge branch 'develop' 2021-01-09 16:00:25 +01:00
285 changed files with 4851 additions and 37454 deletions

23
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,23 @@
# [Choice] Java version (use -bullseye variants on local arm64/Apple Silicon): 11, 17, 11-bullseye, 17-bullseye, 11-buster, 17-buster
ARG VARIANT=11-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/java:0-${VARIANT}
# [Option] Install Maven
ARG INSTALL_MAVEN="false"
ARG MAVEN_VERSION=""
# [Option] Install Gradle
ARG INSTALL_GRADLE="false"
ARG GRADLE_VERSION=""
RUN if [ "${INSTALL_MAVEN}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install maven \"${MAVEN_VERSION}\""; fi \
&& if [ "${INSTALL_GRADLE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install gradle \"${GRADLE_VERSION}\""; fi
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
ARG NODE_VERSION="none"
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1

View File

@ -0,0 +1,30 @@
{
"name": "Java & Mariadb",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
// Set *default* container specific settings.json values on container create.
"settings": {
"java.jdt.ls.java.home": "/docker-java-home"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"vscjava.vscode-java-pack",
"pivotal.vscode-boot-dev-pack",
"richardwillis.vscode-gradle-extension-pack",
"eamodio.gitlens",
"donjayamanne.githistory"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// This can be used to network with other containers or with the host.
// "forwardPorts": [5432],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "java -version",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}

View File

@ -0,0 +1,48 @@
version: '3.8'
volumes:
mysql-data:
services:
app:
container_name: javadev
build:
context: .
dockerfile: Dockerfile
args:
# Update 'VARIANT' to pick an version of Java: 11, 17.
# Append -bullseye or -buster to pin to an OS version.
# Use -bullseye variants on local arm64/Apple Silicon.
VARIANT: "17"
# Options
INSTALL_MAVEN: "false"
MAVEN_VERSION: ""
INSTALL_GRADLE: "true"
GRADLE_VERSION: "7.4.2"
NODE_VERSION: "lts/*"
volumes:
- ..:/workspace:cached
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
network_mode: service:db
# Uncomment the next line to use a non-root user for all processes.
# user: vscode
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)
db:
container_name: database
image: mariadb:latest
restart: unless-stopped
volumes:
- mysql-data:/var/lib/mysql
environment:
MARIADB_ROOT_PASSWORD: mariadb_root
MARIADB_PASSWORD: claptrap
MARIADB_USER: claptrap
MARIADB_DATABASE: claptrap
# Add "forwardPorts": ["5432"] to **devcontainer.json** to forward PostgreSQL locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)

View File

@ -5,9 +5,10 @@ name: Build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
branches-ignore:
- "renovate/**"
tags-ignore:
- "**"
jobs:
build-gradle:
@ -15,37 +16,63 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: 1.8
distribution: 'temurin'
java-version: 17
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Upload Jar File
uses: actions/upload-artifact@v2-preview
with:
name: claptrap_jar
path: build/libs/
build-docker:
runs-on: [ubuntu-latest]
needs: [build-gradle]
runs-on: ubuntu-latest
needs:
- build-gradle
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Download artifact
uses: actions/download-artifact@v1.0.0
uses: actions/download-artifact@v3.0.0
with:
# Artifact name
name: claptrap_jar
# Destination path
path: build/libs/
- name: Publish Docker
uses: elgohr/Publish-Docker-Github-Action@master
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to ghcr.io
uses: docker/login-action@v2
with:
name: brokenfire/brokendiscordbot
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
tags: latest,${{ env.GITHUB_RUN_ID}}
buildargs: GITHUB_RUN_NUMBER=${{env.RELEASE_VERSION}}
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.CR_PAT }}
- name: Get branch name
id: branch-name
uses: tj-actions/branch-names@v5.4
- name: Set tag
run: |
echo "tag=${{ steps.branch-name.outputs.current_branch }}" >> $GITHUB_ENV
- name: Build and push Docker
uses: docker/build-push-action@v3
with:
push: true
context: .
tags: "ghcr.io/sebclem/claptrapbot:${{ env.tag }}"
file: ./Dockerfile

78
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,78 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Build Release
on:
push:
tags:
- "**"
jobs:
build-gradle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: 17
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Upload Jar File
uses: actions/upload-artifact@v2-preview
with:
name: claptrap_jar
path: build/libs/
build-docker:
runs-on: ubuntu-latest
needs:
- build-gradle
steps:
- uses: actions/checkout@v3
- name: Download artifact
uses: actions/download-artifact@v3.0.0
with:
# Artifact name
name: claptrap_jar
# Destination path
path: build/libs/
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to ghcr.io
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.CR_PAT }}
- name: Get branch name
id: branch-name
uses: tj-actions/branch-names@v5.4
- name: Set tag
run: |
echo "tag=${{ steps.branch-name.outputs.tag }}" >> $GITHUB_ENV
- name: Build and push Docker
uses: docker/build-push-action@v3
with:
push: true
context: .
tags: |
ghcr.io/sebclem/claptrapbot:${{ env.tag }}
ghcr.io/sebclem/claptrapbot:latest
file: ./Dockerfile

8
.gitignore vendored
View File

@ -26,3 +26,11 @@ src/main/resources/templates/js
src/main/resources/static/error/css
src/main/resources/static/error/js
**.log
.jpb/
**/*.env
bin/

17
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,17 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Launch MainBot",
"request": "launch",
"mainClass": "net.Broken.MainBot",
"projectName": "ClaptrapBot",
"envFile": "${workspaceFolder}/.env"
},
]
}

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "automatic"
}

View File

@ -1,11 +1,10 @@
FROM openjdk:8-jre-buster
FROM openjdk:18.0.1
WORKDIR /bot_src
ARG BUILD_NBR
ARG BRANCH_NAME
ARG BRANCH_NAME
ARG GITHUB_RUN_NUMBER
ADD build/libs/ClaptrapBot-*.jar /bot_src/bot.jar
ADD build/libs/ClaptrapBot.jar /bot_src/claptrapbot.jar
RUN java -version
ENV PORT=8080
ENV TOKEN=10
CMD java -jar bot.jar -t ${TOKEN}
CMD java -jar claptrapbot.jar
LABEL org.opencontainers.image.source=https://github.com/Sebclem/ClaptrapBot/

View File

@ -1,19 +0,0 @@
#!/bin/bash
#This script download the last stable build on jenkins
echo "Branch: "$1
if [[ $1 = "master" ]]
then
base_url="https://jenkins.seb6596.ovh/job/Bot%20Discord%20Gradle/lastStableBuild"
else
base_url="https://jenkins.seb6596.ovh/job/Bot%20Discord%20Gradle%20Devel/lastStableBuild/"
fi
data=$(curl -s -g ${base_url}"/api/xml?xpath=/freeStyleBuild/artifact&wrapper=artifacts")
relativePath=$(grep -oPm1 "(?<=<relativePath>)[^<]+" <<< "$data")
jarFile=$(grep -oPm1 "(?<=<fileName>)[^<]+" <<< "$data")
wget ${base_url}"/artifact/"${relativePath} -O bot.jar -nv

View File

@ -1,6 +1,8 @@
<p align="center"><img alt="discord" src="https://claptrapbot.com/favicon.png" width="150"/></p>
# ClaptrapBot: A multifunctional Discord Bot !
[![GitHub Release][releases-shield]][releases]
![Project Stage][project-stage-shield]
[![License][license-shield]](LICENSE.md)
@ -9,16 +11,20 @@
![Project Maintenance][maintenance-shield]
[![Buy me a coffee][buymeacoffee-shield]][buymeacoffee]
## About
ClaptrapBot is a Discord bot. (No way! :open_mouth:)
### Features:
- :notes: Music bot with a cool web control interface !
- :bar_chart: Rank and Stats ! (Text and voice)
- :heart_eyes: NSFW Commands ! (With a daily surprise :kissing_heart:)
- :hammer_and_pick: Moderation commands !
You can add the bot to your server from the home page: https://claptrapbot.com/
## Authors & contributors
The original development is by [SebClem][Sebclem].
@ -55,19 +61,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
[license-shield]: https://img.shields.io/github/license/Sebclem/ClaptrapBot.svg
[build-badge]: https://img.shields.io/github/workflow/status/Sebclem/ClaptrapBot/Build
[maintenance-shield]: https://img.shields.io/maintenance/yes/2020.svg
[maintenance-shield]: https://img.shields.io/maintenance/yes/2022.svg
[project-stage-shield]: https://img.shields.io/badge/project%20stage-Beta-red.svg
[buymeacoffee-shield]: https://www.buymeacoffee.com/assets/img/guidelines/download-assets-sm-2.svg
[buymeacoffee]: https://www.buymeacoffee.com/seb6596
[issue]: https://github.com/hassio-addons/addon-log-viewer/issues
[releases-shield]: https://img.shields.io/github/release/Sebclem/ClaptrapBot.svg?include_prereleases
[releases]: https://github.com/Sebclem/ClaptrapBot/releases
[Sebclem]: https://github.com/Sebclem
[alex]: https://github.com/Alexandre064
[Aeka]: https://twitter.com/Le_aeka
[contributors]: https://github.com/Sebclem/ClaptrapBot/graphs/contributors

View File

@ -1,90 +1,87 @@
plugins {
id 'org.springframework.boot' version '2.3.5.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'org.springframework.boot' version '2.7.2'
id 'io.spring.dependency-management' version '1.0.12.RELEASE'
id 'java'
id 'groovy'
id 'org.liquibase.gradle' version '2.1.1'
id "nebula.lint" version "17.7.0"
id "com.gorylenko.gradle-git-properties" version "2.4.1"
}
def versionObj = new Version(major: 0, minor: 2, revision: 0)
group = "net.broken"
archivesBaseName = "ClaptrapBot"
version = "$versionObj"
sourceCompatibility = 1.8
targetCompatibility = 1.8
jar.doFirst {
delete "${buildDir}/libs/*"
}
jar {
// delete "${buildDir}/libs/*"
// baseName = 'DiscordBot'
}
sourceCompatibility = '17'
repositories {
mavenCentral()
jcenter()
maven {
url 'https://m2.dv8tion.net/releases'
}
}
jar {
enabled(false)
}
javadoc {
source = sourceSets.main.allJava
classpath = configurations.compile
configurations.implementation {
exclude group: "org.springframework.boot", module: "spring-boot-starter-logging"
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web"){
exclude group:"org.springframework.boot", module: "spring-boot-starter-logging"
exclude group: "org.springframework.boot", module :"spring-boot-starter-tomcat"
}
compile("org.springframework.boot:spring-boot-starter-undertow")
compile("org.springframework.boot:spring-boot-starter-log4j2")
implementation 'org.codehaus.groovy:groovy-all:2.4.15'
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-log4j2")
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
implementation('org.springframework.boot:spring-boot-starter-actuator')
implementation('io.micrometer:micrometer-registry-prometheus:1.9.2')
implementation('org.springdoc:springdoc-openapi-ui:1.6.9')
implementation('org.springdoc:springdoc-openapi-security:1.6.9')
implementation('org.liquibase:liquibase-core')
implementation('io.jsonwebtoken:jjwt-api:0.11.5')
implementation('io.jsonwebtoken:jjwt-impl:0.11.5')
implementation('io.jsonwebtoken:jjwt-jackson:0.11.5')
implementation('com.sedmelluq:lavaplayer:1.3.78')
implementation('net.dv8tion:JDA:4.4.1_353')
implementation(platform("org.apache.logging.log4j:log4j-bom:2.18.0"))
implementation group: 'org.hibernate', name: 'hibernate-validator', version: '7.0.4.Final'
compile("com.sedmelluq:lavaplayer:1.3.61")
// compile 'net.dv8tion:JDA:4.0.0_46'
compile 'net.dv8tion:JDA:4.2.0_214'
compile group: 'org.json', name: 'json', version: '20160810'
compile 'org.springframework.security:spring-security-web:5.0.1.RELEASE'
// JPA Data (We are going to use Repositories, Entities, Hibernate, etc...)
compile("org.springframework.boot:spring-boot-starter-data-jpa") {
exclude group:"org.springframework.boot", module: "spring-boot-starter-logging"
}
// Use MySQL Connector-J
compile 'mysql:mysql-connector-java'
compile 'org.reflections:reflections:0.9.11'
compile 'org.apache.commons:commons-lang3:3.7'
compile 'com.google.api-client:google-api-client:1.23.0'
compile 'com.google.apis:google-api-services-youtube:v3-rev192-1.23.0'
implementation('mysql:mysql-connector-java:8.0.30')
implementation('org.reflections:reflections:0.10.2')
implementation('org.apache.commons:commons-lang3:3.12.0')
compile group: 'org.jsoup', name: 'jsoup', version: '1.12.1'
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('com.jayway.jsonpath:json-path')
liquibaseRuntime('org.liquibase:liquibase-core:4.14.0')
liquibaseRuntime('org.liquibase:liquibase-groovy-dsl:3.0.2')
liquibaseRuntime('mysql:mysql-connector-java:8.0.30')
liquibaseRuntime group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
liquibaseRuntime group: 'org.liquibase.ext', name: 'liquibase-hibernate5', version: '4.14.0'
liquibaseRuntime 'org.springframework.boot:spring-boot-starter-data-jpa'
liquibaseRuntime 'org.springframework.data:spring-data-jpa'
liquibaseRuntime 'org.springframework:spring-beans'
liquibaseRuntime 'net.dv8tion:JDA:4.4.0_352'
liquibaseRuntime 'com.sedmelluq:lavaplayer:1.3.78'
liquibaseRuntime sourceSets.main.output
compile("org.springframework.boot:spring-boot-starter-thymeleaf") {
exclude group:"org.springframework.boot", module: "spring-boot-starter-logging"
}
apply plugin: "org.liquibase.gradle"
configurations {
liquibaseRuntime.extendsFrom runtime
}
liquibase {
activities {
main {
changeLogFile "src/main/resources/db/changelog/db.changelog-master.yml"
url System.getenv("DB_URL")
referenceUrl 'hibernate:spring:net.Broken?dialect=org.hibernate.dialect.MySQL5Dialect&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy'
username System.getenv("DB_USER")
password System.getenv("DB_PWD")
}
}
class Version {
String major, minor, revision
static String getBuild() {
System.getenv("GITHUB_RUN_NUMBER") ?: System.getProperty("BUILD_NUMBER") ?:
System.getenv("GIT_COMMIT")?.substring(0, 7) ?: System.getProperty("GIT_COMMIT")?.substring(0, 7) ?:"DEV"
}
String toString() {
"${major}.${minor}.${revision}_$build"
}
}

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

6
renovate.json Normal file
View File

@ -0,0 +1,6 @@
{
"extends": [
"config:base"
],
"commitMessagePrefix": ":arrow_up:"
}

View File

@ -0,0 +1,83 @@
package net.Broken.Api.Controllers;
import net.Broken.Api.Data.Music.Add;
import net.Broken.Api.Data.Music.Connect;
import net.Broken.Api.Data.Music.Status;
import net.Broken.Api.Security.Data.JwtPrincipal;
import net.Broken.Api.Services.AudioService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.ExecutionException;
@RestController
@RequestMapping("/api/v2/audio")
@CrossOrigin(origins = "*", maxAge = 3600)
public class AudioController {
public final AudioService audioService;
public AudioController(AudioService audioService) {
this.audioService = audioService;
}
@GetMapping("/{guildId}/status")
@PreAuthorize("isInGuild(#guildId)")
public Status getMusicStatus(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.getGuildAudioStatus(guildId, principal.user().getDiscordId());
}
@PostMapping("/{guildId}/connect")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId, #body)")
public ResponseEntity<Status> connect(@PathVariable String guildId, @RequestBody Connect body, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.connect(guildId, body, principal.user().getDiscordId());
}
@PostMapping("/{guildId}/disconnect")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> disconnect(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.disconnect(guildId, principal.user().getDiscordId());
}
@PostMapping("/{guildId}/resume")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> resume(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.resume(guildId, principal.user().getDiscordId());
}
@PostMapping("/{guildId}/pause")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> pause(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.pause(guildId, principal.user().getDiscordId());
}
@PostMapping("/{guildId}/skip")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> skip(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.skip(guildId, principal.user().getDiscordId());
}
@PostMapping("/{guildId}/stop")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> stop(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.stop(guildId, principal.user().getDiscordId());
}
@PostMapping("/{guildId}/add")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> add(@PathVariable String guildId, @RequestBody Add body, Authentication authentication) throws ExecutionException, InterruptedException {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.add(guildId, principal.user().getDiscordId(), body);
}
}

View File

@ -0,0 +1,40 @@
package net.Broken.Api.Controllers;
import net.Broken.Api.Data.Login;
import net.Broken.Api.Security.Data.JwtResponse;
import net.Broken.Api.Security.Services.JwtService;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.UserRepository;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v2/auth")
@CrossOrigin(origins = "*", maxAge = 3600)
public class AuthController {
private final AuthenticationManager authenticationManager;
private final JwtService jwtService;
public AuthController(AuthenticationManager authenticationManager, UserRepository userRepository, JwtService jwtService) {
this.authenticationManager = authenticationManager;
this.jwtService = jwtService;
}
@PostMapping("/discord")
public JwtResponse loginDiscord(@Validated @RequestBody Login login) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(login.redirectUri(), login.code())
);
UserEntity user = (UserEntity) authentication.getPrincipal();
String jwt = jwtService.buildJwt(user);
return new JwtResponse(jwt);
}
}

View File

@ -0,0 +1,28 @@
package net.Broken.Api.Controllers;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v2")
@CrossOrigin(origins = "*", maxAge = 3600)
@Hidden
public class CrossOptionController {
/**
* For cross preflight request send by axios
*/
@RequestMapping(
value = "/**",
method = RequestMethod.OPTIONS
)
public ResponseEntity<String> handle() {
return new ResponseEntity<>("",HttpStatus.OK);
}
}

View File

@ -0,0 +1,62 @@
package net.Broken.Api.Controllers;
import java.util.List;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import net.Broken.Api.Data.InviteLink;
import net.Broken.Api.Data.Guild.Channel;
import net.Broken.Api.Data.Guild.Guild;
import net.Broken.Api.Data.Guild.Role;
import net.Broken.Api.Security.Data.JwtPrincipal;
import net.Broken.Api.Services.GuildService;
@RestController
@RequestMapping("/api/v2/guild")
@CrossOrigin(origins = "*", maxAge = 3600)
public class GuildController {
public final GuildService guildService;
public GuildController(GuildService guildService) {
this.guildService = guildService;
}
@GetMapping("mutual")
public List<Guild> getMutualGuilds(Authentication authentication) {
JwtPrincipal jwtPrincipal = (JwtPrincipal) authentication.getPrincipal();
return guildService.getMutualGuilds(jwtPrincipal.user());
}
@GetMapping("inviteLink")
public InviteLink getInviteLink() {
return new InviteLink(guildService.getInviteLink());
}
@GetMapping("/{guildId}/voiceChannels")
@PreAuthorize("isInGuild(#guildId)")
public List<Channel> getVoiceChannels(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return guildService.getVoiceChannel(guildId, principal.user().getDiscordId());
}
@GetMapping("/{guildId}/textChannels")
@PreAuthorize("isInGuild(#guildId)")
public List<Channel> getTextChannels(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return guildService.getTextChannel(guildId, principal.user().getDiscordId());
}
@GetMapping("/{guildId}/roles")
@PreAuthorize("isInGuild(#guildId)")
public List<Role> getRoles(@PathVariable String guildId) {
return guildService.getRole(guildId);
}
}

View File

@ -0,0 +1,40 @@
package net.Broken.Api.Controllers;
import net.Broken.Api.Data.Settings.SettingGroup;
import net.Broken.Api.Data.Settings.Value;
import net.Broken.Api.Services.SettingService;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.Tools.Settings.SettingValueBuilder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/v2/setting")
@CrossOrigin(origins = "*", maxAge = 3600)
public class SettingController {
public final SettingService settingService;
public SettingController(SettingService settingService) {
this.settingService = settingService;
}
@GetMapping("description")
public List<SettingGroup> getSettingDescription(){
return settingService.getSettingDescription();
}
@GetMapping("/{guildId}/values")
@PreAuthorize("isInGuild(#guildId) && canManageGuild(#guildId)")
public List<Value> getSettingValues(@PathVariable String guildId){
return settingService.getValues(guildId);
}
@PostMapping("/{guildId}/values")
@PreAuthorize("isInGuild(#guildId) && canManageGuild(#guildId)")
public List<Value> getSettingValues(@PathVariable String guildId, @RequestBody List<Value> values){
GuildPreferenceEntity pref = settingService.saveValue(guildId, values);
return new SettingValueBuilder(pref).build();
}
}

View File

@ -0,0 +1,4 @@
package net.Broken.Api.Data.Guild;
public record Channel(String id, String name) {
}

View File

@ -0,0 +1,4 @@
package net.Broken.Api.Data.Guild;
public record Guild(String id, String name, String iconUrl, boolean canManage) {
}

View File

@ -0,0 +1,4 @@
package net.Broken.Api.Data.Guild;
public record Role(String id, String name) {
}

View File

@ -0,0 +1,4 @@
package net.Broken.Api.Data;
public record InviteLink(String link) {
}

View File

@ -0,0 +1,8 @@
package net.Broken.Api.Data;
import javax.validation.constraints.NotBlank;
public record Login(
@NotBlank String code, @NotBlank String redirectUri) {
}

View File

@ -0,0 +1,4 @@
package net.Broken.Api.Data.Music;
public record Add(String url) {
}

View File

@ -0,0 +1,4 @@
package net.Broken.Api.Data.Music;
public record Connect(String channelId) {
}

View File

@ -0,0 +1,12 @@
package net.Broken.Api.Data.Music;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record PlayBackInfo(
Boolean paused,
Boolean stopped,
Long progress,
TrackInfo trackInfo
) {
}

View File

@ -0,0 +1,16 @@
package net.Broken.Api.Data.Music;
import com.fasterxml.jackson.annotation.JsonInclude;
import net.Broken.Api.Data.Guild.Channel;
import net.dv8tion.jda.api.audio.hooks.ConnectionStatus;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record Status(
Boolean connected,
ConnectionStatus connectionStatus,
Channel channel,
Boolean canView,
Boolean canInteract,
PlayBackInfo playBackInfo
) {
}

View File

@ -0,0 +1,13 @@
package net.Broken.Api.Data.Music;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import net.Broken.Api.Data.UserInfo;
import net.Broken.Audio.UserAudioTrack;
public record TrackInfo(UserInfo submitter, AudioTrackInfo detail) {
public TrackInfo(UserAudioTrack userAudioTrack) {
this(new UserInfo(userAudioTrack.getSubmittedUser().getId(), userAudioTrack.getSubmittedUser().getName(), userAudioTrack.getSubmittedUser().getAvatarUrl()),
userAudioTrack.getAudioTrack().getInfo());
}
}

View File

@ -0,0 +1,16 @@
package net.Broken.Api.Data.Settings;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record SettingDescriber(
String id,
String name,
String description,
TYPE type
) {
public enum TYPE {
BOOL, LIST, STRING, ROLE, TEXT_CHANNEL, VOICE_CHANNEL
}
}

View File

@ -0,0 +1,13 @@
package net.Broken.Api.Data.Settings;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record SettingGroup(
String name,
SettingDescriber mainField,
List<SettingDescriber> fields
) {
}

View File

@ -0,0 +1,4 @@
package net.Broken.Api.Data.Settings;
public record Value(String id, Object value) {
}

View File

@ -0,0 +1,8 @@
package net.Broken.Api.Data;
public record UserInfo(
String id,
String username,
String avatar
) {
}

View File

@ -0,0 +1,35 @@
package net.Broken.Api.OpenApi;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import net.Broken.VersionLoader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OpenApiConfig {
private final VersionLoader versionLoader;
public OpenApiConfig(VersionLoader version) {
this.versionLoader = version;
}
@Bean
public OpenAPI customOpenAPI() {
final String securitySchemeName = "JWT";
return new OpenAPI().addSecurityItem(
new SecurityRequirement().addList(securitySchemeName)).components(
new Components().addSecuritySchemes(
securitySchemeName,
new SecurityScheme().name(securitySchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT"))
).addServersItem(new Server().url("/").description("Default"))
.info(new Info().title("ClaptrapBot API").version(versionLoader.getVersion()));
}
}

View File

@ -0,0 +1,47 @@
package net.Broken.Api.Security.Components;
import net.Broken.Api.Security.Data.DiscordOauthUserInfo;
import net.Broken.Api.Security.Exceptions.OAuthLoginFail;
import net.Broken.Api.Security.Services.DiscordOauthService;
import net.Broken.DB.Entity.UserEntity;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
@Component
public class DiscordAuthenticationProvider implements AuthenticationProvider {
private final DiscordOauthService discordOauthService;
public DiscordAuthenticationProvider(DiscordOauthService discordOauthService) {
this.discordOauthService = discordOauthService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String redirectUri = authentication.getPrincipal().toString();
String code = authentication.getCredentials().toString();
try {
String token = discordOauthService.getAccessToken(code, redirectUri);
DiscordOauthUserInfo discordOauthUserInfo = discordOauthService.getUserInfo(token);
discordOauthService.revokeToken(token);
DiscordOauthService.LoginOrRegisterResponse<UserEntity> loginOrRegisterResponse = discordOauthService.loginOrRegisterDiscordUser(discordOauthUserInfo);
UserEntity userEntity = loginOrRegisterResponse.response();
if(!loginOrRegisterResponse.created()){
userEntity = discordOauthService.updateUserInfo(discordOauthUserInfo, loginOrRegisterResponse.response());
}
return new UsernamePasswordAuthenticationToken(userEntity, null, new ArrayList<>());
} catch (OAuthLoginFail e) {
throw new BadCredentialsException("Bad response form Discord Oauth server ! Code expired ?");
}
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}

View File

@ -0,0 +1,37 @@
package net.Broken.Api.Security.Components;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Component
public class UnauthorizedHandler implements AuthenticationEntryPoint {
private final Logger logger = LogManager.getLogger();
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
logger.error("[API] Unauthorized error: {}", authException.getMessage());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
final Map<String, Object> body = new HashMap<>();
body.put("status", HttpServletResponse.SC_UNAUTHORIZED);
body.put("error", "Unauthorized");
body.put("message", authException.getMessage());
body.put("path", request.getServletPath());
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), body);
}
}

View File

@ -0,0 +1,10 @@
package net.Broken.Api.Security.Data;
public record AccessTokenResponse(
String access_token,
String token_type,
String expires_in,
String refresh_token,
String scope
) {
}

View File

@ -0,0 +1,12 @@
package net.Broken.Api.Security.Data;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public record DiscordOauthUserInfo(
String id,
String username,
String discriminator,
String avatar) {
}

View File

@ -0,0 +1,6 @@
package net.Broken.Api.Security.Data;
import net.Broken.DB.Entity.UserEntity;
public record JwtPrincipal(String jwtId, UserEntity user) {
}

View File

@ -0,0 +1,5 @@
package net.Broken.Api.Security.Data;
public record JwtResponse(String token) {
}

View File

@ -0,0 +1,4 @@
package net.Broken.Api.Security.Exceptions;
public class OAuthLoginFail extends Exception{
}

View File

@ -0,0 +1,25 @@
package net.Broken.Api.Security.Expression;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
public class CustomMethodSecurityExpressionHandler
extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver =
new AuthenticationTrustResolverImpl();
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(
Authentication authentication, MethodInvocation invocation) {
CustomMethodSecurityExpressionRoot root =
new CustomMethodSecurityExpressionRoot(authentication);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}

View File

@ -0,0 +1,102 @@
package net.Broken.Api.Security.Expression;
import net.Broken.Api.Data.Music.Connect;
import net.Broken.Api.Security.Data.JwtPrincipal;
import net.Broken.Audio.GuildAudioBotService;
import net.Broken.MainBot;
import net.Broken.Tools.CacheTools;
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.VoiceChannel;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.core.Authentication;
public class CustomMethodSecurityExpressionRoot
extends SecurityExpressionRoot
implements MethodSecurityExpressionOperations {
private Object filterObject;
private Object returnObject;
/**
* Creates a new instance
*
* @param authentication the {@link Authentication} to use. Cannot be null.
*/
public CustomMethodSecurityExpressionRoot(Authentication authentication) {
super(authentication);
}
public boolean isInGuild(String guildId){
JwtPrincipal jwtPrincipal = (JwtPrincipal) authentication.getPrincipal();
Guild guild = MainBot.jda.getGuildById(guildId);
return CacheTools.getJdaUser(jwtPrincipal.user()).getMutualGuilds().contains(guild);
}
public boolean canManageGuild(String guildId){
JwtPrincipal jwtPrincipal = (JwtPrincipal) authentication.getPrincipal();
Member member = MainBot.jda.getGuildById(guildId).getMemberById(jwtPrincipal.user().getDiscordId());
return member.hasPermission(
Permission.MANAGE_SERVER,
Permission.MANAGE_PERMISSIONS,
Permission.MANAGE_CHANNEL
);
}
public boolean canInteractWithVoiceChannel(String guildId, Connect connectPayload){
JwtPrincipal jwtPrincipal = (JwtPrincipal) authentication.getPrincipal();
Guild guild = MainBot.jda.getGuildById(guildId);
Member member = guild.getMemberById(jwtPrincipal.user().getDiscordId());
VoiceChannel channel = guild.getVoiceChannelById(connectPayload.channelId());
if( channel == null){
return false;
}
return (member.hasPermission(channel, Permission.VOICE_CONNECT)
|| member.getVoiceState() != null
&& member.getVoiceState().getChannel() == channel)
&& member.hasPermission(channel, Permission.VOICE_SPEAK);
}
public boolean canInteractWithVoiceChannel(String guildId) {
JwtPrincipal jwtPrincipal = (JwtPrincipal) authentication.getPrincipal();
Guild guild = MainBot.jda.getGuildById(guildId);
GuildAudioBotService guildAudioBotService = GuildAudioBotService.getInstance(guild);
VoiceChannel channel = guild.getAudioManager().getConnectedChannel();
if (channel == null) {
return false;
}
Member member = guild.getMemberById(jwtPrincipal.user().getDiscordId());
return (member.hasPermission(channel, Permission.VOICE_CONNECT)
|| member.getVoiceState() != null
&& member.getVoiceState().getChannel() == channel)
&& member.hasPermission(channel, Permission.VOICE_SPEAK);
}
@Override
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
@Override
public Object getFilterObject() {
return this.filterObject;
}
@Override
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
@Override
public Object getReturnObject() {
return this.returnObject;
}
@Override
public Object getThis() {
return this;
}
}

View File

@ -0,0 +1,60 @@
package net.Broken.Api.Security.Filters;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import net.Broken.Api.Security.Data.JwtPrincipal;
import net.Broken.Api.Security.Services.JwtService;
import net.Broken.BotConfigLoader;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.UserRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
public class JwtFilter extends OncePerRequestFilter {
@Autowired
private JwtService jwtService;
@Autowired
private BotConfigLoader config;
@Autowired
private UserRepository userRepository;
private final Logger logger = LogManager.getLogger();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.replace("Bearer ", "");
try {
UserEntity user;
JwtPrincipal principal;
if(config.mode().equals("DEV")){
user = userRepository.findByDiscordId(token).orElseThrow();
principal = new JwtPrincipal("DEV", user);
}
else {
Jws<Claims> jwt = jwtService.verifyAndParseJwt(token);
user = jwtService.getUserWithJwt(jwt);
principal = new JwtPrincipal(jwt.getBody().getId(), user);
}
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(principal, null, new ArrayList<>());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
} catch (Exception e) {
logger.warn("[JWT] Cannot set user authentication: " + e);
}
}
filterChain.doFilter(request, response);
}
}

View File

@ -0,0 +1,16 @@
package net.Broken.Api.Security;
import net.Broken.Api.Security.Expression.CustomMethodSecurityExpressionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new CustomMethodSecurityExpressionHandler();
}
}

View File

@ -0,0 +1,51 @@
package net.Broken.Api.Security;
import net.Broken.Api.Security.Components.UnauthorizedHandler;
import net.Broken.Api.Security.Filters.JwtFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UnauthorizedHandler unauthorizedHandler;
public SecurityConfig(UnauthorizedHandler unauthorizedHandler) {
this.unauthorizedHandler = unauthorizedHandler;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/api/v2/auth/**").permitAll()
.antMatchers("/api/v2/guild/inviteLink").permitAll()
.antMatchers("/swagger-ui/**").permitAll()
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/v3/api-docs/**").permitAll()
.antMatchers("/actuator/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public JwtFilter jwtFilter(){
return new JwtFilter();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}

View File

@ -0,0 +1,172 @@
package net.Broken.Api.Security.Services;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.Broken.Api.Security.Data.AccessTokenResponse;
import net.Broken.Api.Security.Data.DiscordOauthUserInfo;
import net.Broken.Api.Security.Exceptions.OAuthLoginFail;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.UserRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@Service
public class DiscordOauthService {
private final Logger logger = LogManager.getLogger();
@Value("${discord.oauth.client-id}")
private String clientId;
@Value("${discord.oauth.client-secret}")
private String clientSecret;
@Value("${discord.oauth.token-endpoint}")
private String tokenEndpoint;
@Value("${discord.oauth.tokenRevokeEndpoint}")
private String tokenRevokeEndpoint;
@Value("${discord.oauth.userInfoEnpoint}")
private String userInfoEnpoint;
private final UserRepository userRepository;
public DiscordOauthService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public String getAccessToken(String code, String redirectUrl) throws OAuthLoginFail {
logger.debug("[OAUTH] Getting access token");
HashMap<String, String> data = new HashMap<>();
data.put("client_id", this.clientId);
data.put("client_secret", this.clientSecret);
data.put("grant_type", "authorization_code");
data.put("code", code);
data.put("redirect_uri", redirectUrl);
try {
HttpResponse<String> response = makeFormPost(this.tokenEndpoint, data);
if (response.statusCode() != 200) {
logger.warn("[OAUTH] Invalid response while getting AccessToken: Status Code: " + response.statusCode() + " Body:" + response.body());
throw new OAuthLoginFail();
}
ObjectMapper objectMapper = new ObjectMapper();
AccessTokenResponse accessTokenResponse = objectMapper.readValue(response.body(), AccessTokenResponse.class);
return accessTokenResponse.access_token();
} catch (IOException | InterruptedException e) {
logger.catching(e);
throw new OAuthLoginFail();
}
}
public DiscordOauthUserInfo getUserInfo(String token) throws OAuthLoginFail {
logger.debug("[OAUTH] Getting user info");
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(this.userInfoEnpoint))
.header("Authorization", "Bearer " + token)
.GET()
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
logger.warn("[OAUTH] Invalid response while getting UserInfo: Status Code: " + response.statusCode() + " Body:" + response.body());
throw new OAuthLoginFail();
}
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(response.body(), DiscordOauthUserInfo.class);
} catch (IOException | InterruptedException e) {
logger.catching(e);
throw new OAuthLoginFail();
}
}
public void revokeToken(String token) {
logger.debug("[OAUTH] Revoking access token");
HashMap<String, String> data = new HashMap<>();
data.put("token", token);
try {
HttpResponse<String> response = makeFormPost(this.tokenRevokeEndpoint, data);
if (response.statusCode() != 200) {
logger.warn("[OAUTH] Invalid response while token revocation: Status Code: " + response.statusCode() + " Body:" + response.body());
}
} catch (IOException | InterruptedException e) {
logger.catching(e);
}
}
public record LoginOrRegisterResponse<T>(T response, boolean created) {
}
public LoginOrRegisterResponse<UserEntity> loginOrRegisterDiscordUser(DiscordOauthUserInfo discordOauthUserInfo) {
Optional<UserEntity> optionalUserEntity = userRepository.findByDiscordId(discordOauthUserInfo.id());
return optionalUserEntity.map(
userEntity -> new LoginOrRegisterResponse<>(userEntity, false))
.orElseGet(() -> {
UserEntity created = userRepository.save(new UserEntity(discordOauthUserInfo));
return new LoginOrRegisterResponse<>(created, true);
});
}
public UserEntity updateUserInfo(DiscordOauthUserInfo discordOauthUserInfo, UserEntity userEntity){
boolean updated = false;
if(userEntity.getUsername() == null || !userEntity.getUsername().equals(discordOauthUserInfo.username())){
userEntity.setUsername(discordOauthUserInfo.username());
updated = true;
}
if(userEntity.getDiscriminator() == null || !userEntity.getDiscriminator().equals(discordOauthUserInfo.discriminator())){
userEntity.setDiscriminator(discordOauthUserInfo.discriminator());
updated = true;
}
if(userEntity.getAvatar() == null || !userEntity.getAvatar().equals(discordOauthUserInfo.avatar())){
userEntity.setAvatar(discordOauthUserInfo.avatar());
updated = true;
}
if(updated){
return userRepository.save(userEntity);
}
return userEntity;
}
private String getFormString(HashMap<String, String> params) {
StringBuilder result = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : params.entrySet()) {
if (first)
first = false;
else
result.append("&");
result.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
}
return result.toString();
}
private HttpResponse<String> makeFormPost(String endpoint, HashMap<String, String> data) throws IOException, InterruptedException {
HttpRequest.BodyPublisher body = HttpRequest.BodyPublishers.ofString(getFormString(data));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(tokenEndpoint))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(body)
.build();
HttpClient client = HttpClient.newHttpClient();
return client.send(request, HttpResponse.BodyHandlers.ofString());
}
}

View File

@ -0,0 +1,69 @@
package net.Broken.Api.Security.Services;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.UserRepository;
import org.springframework.stereotype.Service;
import java.security.Key;
import java.util.Calendar;
import java.util.Date;
import java.util.NoSuchElementException;
import java.util.UUID;
@Service
public class JwtService {
private final Key jwtKey;
private final UserRepository userRepository;
public JwtService(UserRepository userRepository) {
this.userRepository = userRepository;
this.jwtKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
}
public String buildJwt(UserEntity user){
Date iat = new Date();
Date nbf = new Date();
Calendar expCal = Calendar.getInstance();
expCal.add(Calendar.DATE, 7);
Date exp = expCal.getTime();
UUID uuid = UUID.randomUUID();
return Jwts.builder()
.setSubject(user.getUsername())
.claim("discord_id", user.getDiscordId())
.claim("avatar", user.getAvatar())
.claim("discriminator", user.getDiscriminator())
.setId(uuid.toString())
.setIssuedAt(iat)
.setNotBefore(nbf)
.setExpiration(exp)
.signWith(this.jwtKey)
.compact();
}
public Jws<Claims> verifyAndParseJwt(String token) {
return Jwts.parserBuilder()
.setSigningKey(this.jwtKey)
.build()
.parseClaimsJws(token);
}
public UserEntity getUserWithJwt(Jws<Claims> jwt) throws NoSuchElementException {
String discordId = jwt.getBody().get("discord_id", String.class);
return userRepository.findByDiscordId(discordId)
.orElseThrow();
}
}

View File

@ -0,0 +1,131 @@
package net.Broken.Api.Services;
import net.Broken.Api.Data.Guild.Channel;
import net.Broken.Api.Data.Music.*;
import net.Broken.Audio.GuildAudioBotService;
import net.Broken.Audio.UserAudioTrack;
import net.Broken.MainBot;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.audio.hooks.ConnectionStatus;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.VoiceChannel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.util.concurrent.ExecutionException;
@Service
public class AudioService {
final Logger logger = LogManager.getLogger();
public Status getGuildAudioStatus(String guildId, String userId) {
Guild guild = MainBot.jda.getGuildById(guildId);
Member member = guild.getMemberById(userId);
VoiceChannel channel = guild.getAudioManager().getConnectedChannel();
ConnectionStatus status = guild.getAudioManager().getConnectionStatus();
if (channel != null) {
// The user can view the audio status if:
// -> He can view the voice channel
// -> OR He can *not* view the voice channel, but he is connected to this voice channel
boolean canView = member.hasPermission(channel, Permission.VIEW_CHANNEL)
|| (member.getVoiceState() != null
&& member.getVoiceState().getChannel() == channel);
GuildAudioBotService guildAudioBotService = GuildAudioBotService.getInstance(guild);
if (canView) {
// The user can interact with the audio if:
// -> He can connect to this voice channel
// -> OR he is connected to this voice channel
// -> AND He can speak in this voice channel
boolean canInteract = (member.hasPermission(channel, Permission.VOICE_CONNECT)
|| member.getVoiceState() != null
&& member.getVoiceState().getChannel() == channel)
&& member.hasPermission(channel, Permission.VOICE_SPEAK);
boolean stopped = guildAudioBotService.getGuidAudioManager().player.getPlayingTrack() == null;
PlayBackInfo playBackInfo;
if (!stopped) {
boolean paused = guildAudioBotService.getGuidAudioManager().player.isPaused();
long position = guildAudioBotService.getGuidAudioManager().player.getPlayingTrack().getPosition();
UserAudioTrack userAudioTrack = guildAudioBotService.getGuidAudioManager().scheduler.getCurrentPlayingTrack();
playBackInfo = new PlayBackInfo(paused, false, position, new TrackInfo(userAudioTrack));
} else {
playBackInfo = new PlayBackInfo(false, true, null, null);
}
Channel channelApi = new Channel(channel.getId(), channel.getName());
return new Status(true, status, channelApi, true, canInteract, playBackInfo);
} else {
return new Status(true, status, null, false, false, null);
}
}
return new Status(false, status, null, null, null, null);
}
public ResponseEntity<Status> connect(String guildId, Connect body, String userId) {
Guild guild = MainBot.jda.getGuildById(guildId);
VoiceChannel voiceChannel = guild.getVoiceChannelById(body.channelId());
GuildAudioBotService.getInstance(guild).connect(voiceChannel);
Status status = getGuildAudioStatus(guildId, userId);
return new ResponseEntity<>(status, HttpStatus.OK);
}
public ResponseEntity<Status> disconnect(String guildId, String userId) {
Guild guild = MainBot.jda.getGuildById(guildId);
GuildAudioBotService guildAudioBotService = GuildAudioBotService.getInstance(guild);
guildAudioBotService.disconnect();
Status status = getGuildAudioStatus(guildId, userId);
return new ResponseEntity<>(status, HttpStatus.OK);
}
public ResponseEntity<Status> pause(String guildId, String userId) {
Guild guild = MainBot.jda.getGuildById(guildId);
GuildAudioBotService.getInstance(guild).pause();
Status status = getGuildAudioStatus(guildId, userId);
return new ResponseEntity<>(status, HttpStatus.OK);
}
public ResponseEntity<Status> resume(String guildId, String userId) {
Guild guild = MainBot.jda.getGuildById(guildId);
GuildAudioBotService.getInstance(guild).resume();
Status status = getGuildAudioStatus(guildId, userId);
return new ResponseEntity<>(status, HttpStatus.OK);
}
public ResponseEntity<Status> skip(String guildId, String userId) {
Guild guild = MainBot.jda.getGuildById(guildId);
GuildAudioBotService.getInstance(guild).skipTrack();
Status status = getGuildAudioStatus(guildId, userId);
return new ResponseEntity<>(status, HttpStatus.OK);
}
public ResponseEntity<Status> stop(String guildId, String userId) {
Guild guild = MainBot.jda.getGuildById(guildId);
GuildAudioBotService.getInstance(guild).stop();
Status status = getGuildAudioStatus(guildId, userId);
return new ResponseEntity<>(status, HttpStatus.OK);
}
public ResponseEntity<Status> add(String guildId, String userId, Add body) throws ExecutionException, InterruptedException {
Guild guild = MainBot.jda.getGuildById(guildId);
boolean success = GuildAudioBotService.getInstance(guild).loadAndPlaySync(body.url(), userId);
if (success) {
Status status = getGuildAudioStatus(guildId, userId);
return new ResponseEntity<>(status, HttpStatus.OK);
} else {
return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
}
}
}

View File

@ -0,0 +1,74 @@
package net.Broken.Api.Services;
import net.Broken.Api.Data.Guild.Channel;
import net.Broken.Api.Data.Guild.Guild;
import net.Broken.Api.Data.Guild.Role;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.MainBot;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class GuildService {
public List<Guild> getMutualGuilds(UserEntity user) {
User discordUser = MainBot.jda.retrieveUserById(user.getDiscordId()).complete();
List<net.dv8tion.jda.api.entities.Guild> mutualGuilds = discordUser.getMutualGuilds();
List<Guild> guildList = new ArrayList<>();
for (net.dv8tion.jda.api.entities.Guild guild : mutualGuilds) {
boolean canManage = guild.getMember(discordUser).hasPermission(
Permission.MANAGE_SERVER,
Permission.MANAGE_PERMISSIONS,
Permission.MANAGE_CHANNEL
);
guildList.add(new Guild(guild.getId(), guild.getName(), guild.getIconUrl(), canManage));
}
return guildList;
}
public List<Channel> getVoiceChannel(String guildId, String userId) {
net.dv8tion.jda.api.entities.Guild guild = MainBot.jda.getGuildById(guildId);
Member member = guild.getMemberById(userId);
List<Channel> voiceChannels = new ArrayList<>();
for (net.dv8tion.jda.api.entities.VoiceChannel voiceChannel : guild.getVoiceChannels()) {
if (member.hasPermission(voiceChannel, Permission.VIEW_CHANNEL)) {
voiceChannels.add(new Channel(voiceChannel.getId(), voiceChannel.getName()));
}
}
return voiceChannels;
}
public List<Channel> getTextChannel(String guildId, String userId) {
net.dv8tion.jda.api.entities.Guild guild = MainBot.jda.getGuildById(guildId);
Member member = guild.getMemberById(userId);
List<Channel> voiceChannels = new ArrayList<>();
for (net.dv8tion.jda.api.entities.TextChannel textChannel : guild.getTextChannels()) {
if (member.hasPermission(textChannel, Permission.VIEW_CHANNEL)) {
voiceChannels.add(new Channel(textChannel.getId(), textChannel.getName()));
}
}
return voiceChannels;
}
public List<Role> getRole(String guildId) {
net.dv8tion.jda.api.entities.Guild guild = MainBot.jda.getGuildById(guildId);
List<Role> roles = new ArrayList<>();
for (net.dv8tion.jda.api.entities.Role role : guild.getRoles()) {
if (!role.isManaged()) {
roles.add(new Role(role.getId(), role.getName()));
}
}
return roles;
}
public String getInviteLink(){
return MainBot.jda.setRequiredScopes("applications.commands").getInviteUrl(Permission.getPermissions(1644971949399L));
}
}

View File

@ -0,0 +1,48 @@
package net.Broken.Api.Services;
import net.Broken.Api.Data.Settings.SettingGroup;
import net.Broken.Api.Data.Settings.Value;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository;
import net.Broken.Tools.Settings.SettingDescriptionBuilder;
import net.Broken.Tools.Settings.SettingSaver;
import net.Broken.Tools.Settings.SettingValueBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class SettingService {
public final GuildPreferenceRepository preferenceRepository;
private final Logger logger = LogManager.getLogger();
public SettingService(GuildPreferenceRepository preferenceRepository) {
this.preferenceRepository = preferenceRepository;
}
public List<SettingGroup> getSettingDescription() {
return new SettingDescriptionBuilder().build();
}
public List<Value> getValues(String guildId) {
GuildPreferenceEntity pref = preferenceRepository.findByGuildId(guildId).orElseGet(() -> {
logger.info("[API] : Generate default guild pref");
return preferenceRepository.save(GuildPreferenceEntity.getDefault(guildId));
});
return new SettingValueBuilder(pref).build();
}
public GuildPreferenceEntity saveValue(String guildId, List<Value> values){
GuildPreferenceEntity pref = preferenceRepository.findByGuildId(guildId).orElseGet(() -> {
logger.info("[API] : Generate default guild pref");
return preferenceRepository.save(GuildPreferenceEntity.getDefault(guildId));
});
return new SettingSaver(preferenceRepository, pref).save(values);
}
}

View File

@ -1,7 +1,6 @@
package net.Broken.audio;
package net.Broken.Audio;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame;
import com.sedmelluq.discord.lavaplayer.track.playback.MutableAudioFrame;
import net.dv8tion.jda.api.audio.AudioSendHandler;
@ -34,7 +33,7 @@ public class AudioPlayerSendHandler implements AudioSendHandler {
@Override
public ByteBuffer provide20MsAudio() {
return (ByteBuffer) buffer.flip();
return buffer.flip();
}
@Override

View File

@ -0,0 +1,427 @@
package net.Broken.Audio;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers;
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Emoji;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.VoiceChannel;
import net.dv8tion.jda.api.events.interaction.GenericInteractionCreateEvent;
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.components.Button;
public class GuildAudioBotService {
private static final HashMap<Guild, GuildAudioBotService> INSTANCES = new HashMap<>();
private final GuildAudioManager guildAudioManager;
private final AudioPlayerManager audioPlayerManager;
/**
* Extrem limit for playlist
*/
private final int listExtremLimit = 300;
private final Guild guild;
private final Logger logger = LogManager.getLogger();
private final Map<String, Boolean> addStatus = new HashMap<>();
private Message lastMessageWithButton;
private GuildAudioBotService(Guild guild) {
this.audioPlayerManager = new DefaultAudioPlayerManager();
AudioSourceManagers.registerRemoteSources(audioPlayerManager);
AudioSourceManagers.registerLocalSource(audioPlayerManager);
this.guildAudioManager = new GuildAudioManager(audioPlayerManager, guild);
guild.getAudioManager().setSendingHandler(guildAudioManager.getSendHandler());
this.guild = guild;
}
public static GuildAudioBotService getInstance(Guild guild) {
if (!INSTANCES.containsKey(guild)) {
INSTANCES.put(guild, new GuildAudioBotService(guild));
}
return INSTANCES.get(guild);
}
/**
* Load audio track from url, connect to chanel if not connected
*
* @param voiceChannel Voice channel to connect if no connected
* @param trackUrl Audio track url
* @param playlistLimit Limit of playlist
* @param onHead True for adding audio track on top of playlist
*/
public void loadAndPlay(SlashCommandEvent event, VoiceChannel voiceChannel, final String trackUrl, int playlistLimit, boolean onHead) {
audioPlayerManager.loadItemOrdered(guildAudioManager, trackUrl, new AudioLoadResultHandler() {
@Override
public void trackLoaded(AudioTrack track) {
logger.info("[" + guild + "] Single Track detected!");
UserAudioTrack uat = new UserAudioTrack(event.getUser(), track);
Message message = new MessageBuilder()
.setEmbeds(EmbedMessageUtils.getMusicAdded(track.getInfo(), event.getMember(), -1))
.build();
clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
play(guild, voiceChannel, guildAudioManager, uat, onHead);
}
@Override
public void playlistLoaded(AudioPlaylist playlist) {
logger.info("[" + guild + "] Playlist detected! Limit: " + playlistLimit);
AudioTrack firstTrack = playlist.getSelectedTrack();
int size = Math.min(playlist.getTracks().size(), playlistLimit);
Message message = new MessageBuilder()
.setEmbeds(EmbedMessageUtils.getMusicAdded(firstTrack.getInfo(), event.getMember(), size))
.build();
clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
playListLoader(playlist, playlistLimit, event.getUser(), onHead);
}
@Override
public void noMatches() {
logger.warn("[" + guild + "] Cant find media!");
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("Video not found !")).build();
event.getHook().setEphemeral(true).sendMessage(message).queue();
}
@Override
public void loadFailed(FriendlyException exception) {
logger.error("[" + guild + "] Can't load media!");
logger.error(exception.getMessage());
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("Playback error !")).build();
event.getHook().setEphemeral(true).sendMessage(message).queue();
}
});
}
public boolean loadAndPlaySync(String trackUrl, String userId) throws ExecutionException, InterruptedException {
Member member = guild.getMemberById(userId);
VoiceChannel playedChanel = guild.getAudioManager().getConnectedChannel();
final String uuid = UUID.randomUUID().toString();
Future<Void> future = audioPlayerManager.loadItemOrdered(guildAudioManager, trackUrl, new AudioLoadResultHandler() {
@Override
public void trackLoaded(AudioTrack track) {
logger.info("[" + guild + "] Auto add " + track.getInfo().title + " to playlist.");
UserAudioTrack userAudioTrack = new UserAudioTrack(member.getUser(), track);
play(guild, playedChanel, guildAudioManager, userAudioTrack, true);
addStatus.put(uuid, true);
}
@Override
public void playlistLoaded(AudioPlaylist playlist) {
AudioTrack track = playlist.getTracks().get(0);
logger.info("[" + guild + "] Auto add " + track.getInfo().title + " to playlist.");
UserAudioTrack userAudioTrack = new UserAudioTrack(member.getUser(), track);
play(guild, playedChanel, guildAudioManager, userAudioTrack, true);
addStatus.put(uuid, true);
}
@Override
public void noMatches() {
logger.warn("[" + guild + "] Track not found: " + trackUrl);
addStatus.put(uuid, false);
}
@Override
public void loadFailed(FriendlyException exception) {
logger.error("[" + guild + "] Cant load media!");
logger.error(exception.getMessage());
addStatus.put(uuid, false);
}
});
future.get();
return addStatus.remove(uuid);
}
/**
* Load playlist to playlist
*
* @param playlist Loaded playlist
* @param playlistLimit Playlist limit
* @param user User who have submitted the playlist
* @param onHead True for adding audio track on top of playlist
*/
public void playListLoader(AudioPlaylist playlist, int playlistLimit, User user, boolean onHead) {
VoiceChannel playedChanel = guild.getAudioManager().getConnectedChannel();
List<AudioTrack> tracks = playlist.getTracks();
if (onHead)
Collections.reverse(tracks);
int i = 0;
for (AudioTrack track : playlist.getTracks()) {
UserAudioTrack uat = new UserAudioTrack(user, track);
play(guild, playedChanel, guildAudioManager, uat, onHead);
if ((playlistLimit != -1 && i >= playlistLimit) || i > listExtremLimit)
break;
i++;
}
}
/**
* Add single track to playlist, auto-connect if not connected to vocal chanel
*
* @param guild guild
* @param channel Chanel for auto-connect
* @param musicManager Guild music manager
* @param track Track to add to playlist
* @param onHead True for adding audio track on top of playlist
*/
public void play(Guild guild, VoiceChannel channel, GuildAudioManager musicManager, UserAudioTrack track, boolean onHead) {
if (!guild.getAudioManager().isConnected())
guild.getAudioManager().openAudioConnection(channel);
if (!onHead)
musicManager.scheduler.queue(track);
else
musicManager.scheduler.addNext(track);
}
public void add(SlashCommandEvent event, String url, int playListLimit, boolean onHead) {
if (guild.getAudioManager().isConnected()) {
loadAndPlay(event, guild.getAudioManager().getConnectedChannel(), url, playListLimit, onHead);
} else {
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("Not connected to vocal chanel !")).build();
event.getHook().setEphemeral(true).sendMessage(message).queue();
}
}
public void connect(VoiceChannel voiceChannel) {
guild.getAudioManager().openAudioConnection(voiceChannel);
}
public void pause(GenericInteractionCreateEvent event) {
pause();
Message message = new MessageBuilder().setEmbeds(
EmbedMessageUtils.buildStandar(
new EmbedBuilder()
.setTitle(":pause_button: Playback paused")
.setColor(Color.green)
)).build();
clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
}
public void pause() {
guildAudioManager.scheduler.pause();
}
public void resume(GenericInteractionCreateEvent event) {
Message message;
if (guildAudioManager.player.getPlayingTrack() == null) {
message = new MessageBuilder().setEmbeds(
EmbedMessageUtils.buildStandar(
new EmbedBuilder()
.setTitle(":warning: Nothing to play, playlist is empty !")
.setColor(Color.green)
)).build();
} else {
resume();
message = new MessageBuilder().setEmbeds(
EmbedMessageUtils.buildStandar(
new EmbedBuilder()
.setTitle(":arrow_forward: Playback resumed")
.setColor(Color.green)
)).build();
}
clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
}
public void resume() {
guildAudioManager.scheduler.resume();
}
public void skipTrack(GenericInteractionCreateEvent event) {
skipTrack();
Message message = new MessageBuilder().setEmbeds(
EmbedMessageUtils.buildStandar(
new EmbedBuilder()
.setTitle(":track_next: Next Track")
.setColor(Color.green)
)).build();
clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
}
public void skipTrack() {
guildAudioManager.scheduler.nextTrack();
}
public void stop(GenericInteractionCreateEvent event) {
stop();
Message message = new MessageBuilder().setEmbeds(
EmbedMessageUtils.buildStandar(
new EmbedBuilder()
.setTitle(":stop_button: Playback stopped")
.setColor(Color.green)
)).build();
clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
}
public void stop() {
guildAudioManager.scheduler.stop();
guildAudioManager.scheduler.flush();
clearLastButton();
}
public void disconnect(GenericInteractionCreateEvent event) {
disconnect();
Message message = new MessageBuilder().setEmbeds(
EmbedMessageUtils.buildStandar(
new EmbedBuilder()
.setTitle(":eject: Disconnected")
.setColor(Color.green)
)).build();
clearLastButton();
event.getHook().sendMessage(message).queue();
}
public void disconnect() {
guildAudioManager.scheduler.stop();
guildAudioManager.scheduler.flush();
guild.getAudioManager().closeAudioConnection();
clearLastButton();
}
public void info(GenericInteractionCreateEvent event) {
AudioTrackInfo info = guildAudioManager.scheduler.getInfo();
UserAudioTrack userAudioTrack = guildAudioManager.scheduler.getCurrentPlayingTrack();
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicInfo(info, userAudioTrack)).build();
clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
}
public void flush(GenericInteractionCreateEvent event) {
guildAudioManager.scheduler.flush();
Message message = new MessageBuilder().setEmbeds(
EmbedMessageUtils.buildStandar(
new EmbedBuilder()
.setTitle(":wastebasket: Playlist flushed")
.setColor(Color.green)
)).build();
clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
}
/**
* Print current playlist content
*
* @param event
*/
public void list(GenericInteractionCreateEvent event) {
List<UserAudioTrack> list = guildAudioManager.scheduler.getList();
if (list.size() == 0) {
Message message = new MessageBuilder().setEmbeds(
EmbedMessageUtils.buildStandar(
new EmbedBuilder()
.setTitle(":scroll: Playlist")
.setColor(Color.green)
.setDescription("Oh no ! The playlist is empty !")
)).build();
event.getHook().sendMessage(message).queue();
} else {
StringBuilder resp = new StringBuilder();
int i = 0;
for (UserAudioTrack trackInfo : list) {
resp.append(":arrow_right: ");
resp.append(trackInfo.getAudioTrack().getInfo().title);
resp.append(" - ");
resp.append(trackInfo.getAudioTrack().getInfo().author);
resp.append("\n\n");
if (i >= 5) {
resp.append(":arrow_forward: And ");
resp.append(list.size() - 5);
resp.append(" other tracks ...");
break;
}
i++;
}
Message message = new MessageBuilder().setEmbeds(
EmbedMessageUtils.buildStandar(
new EmbedBuilder()
.setTitle(":scroll: Playlist")
.setColor(Color.green)
.setDescription(resp.toString())
)).build();
event.getHook().sendMessage(message).queue();
}
}
public Guild getGuild() {
return guild;
}
public GuildAudioManager getGuidAudioManager() {
return guildAudioManager;
}
public void clearLastButton() {
if (lastMessageWithButton != null) {
this.lastMessageWithButton.editMessageComponents(new ArrayList<>()).queue();
this.lastMessageWithButton = null;
}
}
public void updateLastButton() {
if (lastMessageWithButton != null)
lastMessageWithButton = lastMessageWithButton.editMessageComponents(ActionRow.of(getActionButton())).complete();
}
private List<Button> getActionButton() {
ArrayList<Button> buttonArrayList = new ArrayList<>();
if (guildAudioManager.player.getPlayingTrack() == null) {
buttonArrayList.add(Button.success("play", Emoji.fromUnicode("▶️")).withDisabled(true));
buttonArrayList.add(Button.primary("next", Emoji.fromUnicode("⏭️")).withDisabled(true));
buttonArrayList.add(Button.primary("stop", Emoji.fromUnicode("⏹️")).withDisabled(true));
buttonArrayList.add(Button.danger("disconnect", Emoji.fromUnicode("⏏️")));
return buttonArrayList;
}
if (guildAudioManager.player.isPaused()) {
buttonArrayList.add(Button.success("play", Emoji.fromUnicode("▶️")));
} else {
buttonArrayList.add(Button.success("pause", Emoji.fromUnicode("⏸️")));
}
buttonArrayList.add(Button.primary("next", Emoji.fromUnicode("⏭️")));
buttonArrayList.add(Button.primary("stop", Emoji.fromUnicode("⏹️")));
buttonArrayList.add(Button.danger("disconnect", Emoji.fromUnicode("⏏️")));
return buttonArrayList;
}
}

View File

@ -1,4 +1,4 @@
package net.Broken.audio;
package net.Broken.Audio;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
@ -7,7 +7,7 @@ import net.dv8tion.jda.api.entities.Guild;
/**
* Holder for both the player and a track scheduler for one guild.
*/
public class GuildMusicManager {
public class GuildAudioManager {
/**
* Audio player for the guild.
*/
@ -21,9 +21,10 @@ public class GuildMusicManager {
/**
* Creates a player and a track scheduler.
*
* @param manager Audio player manager to use for creating the player.
*/
public GuildMusicManager(AudioPlayerManager manager, Guild guild) {
public GuildAudioManager(AudioPlayerManager manager, Guild guild) {
player = manager.createPlayer();
scheduler = new TrackScheduler(player, guild);
player.addListener(scheduler);

View File

@ -1,26 +1,23 @@
package net.Broken.audio;
package net.Broken.Audio;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import net.Broken.MainBot;
import net.Broken.RestApi.Data.UserAudioTrackData;
import net.Broken.audio.Youtube.RelatedIdNotFound;
import net.Broken.audio.Youtube.YoutubeSearchRework;
import net.Broken.audio.Youtube.YoutubeTools;
import net.dv8tion.jda.api.entities.Guild;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import net.Broken.MainBot;
import net.dv8tion.jda.api.entities.Guild;
/**
* This class schedules tracks for the audio player. It contains the queue of tracks.
*/
@ -30,9 +27,7 @@ public class TrackScheduler extends AudioEventAdapter {
private final Guild guild;
private UserAudioTrack currentPlayingTrack;
private boolean autoFlow = false;
private ArrayList<String> history = new ArrayList<>();
private Logger logger = LogManager.getLogger();
private final Logger logger = LogManager.getLogger();
/**
* @param player The audio player this scheduler uses
@ -56,20 +51,13 @@ public class TrackScheduler extends AudioEventAdapter {
// track goes to the queue instead.
if (track.getSubmittedUser() != MainBot.jda.getSelfUser()) {
logger.debug("[" + guild + "] Flush history");
history = new ArrayList<>();
}
history.add(track.getAudioTrack().getIdentifier());
if (!player.startTrack(track.getAudioTrack(), true)) {
queue.offer(track);
} else {
currentPlayingTrack = track;
}
if (track.getSubmittedUser() != MainBot.jda.getSelfUser()) {
needAutoPlay();
}
}
/**
@ -81,22 +69,11 @@ public class TrackScheduler extends AudioEventAdapter {
// Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If
// something is playing, it returns false and does nothing. In that case the player was already playing so this
// track goes to the queue instead.
if (track.getSubmittedUser() != MainBot.jda.getSelfUser()) {
logger.debug("Flush history");
history = new ArrayList<>();
}
history.add(track.getAudioTrack().getIdentifier());
if (!player.startTrack(track.getAudioTrack(), true)) {
queue.addFirst(track);
} else {
currentPlayingTrack = track;
}
if (track.getSubmittedUser() != MainBot.jda.getSelfUser()) {
needAutoPlay();
} else
logger.debug("[" + guild + "] Bot add, ignore autoFlow");
}
public void pause() {
@ -118,14 +95,12 @@ public class TrackScheduler extends AudioEventAdapter {
queue.clear();
}
public List<UserAudioTrackData> getList() {
// AudioTrack[] test = (AudioTrack[]) queue.toArray();
List<UserAudioTrackData> temp = new ArrayList<>();
public List<UserAudioTrack> getList() {
List<UserAudioTrack> temp = new ArrayList<>();
Object[] test = queue.toArray();
for (Object track : test) {
UserAudioTrack casted = (UserAudioTrack) track;
temp.add(new UserAudioTrackData(casted.getSubmittedUser().getName(), casted.getAudioTrack().getInfo()));
temp.add(casted);
}
return temp;
}
@ -146,7 +121,6 @@ public class TrackScheduler extends AudioEventAdapter {
return false;
} else {
logger.info("[" + guild + "] Delete successful");
needAutoPlay();
return true;
}
}
@ -163,54 +137,55 @@ public class TrackScheduler extends AudioEventAdapter {
// Start the next track, regardless of if something is already playing or not. In case queue was empty, we are
// giving null to startTrack, which is a valid argument and will simply stop the player.
UserAudioTrack track = queue.poll();
if (track != null)
if (track != null){
this.currentPlayingTrack = track;
if (track != null)
player.startTrack(track.getAudioTrack(), false);
needAutoPlay();
}
}
@Override
public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
// Only start the next track if the end reason is suitable for it (FINISHED or LOAD_FAILED)
if (endReason.mayStartNext) {
logger.debug("[" + guild + "] End of track, start next.");
if(queue.isEmpty()){
logger.debug("[" + guild.getName() + "] End of track, Playlist empty.");
GuildAudioBotService.getInstance(guild).updateLastButton();
}else{
logger.debug("[" + guild.getName() + "] End of track, start next.");
nextTrack();
}
}
private void needAutoPlay() {
if ((queue.size() < 1) && autoFlow && currentPlayingTrack != null) {
logger.debug("[" + guild.getName() + "] Auto add needed!");
AudioM audioM = AudioM.getInstance(guild);
YoutubeSearchRework youtubeSearchRework = YoutubeSearchRework.getInstance();
try {
String id = youtubeSearchRework.getRelatedVideo(currentPlayingTrack.getAudioTrack().getInfo().identifier);
logger.debug("[" + guild.getName() + "] Related id: " + id);
audioM.loadAndPlayAuto(id);
} catch (IOException | RelatedIdNotFound ex) {
logger.debug("[" + guild.getName() + "] Can't find related id, try API...");
YoutubeTools youtubeTools = YoutubeTools.getInstance();
try {
String id = youtubeTools.getRelatedVideo(currentPlayingTrack.getAudioTrack().getInfo().identifier, history);
logger.debug("[" + guild.getName() + "] Related id: " + id);
audioM.loadAndPlayAuto(id);
} catch (GoogleJsonResponseException e) {
logger.error("[" + guild.getName() + "] There was a service error: " + e.getDetails().getCode() + " : " + e.getDetails().getMessage());
} catch (IOException t) {
logger.catching(t);
}
}
}
}
public void setAutoFlow(boolean autoFlow) {
this.autoFlow = autoFlow;
needAutoPlay();
@Override
public void onTrackStart(AudioPlayer player, AudioTrack track) {
super.onTrackStart(player, track);
GuildAudioBotService.getInstance(guild).updateLastButton();
}
public boolean isAutoFlow() {
return autoFlow;
@Override
public void onPlayerPause(AudioPlayer player) {
super.onPlayerPause(player);
GuildAudioBotService.getInstance(guild).updateLastButton();
}
@Override
public void onPlayerResume(AudioPlayer player) {
super.onPlayerResume(player);
GuildAudioBotService.getInstance(guild).updateLastButton();
}
@Override
public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) {
super.onTrackException(player, track, exception);
GuildAudioBotService.getInstance(guild).updateLastButton();
}
@Override
public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) {
super.onTrackStuck(player, track, thresholdMs);
GuildAudioBotService.getInstance(guild).updateLastButton();
}
}

View File

@ -1,4 +1,4 @@
package net.Broken.audio;
package net.Broken.Audio;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import net.dv8tion.jda.api.entities.User;
@ -7,8 +7,8 @@ import net.dv8tion.jda.api.entities.User;
* Container that link AudioTrack to who submit it (User)
*/
public class UserAudioTrack {
private User user;
private AudioTrack audioTrack;
private final User user;
private final AudioTrack audioTrack;
public UserAudioTrack(User user, AudioTrack audioTrack) {
this.user = user;

View File

@ -0,0 +1,13 @@
package net.Broken;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
@ConfigurationProperties(prefix = "discord.bot")
@ConstructorBinding
public record BotConfigLoader (
String token,
String url,
String mode,
String randomApiKey
){}

View File

@ -1,18 +1,13 @@
package net.Broken;
import net.Broken.Commands.Move;
import net.Broken.Audio.GuildAudioBotService;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository;
import net.Broken.DB.Repository.UserRepository;
import net.Broken.Tools.AntiSpam;
import net.Broken.Tools.Command.CommandParser;
import net.Broken.Tools.AutoVoiceChannel;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.Moderateur;
import net.Broken.Tools.PrivateMessage;
import net.Broken.Tools.UserManager.Stats.UserStatsUtils;
import net.Broken.audio.AudioM;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.events.ReadyEvent;
import net.dv8tion.jda.api.events.guild.GuildJoinEvent;
@ -20,101 +15,80 @@ import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent;
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceJoinEvent;
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent;
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMoveEvent;
import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.managers.GuildManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.ApplicationContext;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Optional;
/**
* Bot Listener
*/
public class BotListener extends ListenerAdapter {
private AntiSpam antispam = new AntiSpam();
private Moderateur modo = new Moderateur();
private final GuildPreferenceRepository guildPreferenceRepository;
private final BotConfigLoader botConfig;
private GuildPreferenceRepository guildPreferenceRepository;
private UserRepository userRepository;
private Logger logger = LogManager.getLogger();
private final Logger logger = LogManager.getLogger();
public BotListener() {
ApplicationContext context = SpringContext.getAppContext();
guildPreferenceRepository = (GuildPreferenceRepository) context.getBean("guildPreferenceRepository");
userRepository = (UserRepository) context.getBean("userRepository");
guildPreferenceRepository = context.getBean(GuildPreferenceRepository.class);
botConfig = context.getBean(BotConfigLoader.class);
}
@Override
public void onReady(ReadyEvent event) {
logger.info("Connection succees");
logger.info("Connection success");
}
@Override
public void onGuildMemberJoin(GuildMemberJoinEvent event) {
GuildPreferenceEntity guildPref = getPreference(event.getGuild());
if (guildPref.isDefaultRole()) {
logger.info(event.getUser().getName() + "join the guild, move it!");
List<Role> roles = new ArrayList<>();
roles.add(event.getGuild().getRoleById(guildPref.getDefaultRoleId()));
new Move().exc(event.getMember(), roles, false, event.getGuild(), event.getGuild().getManager());
logger.info("[" + event.getGuild().getName() + "] : " + event.getUser().getName() + " join the guild, adding default role !");
Role default_role = event.getGuild().getRoleById(guildPref.getDefaultRoleId());
if (default_role != null) {
event.getGuild().addRoleToMember(event.getMember(), default_role).queue();
} else {
logger.fatal("[" + event.getGuild().getName() + "] : Default role is null !");
}
}
if (guildPref.isWelcome()) {
TextChannel chanel = event.getGuild().getTextChannelById(guildPref.getWelcomeChanelID());
if (chanel != null) {
String message = guildPref.getWelcomeMessage();
message = message.replaceAll("@name", event.getMember().getAsMention());
String message = guildPref.getWelcomeMessage().replaceAll("@name", event.getMember().getAsMention());
logger.debug(message);
chanel.sendMessage(message).complete();
chanel.sendMessage(message).queue();
} else {
logger.fatal("[" + event.getGuild().getName() + "] : Welcome chanel is null !");
}
MainBot.roleFlag = false;
}
}
@Override
public void onGuildMemberRoleRemove(GuildMemberRoleRemoveEvent event) {
GuildPreferenceEntity guildPref = getPreference(event.getGuild());
if (guildPref.isDefaultRole()) {
if (!MainBot.roleFlag) {
if (event.getMember().getRoles().size() == 0) {
logger.info(event.getUser().getName() + "have no roles, move it!");
List<Role> roles = new ArrayList<>();
roles.add(event.getGuild().getRoleById(guildPref.getDefaultRoleId()));
new Move().exc(event.getMember(), roles, false, event.getGuild(), event.getGuild().getManager());
MainBot.roleFlag = false;
logger.info("[" + event.getGuild().getName() + "] : " + event.getUser().getName() + " have no roles, reset to default !");
Role default_role = event.getGuild().getRoleById(guildPref.getDefaultRoleId());
if (default_role == null) {
logger.fatal("[" + event.getGuild().getName() + "] : Default role is null !");
return;
}
} else {
logger.debug("ignore it");
MainBot.roleFlag = false;
event.getGuild().addRoleToMember(event.getMember(), default_role).queue();
}
}
@ -132,6 +106,8 @@ public class BotListener extends ListenerAdapter {
userStatsUtils.runningCounters.put(event.getMember().getId(), temp);
}
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.join(event.getChannelJoined());
}
}
@ -143,67 +119,73 @@ public class BotListener extends ListenerAdapter {
if (event.getGuild().getAudioManager().getConnectedChannel().getMembers().size() == 1) {
logger.debug("I'm alone, close audio connection.");
GuildAudioBotService.getInstance(event.getGuild()).stop();
}
} else if (event.getMember().getUser() == MainBot.jda.getSelfUser()) {
GuildAudioBotService.getInstance(event.getGuild()).clearLastButton();
}
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.leave(event.getChannelLeft());
}
AudioM.getInstance(event.getGuild()).stop();
}
}
@Override
public void onGuildVoiceMove(@NotNull GuildVoiceMoveEvent event) {
super.onGuildVoiceMove(event);
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.leave(event.getChannelLeft());
autoVoiceChannel.join(event.getChannelJoined());
}
@Override
public void onMessageReceived(MessageReceivedEvent event) {
if (!event.getAuthor().isBot()) {
UserStatsUtils.getINSTANCE().addMessageCount(event.getMember());
}
try {
if (event.getMessage().getContentRaw().startsWith("//") && !event.getMessage().getAuthor().getId().equals(event.getJDA().getSelfUser().getId())) {
//On a detecter que c'etait une commande
//System.out.println(event.getMessage().getContent());
List<UserEntity> users = userRepository.findByJdaId(event.getAuthor().getId());
UserEntity user = users.size() == 0 ? null : users.get(0);
MainBot.handleCommand(new CommandParser().parse(event.getMessage().getContentRaw(), event), user);
} else if (!event.getMessage().getAuthor().getId().equals(event.getJDA().getSelfUser().getId())) {
if (!event.isFromType(ChannelType.PRIVATE)) {
Guild serveur = event.getGuild();
GuildPreferenceEntity guildPref = getPreference(serveur);
if (!guildPref.isAntiSpam())
return;
try {
GuildManager guildManager = serveur.getManager();
Member user = event.getMember();
// appel de la methode d'analyse de message de "Moderateur"
if (event.getMessage().getContentRaw().length() > 0) {
if (modo.analyse(user, serveur, guildManager, event) == 1) {
antispam.extermine(user, serveur, guildManager, true, event);
}
} else if (event.getMessage().getContentRaw().length() == 0)
logger.error("Image detected, ignoring it.");
} catch (InsufficientPermissionException e) {
logger.warn("Insufficient permission for guild " + e.getGuild(MainBot.jda).getName() + " Missing " + e.getPermission() + " permission.");
}
@Override
public void onButtonClick(@NotNull ButtonClickEvent event) {
super.onButtonClick(event);
event.deferReply().queue();
GuildAudioBotService guildAudioBotService = GuildAudioBotService.getInstance(event.getGuild());
switch (event.getComponentId()) {
case "pause" -> guildAudioBotService.pause(event);
case "play" -> guildAudioBotService.resume(event);
case "next" -> guildAudioBotService.skipTrack(event);
case "stop" -> guildAudioBotService.stop(event);
case "disconnect" -> guildAudioBotService.disconnect(event);
}
}
@Override
public void onSlashCommand(@NotNull SlashCommandEvent event) {
HashMap<String, SlashCommand> commands = MainBot.slashCommands;
super.onSlashCommand(event);
if (commands.containsKey(event.getName())) {
SlashCommand commandRunner = commands.get(event.getName());
// It's form private message
if (!event.isFromGuild()) {
if (commandRunner.isPrivateUsable()) {
commandRunner.action(event);
} else {
MessageEmbed message = EmbedMessageUtils.buildStandar(new EmbedBuilder()
.setTitle(":no_entry_sign: This command is not usable in private message")
.setColor(Color.red)
);
event.replyEmbeds(message).setEphemeral(true).queue();
}
} else {
if (!commandRunner.isNSFW() || event.getTextChannel().isNSFW()) {
commandRunner.action(event);
} else {
MessageEmbed message = EmbedMessageUtils.buildStandar(new EmbedBuilder()
.setTitle(":underage: This command is only usable in NSFW channels")
.setColor(Color.red)
);
event.replyEmbeds(message).setEphemeral(true).queue();
}
}
} catch (Exception e) {
logger.catching(e);
if (event.isFromType(ChannelType.PRIVATE))
PrivateMessage.send(event.getAuthor(), EmbedMessageUtils.getInternalError(), logger);
else
event.getTextChannel().sendMessage(EmbedMessageUtils.getInternalError()).queue();
}
}
@Override
@ -211,34 +193,36 @@ public class BotListener extends ListenerAdapter {
logger.info("Join new guild! (" + event.getGuild().getName() + " " + event.getGuild().getMembers().size() + " Members)");
super.onGuildJoin(event);
getPreference(event.getGuild());
event.getGuild().loadMembers().onSuccess((members -> logger.debug("[" + event.getGuild().getName() + "] Members loaded")));
EmbedBuilder eb = new EmbedBuilder().setColor(Color.GREEN)
.setTitle("Hello there !")
.setDescription("Allow me to introduce myself -- I am a CL4P-TP the discord bot, but my friends call me Claptrap ! Or they would, if any of them were real...\n" +
"\nYou can access to my web UI with: " + MainBot.url)
"\nYou can access to my web UI with: " + botConfig.url())
.setImage("https://i.imgur.com/Anf1Srg.gif");
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.buildStandar(eb)).build();
TextChannel defaultChan = event.getGuild().getDefaultChannel();
if (defaultChan != null && defaultChan.canTalk())
defaultChan.sendMessage(EmbedMessageUtils.buildStandar(eb)).queue();
else {
if (defaultChan != null && defaultChan.canTalk()) {
defaultChan.sendMessage(message).queue();
} else {
for (TextChannel chan : event.getGuild().getTextChannels()) {
if (chan.canTalk()) {
chan.sendMessage(EmbedMessageUtils.buildStandar(eb)).queue();
chan.sendMessage(message).queue();
break;
}
}
}
}
private GuildPreferenceEntity getPreference(Guild guild) {
List<GuildPreferenceEntity> guildPrefList = guildPreferenceRepository.findByGuildId(guild.getId());
GuildPreferenceEntity guildPref;
if (guildPrefList.isEmpty()) {
logger.info("Generate default pref");
guildPref = GuildPreferenceEntity.getDefault(guild);
guildPreferenceRepository.save(guildPref);
} else
guildPref = guildPrefList.get(0);
return guildPref;
Optional<GuildPreferenceEntity> guildPref = guildPreferenceRepository.findByGuildId(guild.getId());
if (guildPref.isEmpty()) {
logger.info("[" + guild.getName() + "] : Generate default pref");
return guildPreferenceRepository.save(GuildPreferenceEntity.getDefault(guild.getId()));
} else{
return guildPref.get();
}
}
}

View File

@ -9,6 +9,7 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
public interface Commande {
/**
* Main action of command
*
* @param args Command args.
* @param event Command MessageReceivedEvent
*/
@ -16,24 +17,28 @@ public interface Commande {
/**
* Determines if the command is usable whit private message
*
* @return boolean
*/
boolean isPrivateUsable();
/**
* Determines if the command is usable only by admin user
*
* @return boolean
*/
boolean isAdminCmd();
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
boolean isBotAdminCmd();
/**
* Determines if the command is only usable on NSFW channels
*
* @return boolean
*/
boolean isNSFW();

View File

@ -1,73 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.dv8tion.jda.api.entities.ChannelType;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
/**
* Command that return a random picture of cat.
*/
public class Cat implements Commande {
@Override
public void action(String[] args, MessageReceivedEvent event) {
if(!event.isFromType(ChannelType.PRIVATE))
{
try {
URL urlC = new URL("http://aws.random.cat/meow");
URLConnection yc = urlC.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
yc.getInputStream(), "UTF-8"));
String inputLine;
StringBuilder a = new StringBuilder();
while ((inputLine = in.readLine()) != null)
a.append(inputLine);
in.close();
JSONObject json = new JSONObject(a.toString());
event.getTextChannel().sendMessage(json.getString("file")).queue();
} catch (IOException e) {
e.printStackTrace();
}
}
else
event.getPrivateChannel().sendMessage("\n:warning: **__This command cannot be used there !__** :warning:").queue();
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -3,12 +3,10 @@ package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageHistory;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.omg.CosNaming.NamingContextExtPackage.StringNameHelper;
import java.text.DateFormat;
import java.text.ParseException;
@ -19,7 +17,7 @@ import java.util.HashMap;
import java.util.Locale;
public class ChannelsReview implements Commande {
Logger logger = LogManager.getLogger();
final Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event) {
@ -31,8 +29,7 @@ public class ChannelsReview implements Commande {
} catch (ParseException e) {
logger.warn("Can't parse date : " + e.getMessage());
}
}
else{
} else {
SendBack(event);
}
}
@ -48,7 +45,7 @@ public class ChannelsReview implements Commande {
try {
Message lastMessage = textChannel.retrieveMessageById(lastMessageId).complete();
if (beforeDate.compareTo(format.parse(lastMessage.getTimeCreated().format(formatter))) > 0) {
logger.debug("Last message in channel " + textChannel.toString() + " is " + lastMessageId);
logger.debug("Last message in channel " + textChannel + " is " + lastMessageId);
String date = lastMessage.getTimeCreated().format(formatter);
charCtl += textChannel.getName().length() + date.length();
result.put(textChannel.getName(), date);
@ -80,7 +77,7 @@ public class ChannelsReview implements Commande {
for (TextChannel textChannel : event.getGuild().getTextChannels()) {
if (textChannel.hasLatestMessage()) {
String lastMessageId = textChannel.getLatestMessageId();
logger.debug("Last message in channel " + textChannel.toString() + " is " + lastMessageId);
logger.debug("Last message in channel " + textChannel + " is " + lastMessageId);
try {
Message lastMessage = textChannel.retrieveMessageById(lastMessageId).complete();

View File

@ -1,105 +0,0 @@
package net.Broken.Commands;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import net.Broken.Commande;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository;
import net.Broken.DB.Repository.UserRepository;
import net.Broken.SpringContext;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.MessageTimeOut;
import net.Broken.Tools.PrivateMessage;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.ChannelType;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationContext;
import java.awt.*;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
public class Code implements Commande {
private UserRepository userRepository;
private Logger logger = LogManager.getLogger();
public Code (){
ApplicationContext context = SpringContext.getAppContext();
userRepository = (UserRepository) context.getBean("userRepository");
}
@Override
public void action(String[] args, MessageReceivedEvent event) {
StringBuilder stringBuilder = new StringBuilder();
for(String arg : args){
stringBuilder.append(arg);
stringBuilder.append(" ");
}
Binding binding = new Binding();
binding.setVariable("event", event);
GroovyShell shell = new GroovyShell(binding);
EmbedBuilder builder;
try{
Object value = shell.evaluate(stringBuilder.toString());
StringBuilder stringResult = new StringBuilder();
if(value.getClass().isArray()){
Object[] array = (Object[]) value;
for(Object obj : array){
if(stringResult.length() < 1800){
stringResult.append(obj.toString()).append("\n\n");
}
else{
stringResult.append("\n...");
break;
}
}
}else{
stringResult.append(value.toString());
}
builder = new EmbedBuilder().setColor(Color.orange).setTitle(":hammer_pick: Compilation Successful :hammer_pick:").setDescription("```java\n" + stringResult.toString() + "```");
}catch (Exception ex){
builder = new EmbedBuilder().setColor(Color.red).setTitle(":x: Compilation Failed :x:").setDescription("```java\n" + ex.toString() + "```");
}
event.getChannel().sendMessage(builder.build()).queue();
}
@Override
public boolean isPrivateUsable() {
return true;
}
@Override
public boolean isAdminCmd() {
return true;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return true;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,48 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.Tools.DayListener.DayListener;
import net.dv8tion.jda.api.entities.ChannelType;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Admin command to manually trigger daily action(s)
*/
public class DayTrigger implements Commande{
Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event) {
if(!event.isFromType(ChannelType.PRIVATE))
event.getMessage().delete().queue();
DayListener.getInstance().trigger();
}
@Override
public boolean isPrivateUsable() {
return true;
}
@Override
public boolean isAdminCmd() {
return true;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return true;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,76 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.entities.MessageHistory;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List;
/**
* Command to flush X last message on channel.
*/
public class Flush implements Commande{
Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event) {
if(args.length<1){
event.getTextChannel().sendMessage(EmbedMessageUtils.getFlushError("Missing argument!")).queue();
}
else
{
if(event.getMember().hasPermission(Permission.ADMINISTRATOR)){
try {
int limit = Integer.parseInt(args[0]) + 1;
MessageChannel chanel = event.getChannel();
chanel.getIterableHistory().takeAsync(limit).thenAccept(chanel::purgeMessages);
}catch (NumberFormatException e){
event.getTextChannel().sendMessage(EmbedMessageUtils.getFlushError("Argument unknown!")).queue();
}
}
else
{
event.getTextChannel().sendMessage(EmbedMessageUtils.getFlushError("You are not a supreme being, you cannot do that !")).queue();
}
}
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,195 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.MainBot;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.MessageTimeOut;
import net.Broken.Tools.PrivateMessage;
import net.Broken.Tools.TableRenderer;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.ChannelType;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.awt.*;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Help Command.
*/
public class Help implements Commande {
Logger logger = LogManager.getLogger();
private int cellLenght = 25;
@Override
public void action(String[] args, MessageReceivedEvent event) {
if(args.length>=1)
{
String argsString = args[0];
//System.out.println(argsString);
if (MainBot.commandes.containsKey(argsString))
{
Commande cmdObj = MainBot.commandes.get(argsString);
if(!cmdObj.isAdminCmd() || isAdmin(event))
{
logger.debug("Help for "+argsString+" by "+event.getAuthor().getName());
MessageEmbed messageEmbed;
try {
messageEmbed = EmbedMessageUtils.getHelp(argsString);
} catch (FileNotFoundException e) {
try {
messageEmbed = EmbedMessageUtils.getHelp("Default");
} catch (FileNotFoundException e1) {
messageEmbed = EmbedMessageUtils.getInternalError();
logger.catching(e1);
}
}
if(!event.isFromType(ChannelType.PRIVATE)) {
event.getTextChannel().sendMessage(messageEmbed).queue();
} else{
PrivateMessage.send(event.getAuthor(), messageEmbed,logger);
}
}
else
{
logger.info("Help wanted for admin command, Denied!");
if(!event.isFromType(ChannelType.PRIVATE)) {
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getUnautorized()).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
} else{
PrivateMessage.send(event.getAuthor(), EmbedMessageUtils.getUnautorized(), logger);
}
}
}
else
{
if(!event.isFromType(ChannelType.PRIVATE)) {
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getUnknowCommand()).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
} else{
PrivateMessage.send(event.getAuthor(),EmbedMessageUtils.getUnknowCommand(),logger);
}
logger.debug("Unknown command!");
}
}
else
{
TableRenderer table = new TableRenderer();
table.setHeader("Command","PU");
TableRenderer nsfwTable = new TableRenderer();
nsfwTable.setHeader("NSFW Only\u00A0", "PU");
List<String> noPu = new ArrayList<>();
for (Map.Entry<String, Commande> e : MainBot.commandes.entrySet()) {
if(!e.getValue().isAdminCmd() || isAdmin(event)){
if(e.getValue().isPrivateUsable())
table.addRow(e.getKey(), "XX");
else if(e.getValue().isNSFW())
nsfwTable.addRow(e.getKey(),"");
else
noPu.add(e.getKey());
}
}
for(String key : noPu)
table.addRow(key, "");
String txt = table.build();
txt += "\n\n";
txt += nsfwTable.build();
if(!event.isFromType(ChannelType.PRIVATE)){
Message rest = event.getTextChannel().sendMessage(new EmbedBuilder().setTitle("Commands sent by private message").setColor(Color.green).build()).complete();
new MessageTimeOut(MainBot.messageTimeOut, rest, event.getMessage()).start();
}
String role;
if(isAdmin(event))
role = "Admin";
else
role = "No Admin";
try {
PrivateMessage.send(event.getAuthor(), EmbedMessageUtils.getHelpList(role, txt),logger);
} catch (FileNotFoundException e) {
logger.catching(e);
PrivateMessage.send(event.getAuthor(), EmbedMessageUtils.getInternalError(), logger);
}
}
}
@Override
public boolean isPrivateUsable() {
return true;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
public boolean isAdmin(MessageReceivedEvent event){
if(event.isFromType(ChannelType.PRIVATE)){
List<Guild> guilds = event.getAuthor().getMutualGuilds();
for(Guild iterator : guilds){
if(iterator.getMember(event.getAuthor()).hasPermission(Permission.ADMINISTRATOR)){
return true;
}
}
}
else
return event.getMember().hasPermission(Permission.ADMINISTRATOR);
return false;
}
}

View File

@ -1,43 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.Tools.PrivateMessage;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
public class Invite implements Commande{
@Override
public void action(String[] args, MessageReceivedEvent event) {
if(event.getChannelType().isGuild()){
event.getTextChannel().sendMessage("You can invite me whit this link:\nhttps://discordapp.com/oauth2/authorize?client_id=" + event.getJDA().getSelfUser().getId() + "&scope=bot&permissions=8").complete();
}
else {
PrivateMessage.send(event.getAuthor(),"You can invite me whit this link:\nhttps://discordapp.com/oauth2/authorize?client_id=" + event.getJDA().getSelfUser().getId() + "&scope=bot&permissions=8",LogManager.getLogger());
}
}
@Override
public boolean isPrivateUsable() {
return true;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,48 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import java.awt.*;
import java.util.List;
public class ListRoles implements Commande {
@Override
public void action(String[] args, MessageReceivedEvent event) {
List<Role> roles = event.getGuild().getRoles();
EmbedBuilder messageB = new EmbedBuilder();
for (Role role : roles){
messageB.addField(role.getName(),"```id: " + role.getId() + "```",false);
}
messageB.setColor(Color.green);
event.getTextChannel().sendMessage(messageB.build()).complete();
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return true;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,203 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.MainBot;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.MessageTimeOut;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.exceptions.HierarchyException;
import net.dv8tion.jda.api.managers.GuildManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
/**
* Move Command
*/
public class Move implements Commande {
Logger logger = LogManager.getLogger();
private String HELP="`//move <@user> <@Role>`\n:arrow_right:\t*Move a user to a specified role.*";
public List<Role> saveRoleUser;
public Member user;
public Guild serveur;
public GuildManager serveurManager;
/** Perform a move (Reset is role and add target(s) role(s)
*
* @param user User to move
* @param cible Complete list of new role
* @param reset
* @param serveur Guild
* @param serveurManager GuildManager
* @return success
*/
public boolean exc(Member user, List<Role> cible , boolean reset, Guild serveur, GuildManager serveurManager) throws HierarchyException
{
MainBot.roleFlag = true;
boolean erreur = false;
List<Role> allRoll = serveur.getRoles();
//On recupere les roles de l'utilisateur
List<Role> roleUserList = user.getRoles();
logger.info("Roles of " + user.getEffectiveName() + ":");
//On les save
saveRoleUser = roleUserList;
//Ajout du role cible
//On transforme la le role a ajouter en une liste pour pouvoir l'utiliser dans modifyMemberRoles
//on fait ensuite les modif
serveur.modifyMemberRoles(user,cible).complete();
logger.info("Give " + cible + " role to " + user.getEffectiveName());
this.user=user;
this.serveur=serveur;
this.serveurManager=serveurManager;
return erreur;
}
/** Command handler
*
* @param args
* @param event
*/
public void action(String[] args, MessageReceivedEvent event)
{
if(!event.isFromType(ChannelType.PRIVATE))
{
if(args.length>=2)
{
serveur=event.getGuild();
List<User> userL = event.getMessage().getMentionedUsers();
List<Role> roleL = event.getMessage().getMentionedRoles();
if(userL.size()<1 ||roleL.size()<1)
{
logger.warn("Wrong mention.");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getMoveError("Error, please check if the user and/or the role are existing.")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
else
{
user = serveur.getMember(userL.get(0));
serveur=event.getGuild();
logger.info("Attempting role assignement for "+user.getEffectiveName()+" to "+roleL+" by "+event.getAuthor().getName());
logger.info("Permission granted, role assignement authorized");
logger.debug("User found");
try {
boolean erreur=this.exc(user,roleL,true,serveur,serveur.getManager());
if(erreur)
{
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getMoveError("Check the targeted role. ")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
else
{
StringBuilder roleStr = new StringBuilder("");
boolean first = true;
for( Role role : roleL)
{
if (!first) {
roleStr.append(", ");
}
else
first = false;
roleStr.append("__");
roleStr.append(role.getName());
roleStr.append("__");
}
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getMoveOk("User "+user.getEffectiveName()+" as been successfully moved to "+roleStr.toString())).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
}catch (HierarchyException e){
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getMoveError("You cannot move "+user.getRoles().get(0).getAsMention())).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
logger.error("Hierarchy error, please move bot's role on top!");
}
}
}
else
{
logger.warn("Missing argument.");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getMoveError("Missing argument.")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
}
else
event.getPrivateChannel().sendMessage(EmbedMessageUtils.getNoPrivate());
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return true;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,182 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.MainBot;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.MessageTimeOut;
import net.Broken.audio.AudioM;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.VoiceChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
/**
* Music commands
*/
public class Music implements Commande {
private Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event) {
AudioM audio = AudioM.getInstance(event.getGuild());
if(args.length >= 1){
switch (args[0]){
case "play":
event.getTextChannel().sendTyping().queue();
if(args.length>=2){
if(event.getMember().getVoiceState().inVoiceChannel()){
VoiceChannel voiceChanel = event.getMember().getVoiceState().getChannel();
logger.info("Connecting to "+voiceChanel.getName()+"...");
if(args.length ==2){
audio.loadAndPlay(event,voiceChanel,args[1],30,false);
}
else if(args.length == 3){
try{
int limit = Integer.parseInt(args[2]);
audio.loadAndPlay(event,voiceChanel,args[1],limit,false);
}catch (NumberFormatException e){
audio.loadAndPlay(event,voiceChanel,args[1],30,false);
}
}
}
else{
Message message = event.getTextChannel().sendMessage(EmbedMessageUtils.getMusicError("You are not in a voice channel !")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(message);
add(event.getMessage());
}};
new MessageTimeOut(messages, MainBot.messageTimeOut).start();
}
}
else{
Message message = event.getTextChannel().sendMessage(EmbedMessageUtils.getMusicError("Missing argument!")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(message);
add(event.getMessage());
}};
new MessageTimeOut(messages, MainBot.messageTimeOut).start();
}
break;
case "pause":
audio.pause(event);
break;
case "resume":
audio.resume(event);
break;
case "next":
audio.skipTrack(event);
break;
case "stop":
audio.stop(event);
break;
case "info":
audio.info(event);
break;
case "flush":
audio.flush(event);
break;
case "list":
audio.list(event);
break;
case "add":
event.getTextChannel().sendTyping().queue();
if(args.length ==2){
audio.add(event,args[1],30,false);
}
else if(args.length == 3){
try{
int limit = Integer.parseInt(args[2]);
audio.add(event,args[1],limit,false);
}catch (NumberFormatException e){
audio.add(event,args[1],30,false);
}
}
else{
Message message = event.getTextChannel().sendMessage(EmbedMessageUtils.getMusicError("Missing argument!")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(message);
add(event.getMessage());
}};
new MessageTimeOut(messages, MainBot.messageTimeOut).start();
}
break;
case "addNext":
event.getTextChannel().sendTyping().queue();
if(args.length >=2){
audio.add(event,args[1],1,true);
}
else{
Message message = event.getTextChannel().sendMessage(EmbedMessageUtils.getMusicError("Missing argument!")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(message);
add(event.getMessage());
}};
new MessageTimeOut(messages, MainBot.messageTimeOut).start();
}
break;
case "disconnect":
audio.stop();
List<Message> messages = new ArrayList<Message>(){{
add(event.getMessage());
}};
new MessageTimeOut(messages, 0).start();
break;
default:
Message message = event.getTextChannel().sendMessage(EmbedMessageUtils.getMusicError("Unknown argument!")).complete();
List<Message> messagess = new ArrayList<Message>(){{
add(message);
add(event.getMessage());
}};
new MessageTimeOut(messagess, MainBot.messageTimeOut).start();
break;
}
}
else{
Message message = event.getTextChannel().sendMessage(EmbedMessageUtils.getMusicError("Missing argument!")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(message);
add(event.getMessage());
}};
new MessageTimeOut(messages, MainBot.messageTimeOut).start();
}
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,26 +1,25 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.Tools.UserManager.Stats.UserStatsUtils;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
public class Rank implements Commande {
public class Ordre66 implements Commande {
@Override
public void action(String[] args, MessageReceivedEvent event) {
UserStatsUtils userStats = UserStatsUtils.getINSTANCE();
MessageEmbed msg = userStats.getRankMessage(event.getMember());
event.getTextChannel().sendMessage(msg).queue();
Message rest = event.getTextChannel().sendMessage("Très bien maître " + event.getAuthor().getAsMention() + ". J'arrive ! ").complete();
Message reste = event.getTextChannel().sendMessage("https://media2.giphy.com/media/UfzTayIyH7g5hk2BA2/giphy.gif\n").complete();
}
@Override
public boolean isPrivateUsable() {
return false;
return true;
}
@Override
public boolean isAdminCmd() {
return false;
return true;
}
/**

View File

@ -1,47 +0,0 @@
package net.Broken.Commands.Over18;
import net.Broken.Tools.Command.NoDev;
import net.Broken.Tools.Command.NumberedCommande;
import org.apache.logging.log4j.LogManager;
/**
* Ass command, return random picture from les400culs.com
*/
@NoDev()
public class Ass extends NumberedCommande {
public Ass() {
super(LogManager.getLogger(), "http://les400culs.com/","-2/","featured-img","img");
}
@Override
public String toString() {
return "Ass";
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return true;
}
}

View File

@ -1,45 +0,0 @@
package net.Broken.Commands.Over18;
import net.Broken.Tools.Command.NoDev;
import net.Broken.Tools.Command.NumberedCommande;
import org.apache.logging.log4j.LogManager;
/**
* Boobs command, return random picture from lesaintdesseins.fr
*/
@NoDev()
public class Boobs extends NumberedCommande {
public Boobs() {
super(LogManager.getLogger(), "http://lesaintdesseins.fr/","-2/","featured-img","img");
}
@Override
public String toString() {
return "Boobs";
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return true;
}
}

View File

@ -1,45 +0,0 @@
package net.Broken.Commands.Over18;
import net.Broken.Tools.Command.NoDev;
import net.Broken.Tools.Command.NumberedCommande;
import org.apache.logging.log4j.LogManager;
/**
* Ass command, return random picture from feelation.com
*/
@NoDev()
public class Pipe extends NumberedCommande {
public Pipe() {
super(LogManager.getLogger(), "http://feelation.com/","-2/","featured-img","img");
}
@Override
public String toString() {
return "Pipe";
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return true;
}
}

View File

@ -1,57 +0,0 @@
package net.Broken.Commands.Over18;
import net.Broken.Commande;
import net.Broken.Tools.FindContentOnWebPage;
import net.Broken.Tools.Redirection;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
/**
* TODO Remove this
*/
public class SM implements Commande {
Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event) {
Redirection redirect= new Redirection();
try {
String redirectUrl = redirect.get("https://bonjourfetish.tumblr.com/random");
logger.debug(redirectUrl);
String img = FindContentOnWebPage.doYourJob(redirectUrl, "article-picture center", "img");
event.getTextChannel().sendMessage(img).queue();
} catch (IOException e) {
logger.warn("Redirection fail.");
event.getTextChannel().sendMessage(event.getAuthor().getAsMention() + "\n:warning: **__Redirection fail (5 attempt), Try again__**:warning: ").queue();
}
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return true;
}
}

View File

@ -1,86 +0,0 @@
package net.Broken.Commands.Over18;
import net.Broken.Commande;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.FindContentOnWebPage;
import net.Broken.Tools.Redirection;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
public class Suicide implements Commande{
private Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event) {
Redirection redirection = new Redirection();
String base = "http://suicidegirls.tumblr.com";
String redirectUrl = null;
try {
Boolean success = false;
int tryCount = 0;
while(!success && tryCount < 10 ){
redirectUrl = redirection.get(base + "/random");
String img;
try{
img = FindContentOnWebPage.doYourJob(redirectUrl, "post photo_nav_caption", "img");
event.getTextChannel().sendMessage(img).queue();
success = true;
}catch (StringIndexOutOfBoundsException | IOException e){
logger.debug("Photo_nav not found try photoset");
try {
String mid = FindContentOnWebPage.doYourJob(redirectUrl, "html_photoset", "iframe");
img = FindContentOnWebPage.doYourJob(base + mid, "photoset_row", "img");
event.getTextChannel().sendMessage(img).queue();
success = true;
} catch (StringIndexOutOfBoundsException | IOException e1) {
logger.debug("Nothing found, assume it's a comment.");
}
}
tryCount ++;
}
} catch (IOException e) {
logger.catching(e);
}
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return true;
}
}

View File

@ -1,54 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.MainBot;
import net.Broken.Tools.MessageTimeOut;
import net.dv8tion.jda.api.entities.ChannelType;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
/**
* Command that return the Bot's ping
*/
public class Ping implements Commande {
@Override
public void action(String[] args, MessageReceivedEvent event) {
long ping = event.getJDA().getGatewayPing();
// long receivedTime = Timestamp.valueOf(LocalDateTime.ofInstant(event.getMessage().getCreationTime().toInstant(), ZoneId.systemDefault())).getTime();
if(event.isFromType(ChannelType.PRIVATE))
event.getPrivateChannel().sendMessage(":arrow_right: Pong! `" + ping+ "ms`").queue();
else {
Message rest = event.getTextChannel().sendMessage(event.getAuthor().getAsMention()+"\n:arrow_right: Pong! `" + ping + "ms`").complete();
new MessageTimeOut(MainBot.messageTimeOut, event.getMessage(), rest).start();
}
LogManager.getLogger().debug("pong");
}
@Override
public boolean isPrivateUsable() {
return true;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -0,0 +1,69 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.requests.RestAction;
import java.util.Objects;
public class ReportUsers implements Commande {
@Override
public void action(String[] args, MessageReceivedEvent event) {
event.getGuild().loadMembers().onSuccess(members -> {
if (event.getMessage().getMentionedRoles().size() == 1 && args.length == 1) {
RestAction<Void> restAction = null;
for (Member member : members) {
if (member.getRoles().size() == 1) { //check if the member has a role
if (member.getRoles().contains(event.getMessage().getMentionedRoles().get(0))) { //check if the mentioned role is the same as the member's role
restAction = Objects.requireNonNullElseGet(restAction, () -> event.getTextChannel().sendMessage("List des membres : "))
.and(event.getTextChannel().sendMessage(member.getEffectiveName()));
}
}
}
if (restAction != null)
restAction.queue();
} else if (args.length == 0) {
for (Member member : members) {
if (member.getRoles().size() == 0) {
event.getTextChannel().sendMessage(member.getEffectiveName()).complete();
}
}
} else {
event.getTextChannel().sendMessage(EmbedMessageUtils.getReportUsersError()).complete();
}
});
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return true;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,73 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository;
import net.Broken.MainBot;
import net.Broken.SpringContext;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.MessageTimeOut;
import net.Broken.Tools.SettingsUtils;
import net.Broken.audio.AudioM;
import net.Broken.audio.NotConnectedException;
import net.Broken.audio.NullMusicManager;
import net.Broken.audio.Youtube.YoutubeTools;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationContext;
import java.awt.*;
import java.io.IOException;
import java.util.List;
public class Settings implements Commande {
private Logger logger = LogManager.getLogger();
private GuildPreferenceRepository guildPreferenceRepository;
public Settings() {
ApplicationContext context = SpringContext.getAppContext();
guildPreferenceRepository = (GuildPreferenceRepository) context.getBean("guildPreferenceRepository");
}
@Override
public void action(String[] args, MessageReceivedEvent event) {
EmbedBuilder builder = new EmbedBuilder()
.setTitle("Settings")
.setDescription("You can do all the configuration on the web page in the \"Bot Settings\" menu.\nhttps://"+MainBot.url).setColor(Color.green);
event.getTextChannel().sendMessage(EmbedMessageUtils.buildStandar(builder)).queue();
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return true;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,351 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.MainBot;
import net.Broken.Tools.AntiSpam;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.MessageTimeOut;
import net.Broken.Tools.UserSpamUtils;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.exceptions.RateLimitedException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Spam admin command
*/
// TODO Rebuild this ...
public class Spam implements Commande {
private Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event)
{
/****************************
* Verif argument *
****************************/
if(args.length>=1)
{
String commande = args[0];
/****************************
* on traite la commande *
****************************/
switch (commande) {
case "pardon":
this.pardon(event,args);
break;
case "extermine":
try {
this.extermine(event,args);
} catch (RateLimitedException e) {
e.printStackTrace();
}
break;
case "reset":
try {
this.reset(event,args);
} catch (RateLimitedException e) {
e.printStackTrace();
}
break;
}
}
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return true;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
public void pardon(MessageReceivedEvent event, String[] args){
Guild serveur = event.getGuild();
/****************************
* verif argument *
****************************/
if (args.length >= 1)
{
/****************************
* On recupere l'utilisateur et le role cible
****************************/
List<Member> userL = event.getMessage().getMentionedMembers();
/****************************
* verif utilisteur trouver *
****************************/
if(userL.size()<1)
{
logger.error("User unknown.");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamError(":arrow_right: User not found. ","pardon")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
else {
Member user = userL.get(0);
logger.info("Attempt to forgive " + user.getEffectiveName() + " by " + event.getMember().getEffectiveName());
/****************************
* virif si en spammer *
****************************/
if (MainBot.spamUtils.containsKey(user)) {
if (MainBot.spamUtils.get(user).isOnSpam()) {
MainBot.spamUtils.get(user).setOnSpam(false);
} else {
logger.warn("User is not in spam.");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamError(":arrow_right: This user is not in spam.","pardon")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
} else {
logger.warn("User is not in spam.");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamError(":arrow_right: This user is not in spam.","pardon")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
}
}
else
{
logger.warn("Missing argument.");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamError("Missing argument!","pardon")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
}
public void extermine(MessageReceivedEvent event, String[] args) throws RateLimitedException {
/****************************
* verif argument *
****************************/
if (args.length >= 3)
{
/****************************
* On recupere l'utilisateur et le role cible
****************************/
List<User> userL = event.getMessage().getMentionedUsers();
/****************************
* verif utilisteur trouver *
****************************/
if(userL.size()<1)
{
logger.warn("Wrong mention (Spam).");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamError("Wrong mention. ","extermine")).complete();
}
else{
Guild serveur = event.getGuild();
Member user = serveur.getMember(userL.get(0));
logger.info("Starting protocol 66 on "+user.getEffectiveName()+" by the command of "+event.getAuthor().getName());
String multiStr =args[2];
/****************************
* virif pas deja en spammer *
****************************/
if(MainBot.spamUtils.containsKey(user))
{
if(!MainBot.spamUtils.get(user).isOnSpam())
{
this.goSpam(user,multiStr,serveur,event);
}
else
{
logger.warn("User already in spam.");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamError("User already in spam.","extermine")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
}
else
{
this.goSpam(user,multiStr,serveur,event);
}
}
}
else
{
logger.warn("Missing argument.");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamError("Missing argument!","extermine")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
}
public void reset(MessageReceivedEvent event, String[] args) throws RateLimitedException {
if(event!=null)
{
if(args.length>=2)
{
Guild serveur = event.getGuild();
/****************************
* On recupere l'utilisateur et le role cible
****************************/
List<Member> userL = event.getMessage().getMentionedMembers();
/****************************
* verif utilisteur trouver *
****************************/
if(userL.size()<1)
{
logger.warn("User not found.");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamError("User not found.","reset")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
else {
Member user = userL.get(0);
logger.info("Attempt spam reset of " + user.getEffectiveName() + " by " + event.getMember().getEffectiveName());
/****************************
* verif utilisteur trouver *
****************************/
if (MainBot.spamUtils.containsKey(user)) {
logger.info("Multiplictor reset for " + user.getEffectiveName() + " done.");
Message rest = event.getTextChannel().sendMessage(event.getAuthor().getAsMention() + "\n *The spam multiplicator of " + user.getEffectiveName() + " is now down to zero.*").complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
MainBot.spamUtils.remove(user);
}
}
}
else
{
logger.warn("Missing argument.");
Message rest = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamError("Missing argument!","reset")).complete();
List<Message> messages = new ArrayList<Message>(){{
add(rest);
add(event.getMessage());
}};
new MessageTimeOut(messages,MainBot.messageTimeOut).start();
}
}
else
{
if (args[0].equals("all"))
{
logger.info("Multiplicator reseted automaticly.");
for (Member unUser: MainBot.spamUtils.keySet())
{
MainBot.message_compteur.remove(unUser); //TODO resolve garbage collector error ????
}
}
}
}
public void goSpam(Member user, String multiStr, Guild serveur, MessageReceivedEvent event)
{
if(Objects.equals(multiStr, "/"))
{
new AntiSpam().extermine(user,serveur,serveur.getManager(),true,event);
}
else
{
int multi = Integer.parseInt(multiStr);
if(MainBot.spamUtils.containsKey(user))
{
MainBot.spamUtils.get(user).setMultip(multi);
}
else
{
MainBot.spamUtils.put(user,new UserSpamUtils(user,new ArrayList<>()));
MainBot.spamUtils.get(user).setMultip(multi);
}
new AntiSpam().extermine(user,serveur,serveur.getManager(),false,event);
}
}
}

View File

@ -1,200 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.MainBot;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.MessageTimeOut;
import net.Broken.Tools.PrivateMessage;
import net.Broken.Tools.UserSpamUtils;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.ChannelType;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Spam Info Command
*/
public class SpamInfo implements Commande{
private HashMap<Member,MessageUpdater> threadHashMap = new HashMap<>();
Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event) {
Member user;
if(event.getMessage().getMentionedUsers().size() == 0){
user = event.getMember();
}
else {
user = event.getMessage().getMentionedMembers().get(0);
}
Message message = null;
if(!MainBot.spamUtils.containsKey(user)){
if(!event.isFromType(ChannelType.PRIVATE))
message = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamInfo(user.getEffectiveName() + ":\n\t- Multiplicator: `1`\n\t- In spam: `No`")).complete();
else
PrivateMessage.send(event.getAuthor(),EmbedMessageUtils.getSpamInfo(user.getEffectiveName()+":\n\t- Multiplicator: `1`\n\t- In spam: `No`"),logger);
}
else{
UserSpamUtils util = MainBot.spamUtils.get(user);
if(!util.isOnSpam()){
if(!event.isFromType(ChannelType.PRIVATE))
message = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamInfo(user.getEffectiveName()+"\n\t- Multiplicator: `"+util.getMultip()+"`\n\t- In spam: `No`")).complete();
else
PrivateMessage.send(event.getAuthor(),EmbedMessageUtils.getSpamInfo(user.getEffectiveName()+":\n\t- Multiplicator: `"+util.getMultip()+"`\n\t- In spam: `No`"),logger);
}
else{
if(!event.isFromType(ChannelType.PRIVATE))
message = event.getTextChannel().sendMessage(EmbedMessageUtils.getSpamInfo(user.getEffectiveName()+":\n\t- Multiplicator: `"+util.getMultip()+"`\n\t- In spam: `Yes`\n\t- Time remaining: `"+formatSecond(util.getTimeLeft())+"`")).complete();
else
message = PrivateMessage.send(event.getAuthor(),EmbedMessageUtils.getSpamInfo(user.getEffectiveName()+"\n\t- Multiplicator: `"+util.getMultip()+"`\n\t- In spam: `Yes`\n\t- Time remaining: `"+formatSecond(util.getTimeLeft())+"`"),logger);
}
}
if(message != null){
if(threadHashMap.containsKey(user)){
MessageUpdater startedThread = threadHashMap.get(user);
if(!message.getChannelType().equals(startedThread.message.getChannelType())){
MessageUpdater newThread = new MessageUpdater(message,event.getMessage(),MainBot.spamUtils.get(user),user);
threadHashMap.put(user,newThread);
newThread.start();
}
else
{
threadHashMap.get(user).stop = true;
MessageUpdater newThread = new MessageUpdater(message,event.getMessage(),MainBot.spamUtils.get(user),user);
threadHashMap.replace(user, newThread);
newThread.start();
}
}
else
{
MessageUpdater newThread = new MessageUpdater(message,event.getMessage(),MainBot.spamUtils.get(user),user);
threadHashMap.put(user, newThread);
newThread.start();
}
}
}
@Override
public boolean isPrivateUsable() {
return true;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
public String formatSecond(int second){
long days = TimeUnit.SECONDS.toDays(second);
second -= TimeUnit.DAYS.toSeconds(days);
long hours = TimeUnit.SECONDS.toHours(second);
second -= TimeUnit.HOURS.toSeconds(hours);
long minutes = TimeUnit.SECONDS.toMinutes(second);
second -= TimeUnit.MINUTES.toSeconds(minutes);
long seconds = TimeUnit.SECONDS.toSeconds(second);
logger.debug(""+days+":"+hours+":"+minutes+":"+seconds);
String finalText = "";
if(days!=0)
finalText += days+" day(s) ";
if(hours!=0)
finalText += hours+"h ";
if(minutes!=0)
finalText += minutes+"min ";
finalText += seconds+"s";
return finalText;
}
private class MessageUpdater extends Thread{
public Message message;
public Message command;
public UserSpamUtils util;
public boolean stop;
private int oldValue;
private Member user;
public MessageUpdater(Message message,Message command, UserSpamUtils util, Member user) {
this.message = message;
this.util = util;
this.user = user;
this.command = command;
}
@Override
public void run() {
logger.debug("Start "+user.getEffectiveName()+" theard!");
if(util != null){
oldValue = util.getTimeLeft();
while (util.getTimeLeft()!=0 && !stop && util.isOnSpam()){
try {
Thread.sleep(500);
if(util.getTimeLeft()%5 == 0 && oldValue - util.getTimeLeft() >= 5){
message.editMessage(EmbedMessageUtils.getSpamInfo(user.getEffectiveName()+":\n\t- Multiplicator: `"+util.getMultip()+"`\n\t- In spam: `Yes`\n\t- Time remaining: `"+formatSecond(util.getTimeLeft())+"`")).complete();
oldValue = util.getTimeLeft();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
logger.debug("Kill "+user.getEffectiveName()+" theard!");
if(stop)
message.editMessage(new EmbedBuilder().setColor(Color.RED).setTitle("Aborted").build()).complete();
else
message.editMessage(EmbedMessageUtils.getSpamInfo(user.getEffectiveName()+"\n\t- Multiplicator: `"+util.getMultip()+"`\n\t- In spam: `No`")).complete();
}
logger.debug("Timer for message deletion of "+user.getEffectiveName()+" stated...");
threadHashMap.remove(user);
List<Message> messages = new ArrayList<>();
messages.add(command);
messages.add(message);
new MessageTimeOut(messages,15).start();
}
}
}

View File

@ -1,79 +0,0 @@
package net.Broken.Commands;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import net.Broken.Commande;
import net.Broken.MainBot;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.MessageTimeOut;
import net.Broken.audio.Youtube.SearchResult;
import net.Broken.audio.Youtube.YoutubeSearchRework;
import net.Broken.audio.Youtube.YoutubeTools;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class YtSearch implements Commande {
private Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event) {
YoutubeSearchRework youtubeSearch = YoutubeSearchRework.getInstance();
if (args.length < 1) {
logger.info("YtSearch: Missing args, user: " + event.getAuthor().getName());
Message message = event.getChannel().sendMessage(EmbedMessageUtils.buildStandar(EmbedMessageUtils.getError("Missing search query!"))).complete();
new MessageTimeOut(MainBot.messageTimeOut, message, event.getMessage()).start();
} else {
try {
StringBuilder builder = new StringBuilder();
for (String arg : args) {
builder.append(arg);
}
List<SearchResult> result = youtubeSearch.searchVideo(builder.toString(), 5, false);
for (SearchResult item : result) {
event.getChannel().sendMessage(EmbedMessageUtils.searchResult(item)).queue();
}
} catch (IOException t) {
logger.catching(t);
event.getChannel().sendMessage(EmbedMessageUtils.getInternalError()).queue();
}
}
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return false;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,22 +1,16 @@
package net.Broken.DB.Entity;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.VoiceChannel;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class GuildPreferenceEntity {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(unique=true)
private String guildId;
private boolean antiSpam;
private boolean welcome;
private String welcomeMessage;
@ -29,33 +23,39 @@ public class GuildPreferenceEntity {
private boolean dailyMadame;
@ElementCollection
private List<String> visibleVoiceChanel;
private boolean autoVoice;
private String autoVoiceChannelID;
private String autoVoiceChannelTitle;
public GuildPreferenceEntity(String guildId, boolean antiSpam, boolean welcome, String welcomeMessage, String welcomeChanelID, boolean defaultRole, String defaultRoleId, boolean dailyMadame, ArrayList<String> visibleVoiceChanel) {
public GuildPreferenceEntity(String guildId,
boolean welcome,
String welcomeMessage,
String welcomeChanelID,
boolean defaultRole,
String defaultRoleId,
boolean dailyMadame,
boolean autoVoice,
String autoVoiceChannelID,
String autoVoiceChannelTitle) {
this.guildId = guildId;
this.antiSpam = antiSpam;
this.welcome = welcome;
this.welcomeMessage = welcomeMessage;
this.welcomeChanelID = welcomeChanelID;
this.defaultRole = defaultRole;
this.defaultRoleId = defaultRoleId;
this.dailyMadame = dailyMadame;
this.visibleVoiceChanel = visibleVoiceChanel;
this.autoVoice = autoVoice;
this.autoVoiceChannelID = autoVoiceChannelID;
this.autoVoiceChannelTitle = autoVoiceChannelTitle;
}
public GuildPreferenceEntity(){}
public static GuildPreferenceEntity getDefault(Guild guild){
ArrayList<String> voice = new ArrayList<>();
for(VoiceChannel voiceChannel : guild.getVoiceChannels()){
voice.add(voiceChannel.getId());
public GuildPreferenceEntity() {
}
return new GuildPreferenceEntity(guild.getId(), false, false, "Welcome to this awesome server @name! ", " ", false, " ", true, voice);
public static GuildPreferenceEntity getDefault(String guildId) {
return new GuildPreferenceEntity(guildId, false, "Welcome to this awesome server @name! ", null, false, null, true, false, null, null);
}
public Integer getId() {
@ -74,14 +74,6 @@ public class GuildPreferenceEntity {
this.guildId = guildId;
}
public boolean isAntiSpam() {
return antiSpam;
}
public void setAntiSpam(boolean antiSpam) {
this.antiSpam = antiSpam;
}
public boolean isWelcome() {
return welcome;
}
@ -130,11 +122,27 @@ public class GuildPreferenceEntity {
this.dailyMadame = dailyMadame;
}
public List<String> getVisibleVoiceChanel() {
return visibleVoiceChanel;
public boolean isAutoVoice() {
return autoVoice;
}
public void setVisibleVoiceChanel(List<String> visibleVoiceChanel) {
this.visibleVoiceChanel = visibleVoiceChanel;
public void setAutoVoice(boolean autoVoice) {
this.autoVoice = autoVoice;
}
public String getAutoVoiceChannelID() {
return autoVoiceChannelID;
}
public void setAutoVoiceChannelID(String autoVoiceChannelID) {
this.autoVoiceChannelID = autoVoiceChannelID;
}
public String getAutoVoiceChannelTitle() {
return autoVoiceChannelTitle;
}
public void setAutoVoiceChannelTitle(String autoVoiceChannelTitle) {
this.autoVoiceChannelTitle = autoVoiceChannelTitle;
}
}

View File

@ -1,56 +0,0 @@
package net.Broken.DB.Entity;
import javax.persistence.*;
import java.util.Calendar;
import java.util.Date;
@Entity
public class PendingPwdResetEntity {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
@OneToOne
private UserEntity userEntity;
private String securityToken;
private Date expirationDate;
public PendingPwdResetEntity(UserEntity userEntity,String token) {
this.userEntity = userEntity;
this.securityToken = token;
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.HOUR, 24);
expirationDate = cal.getTime();
}
public PendingPwdResetEntity() {}
public UserEntity getUserEntity() {
return userEntity;
}
public void setUserEntity(UserEntity userEntity) {
this.userEntity = userEntity;
}
public String getSecurityToken() {
return securityToken;
}
public void setSecurityToken(String securityToken) {
this.securityToken = securityToken;
}
public Date getExpirationDate() {
return expirationDate;
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
}

View File

@ -1,77 +0,0 @@
package net.Broken.DB.Entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* Entity for DB. Represent user who not yet confirmed her account.
*/
@Entity
public class PendingUserEntity {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String name;
private String jdaId;
private String checkToken;
private String password;
public PendingUserEntity() {
}
public PendingUserEntity(String name, String jdaId, String checkToken, String password) {
this.name = name;
this.jdaId = jdaId;
this.checkToken = checkToken;
this.password = password;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJdaId() {
return jdaId;
}
public void setJdaId(String jdaId) {
this.jdaId = jdaId;
}
public String getCheckToken() {
return checkToken;
}
public void setCheckToken(String checkToken) {
this.checkToken = checkToken;
}
}

View File

@ -1,83 +0,0 @@
package net.Broken.DB.Entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.annotation.Nullable;
import javax.persistence.*;
import javax.sound.midi.Track;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Entity
public class PlaylistEntity {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String name;
@JsonIgnore
@ManyToOne
@JoinColumn(name="userEntity_id", nullable=false)
private UserEntity user;
@OneToMany(mappedBy = "playlist")
private List<TrackEntity> tracks;
public PlaylistEntity() {
}
public PlaylistEntity(String name, UserEntity user) {
this.name = name;
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
public List<TrackEntity> getTracks() {
return tracks;
}
public void setTracks(List<TrackEntity> tracks) {
this.tracks = tracks;
}
public void addTracks(TrackEntity... tracks )
{
if(this.tracks == null)
this.tracks = new ArrayList<>();
this.tracks.addAll(Arrays.asList(tracks));
}
}

View File

@ -1,94 +0,0 @@
package net.Broken.DB.Entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import javax.persistence.*;
@Entity
public class TrackEntity {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private String title;
private String url;
private String identifier;
private Integer pos;
@JsonIgnore
@ManyToOne
@JoinColumn(name="playlistEntity_id", nullable=false)
private PlaylistEntity playlist;
public TrackEntity() {
}
public TrackEntity(AudioTrackInfo trackInfo, int pos, PlaylistEntity playlist) {
this.title = trackInfo.title;
this.url = trackInfo.uri;
this.identifier = trackInfo.identifier;
this.playlist = playlist;
this.pos = pos;
}
public TrackEntity(TrackEntity trackEntity){
this.title = trackEntity.title;
this.url = trackEntity.url;
this.identifier = trackEntity.identifier;
this.pos = trackEntity.pos;
this.playlist = trackEntity.playlist;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public PlaylistEntity getPlaylist() {
return playlist;
}
public void setPlaylist(PlaylistEntity playlist) {
this.playlist = playlist;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public Integer getPos() {
return pos;
}
public void setPos(Integer pos) {
this.pos = pos;
}
}

View File

@ -1,13 +1,10 @@
package net.Broken.DB.Entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import net.Broken.Tools.UserManager.UserUtils;
import net.Broken.Api.Security.Data.DiscordOauthUserInfo;
import net.dv8tion.jda.api.entities.User;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -16,14 +13,17 @@ import java.util.List;
@Entity
public class UserEntity {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String username;
private String jdaId;
private String discriminator;
private String apiToken;
@Column(unique = true)
private String discordId;
private String avatar;
private boolean isBotAdmin = false;
@ -31,47 +31,27 @@ public class UserEntity {
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
private List<UserStats> userStats;
@JsonIgnore
private String password;
@OneToMany(mappedBy = "user")
private List<PlaylistEntity> playlists;
public UserEntity() {
}
public UserEntity(PendingUserEntity pendingUserEntity, String apiToken) {
this.name = pendingUserEntity.getName();
this.jdaId = pendingUserEntity.getJdaId();
this.password = pendingUserEntity.getPassword();
this.apiToken = apiToken;
public UserEntity(User user) {
this.username = user.getName();
this.discordId = user.getId();
}
public UserEntity(User user, PasswordEncoder passwordEncoder){
this.name = user.getName();
this.jdaId = user.getId();
this.apiToken = UserUtils.getInstance().generateApiToken();
this.password = passwordEncoder.encode(UserUtils.getInstance().generateCheckToken());
public UserEntity(String username, String id) {
this.username = username;
this.discordId = id;
}
public UserEntity(String name, String id, PasswordEncoder passwordEncoder){
this.name = name;
this.jdaId = id;
this.apiToken = UserUtils.getInstance().generateApiToken();
this.password = passwordEncoder.encode(UserUtils.getInstance().generateCheckToken());
public UserEntity(DiscordOauthUserInfo discordOauthUserInfo) {
this.username = discordOauthUserInfo.username();
this.discriminator = discordOauthUserInfo.discriminator();
this.discordId = discordOauthUserInfo.id();
this.avatar = discordOauthUserInfo.avatar();
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getId() {
return id;
}
@ -80,43 +60,20 @@ public class UserEntity {
this.id = id;
}
public String getName() {
return name;
public void setUsername(String username) {
this.username = username;
}
public void setName(String name) {
this.name = name;
public String getUsername() {
return username;
}
public String getJdaId() {
return jdaId;
public String getDiscordId() {
return discordId;
}
public void setJdaId(String jdaId) {
this.jdaId = jdaId;
}
public String getApiToken() {
return apiToken;
}
public void setApiToken(String apiToken) {
this.apiToken = apiToken;
}
public List<PlaylistEntity> getPlaylists() {
return playlists;
}
public void setPlaylists(List<PlaylistEntity> playlists) {
this.playlists = playlists;
}
public void addPlaylist(PlaylistEntity... playlists){
if(this.playlists == null)
this.playlists = new ArrayList<>();
this.playlists.addAll(Arrays.asList(playlists));
public void setDiscordId(String discordId) {
this.discordId = discordId;
}
public List<UserStats> getUserStats() {
@ -134,4 +91,20 @@ public class UserEntity {
public void setBotAdmin(boolean botAdmin) {
isBotAdmin = botAdmin;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getDiscriminator() {
return discriminator;
}
public void setDiscriminator(String discriminator) {
this.discriminator = discriminator;
}
}

View File

@ -8,7 +8,7 @@ import javax.persistence.*;
public class UserStats {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ -27,7 +27,8 @@ public class UserStats {
@ColumnDefault("0")
private Long apiCommandCount = 0L;
public UserStats(){}
public UserStats() {
}
public UserStats(String guildId, UserEntity user) {
this.guildId = guildId;

View File

@ -3,9 +3,9 @@ package net.Broken.DB.Repository;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
import java.util.Optional;
public interface GuildPreferenceRepository extends CrudRepository<GuildPreferenceEntity, Integer> {
List<GuildPreferenceEntity> findByGuildId(String id);
Optional<GuildPreferenceEntity> findByGuildId(String id);
}

View File

@ -1,11 +0,0 @@
package net.Broken.DB.Repository;
import net.Broken.DB.Entity.PendingPwdResetEntity;
import net.Broken.DB.Entity.UserEntity;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface PendingPwdResetRepository extends CrudRepository<PendingPwdResetEntity,Integer>{
List<PendingPwdResetEntity> findByUserEntity(UserEntity userEntity);
}

View File

@ -1,17 +0,0 @@
package net.Broken.DB.Repository;
import net.Broken.DB.Entity.PendingUserEntity;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
/**
* Repository for PendingUserEntity
*/
public interface PendingUserRepository extends CrudRepository<PendingUserEntity, Integer> {
List<PendingUserEntity> findByJdaId(String jdaId);
PendingUserEntity findById(int id);
}

View File

@ -1,8 +0,0 @@
package net.Broken.DB.Repository;
import net.Broken.DB.Entity.PlaylistEntity;
import org.springframework.data.repository.CrudRepository;
public interface PlaylistRepository extends CrudRepository<PlaylistEntity, Integer> {
PlaylistEntity findById(int id);
}

View File

@ -1,13 +0,0 @@
package net.Broken.DB.Repository;
import net.Broken.DB.Entity.PlaylistEntity;
import net.Broken.DB.Entity.TrackEntity;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface TrackRepository extends CrudRepository<TrackEntity, Integer> {
List<TrackEntity> findDistinctByPlaylistOrderByPos(PlaylistEntity playlistEntity);
TrackEntity findById(int id);
}

View File

@ -4,13 +4,14 @@ import net.Broken.DB.Entity.UserEntity;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
import java.util.Optional;
/**
* Repository for UserEntity
*/
public interface UserRepository extends CrudRepository<UserEntity, Integer> {
List<UserEntity> findByName(String name);
List<UserEntity> findByJdaId(String jdaId);
List<UserEntity> findByApiToken(String apiToken);
List<UserEntity> findByUsername(String username);
Optional<UserEntity> findByDiscordId(String discordId);
}

View File

@ -8,7 +8,9 @@ import java.util.List;
public interface UserStatsRepository extends CrudRepository<UserStats, Long> {
List<UserStats> findByUser(UserEntity userEntity);
List<UserStats> findByGuildId(String guildId);
List<UserStats> findByUserAndGuildId(UserEntity user, String guildId);
}

View File

@ -1,14 +1,13 @@
package net.Broken;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository;
import net.Broken.DB.Repository.UserRepository;
import net.Broken.RestApi.ApiCommandLoader;
import net.Broken.Tools.Command.CommandLoader;
import net.Broken.Tools.Command.SlashCommandLoader;
import net.Broken.Tools.DayListener.DayListener;
import net.Broken.Tools.DayListener.Listeners.DailyMadame;
import net.Broken.Tools.DayListener.Listeners.ResetSpam;
import net.Broken.Tools.UserManager.Stats.UserStatsUtils;
import net.dv8tion.jda.api.AccountType;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.OnlineStatus;
@ -24,85 +23,57 @@ import javax.security.auth.login.LoginException;
import java.util.List;
public class Init {
static private Logger logger = LogManager.getLogger();
static private final Logger logger = LogManager.getLogger();
/**
* Initialize all bot functionality
*
* @param token bot user token
* @return JDA object
*/
static JDA initJda(String token) {
JDA jda = null;
static JDA initJda(BotConfigLoader config) {
logger.info("-----------------------INIT-----------------------");
//Bot démarrer sans token
if (token == null) {
if (config == null) {
logger.fatal("Please enter bot token as an argument.");
return null;
} else {
//Token présent
try {
logger.info("Connecting to Discord api...");
//connection au bot
JDABuilder jdaB = JDABuilder.createDefault(token).enableIntents(GatewayIntent.GUILD_MEMBERS)
.setMemberCachePolicy(MemberCachePolicy.ALL);
jdaB.setBulkDeleteSplittingEnabled(false);
jda = jdaB.build();
jda = jda.awaitReady();
MainBot.jda = jda;
jda.setAutoReconnect(true);
JDA jda = JDABuilder
.createDefault(config.token())
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.setMemberCachePolicy(MemberCachePolicy.ALL)
.setBulkDeleteSplittingEnabled(false)
.build();
/*************************************
* Definition des commande *
*************************************/
jda.awaitReady()
.setAutoReconnect(true);
jda.getPresence().setPresence(OnlineStatus.DO_NOT_DISTURB, Activity.playing("Loading..."));
jda.getTextChannels().forEach(textChannel -> {
if (textChannel.canTalk())
textChannel.sendTyping().queue();
});
//On recupere le l'id serveur
logger.info("Connected on " + jda.getGuilds().size() + " Guilds:");
for (Guild server : jda.getGuilds()) {
server.loadMembers().get();
//on recupere les utilisateur
logger.info("... " + server.getName() + " " + server.getMembers().size() + " Members");
}
return jda;
} catch (LoginException | InterruptedException e) {
logger.catching(e);
return null;
}
}
}
return jda;
}
static void polish(JDA jda) {
static void polish(JDA jda, BotConfigLoader config) {
logger.info("Check database...");
checkDatabase();
CommandLoader.load();
ApiCommandLoader.load();
logger.info("Loading commands");
SlashCommandLoader.load(config);
SlashCommandLoader.registerSlashCommands(jda.updateCommands());
DayListener dayListener = DayListener.getInstance();
dayListener.addListener(new ResetSpam());
dayListener.addListener(new DailyMadame());
dayListener.start();
jda.addEventListener(new BotListener());
jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.playing(MainBot.url));
jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.playing(config.url()));
logger.info("-----------------------END INIT-----------------------");
}
@ -112,66 +83,47 @@ public class Init {
List<UserEntity> users = (List<UserEntity>) userRepository.findAll();
UserStatsUtils userStatsUtils = UserStatsUtils.getINSTANCE();
logger.debug("Stats...");
// for (UserEntity userEntity : users) {
// logger.debug("..." + userEntity.getName());
// userStatsUtils.getUserStats(userEntity);
//
// }
logger.debug("Guild Prefs...");
GuildPreferenceRepository guildPreference = context.getBean(GuildPreferenceRepository.class);
for(GuildPreferenceEntity pref :guildPreference.findAll()){
boolean save = false;
if(pref.getWelcomeMessage() != null && pref.getWelcomeMessage().equals(" ")){
pref.setWelcomeMessage(null);
save = true;
}
if(pref.getWelcomeChanelID() != null && pref.getWelcomeChanelID().equals(" ")){
pref.setWelcomeChanelID(null);
save = true;
}
if(pref.getWelcomeChanelID() != null && pref.getWelcomeChanelID().equals(" ")){
pref.setWelcomeChanelID(null);
save = true;
}
if(pref.getDefaultRoleId() != null && pref.getDefaultRoleId().equals(" ")){
pref.setDefaultRoleId(null);
save = true;
}
if(pref.getAutoVoiceChannelID() != null && pref.getAutoVoiceChannelID().equals(" ")){
pref.setAutoVoiceChannelID(null);
save = true;
}
if(pref.getAutoVoiceChannelTitle() != null && pref.getAutoVoiceChannelTitle().equals(" ")){
pref.setAutoVoiceChannelTitle(null);
save = true;
}
public static boolean checkEnv() {
boolean ok = true;
if (System.getenv("PORT") == null) {
logger.fatal("Missing PORT ENV variable.");
ok = false;
}
if (System.getenv("DB_URL") == null) {
logger.fatal("Missing DB_URL ENV variable.");
ok = false;
}
if (System.getenv("DB_USER") == null) {
logger.fatal("Missing DB_USER ENV variable.");
ok = false;
}
if (System.getenv("DB_PWD") == null) {
logger.fatal("Missing DB_PWD ENV variable.");
ok = false;
}
if (System.getenv("OAUTH_URL") == null) {
logger.fatal("Missing OAUTH_URL ENV variable.");
ok = false;
}
if (System.getenv("DISCORD_TOKEN") == null) {
logger.fatal("Missing DISCORD_TOKEN ENV variable.");
ok = false;
}
if (System.getenv("GOOGLE_API_KEY") == null) {
logger.fatal("Missing GOOGLE_API_KEY ENV variable.");
ok = false;
}
if (System.getenv("RANDOM_API_KEY") == null) {
logger.fatal("Missing GOOGLE_API_KEY ENV variable.");
ok = false;
}
if (System.getenv("LOG_LEVEL") == null) {
logger.fatal("Missing LOG_LEVEL ENV variable.");
ok = false;
}
return ok;
if(save){
guildPreference.save(pref);
}
}
}
}

View File

@ -1,148 +1,66 @@
package net.Broken;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.Tools.Command.CommandParser;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.PrivateMessage;
import net.Broken.Tools.UserSpamUtils;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.ChannelType;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Main Class
*/
@SpringBootApplication
@Controller
@ConfigurationPropertiesScan
public class MainBot {
public static HashMap<String, Commande> commandes = new HashMap<>();
public static HashMap<Member, ArrayList<Message>> historique =new HashMap<>();
public static HashMap<Member, Integer> message_compteur =new HashMap<>();
public static final HashMap<String, SlashCommand> slashCommands = new HashMap<>();
public static HashMap<String, Integer> mutualGuildCount = new HashMap<>();
public static boolean roleFlag = false;
public static HashMap<Member, UserSpamUtils> spamUtils = new HashMap<>();
public static JDA jda;
public static boolean ready = false;
public static boolean dev = false;
public static String url= "claptrapbot.com";
public static int messageTimeOut = 10;
public static int gifMessageTimeOut = 30;
private static Logger logger = LogManager.getLogger();
private static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
if(!Init.checkEnv())
System.exit(1);
ConfigurableApplicationContext ctx = SpringApplication.run(MainBot.class, args);
BotConfigLoader config = ctx.getBean(BotConfigLoader.class);
VersionLoader versionLoader = ctx.getBean(VersionLoader.class);
logger.info("=======================================");
logger.info("--------------Starting Bot-------------");
logger.info("=======================================");
if(System.getenv("DEV")!= null){
dev = Boolean.parseBoolean(System.getenv("DEV"));
}
logger.info("Version: " + versionLoader.getVersion());
String token = System.getenv("DISCORD_TOKEN");
jda = Init.initJda(token);
ConfigurableApplicationContext ctx = SpringApplication.run(MainBot.class, args);
jda = Init.initJda(config);
if (jda == null) {
System.exit(SpringApplication.exit(ctx, (ExitCodeGenerator) () -> {
System.exit(SpringApplication.exit(ctx, () -> {
logger.fatal("Init error! Close application!");
return 1;
}));
}
Init.polish(jda);
Init.polish(jda, config);
ready = true;
}
/**
* Perform test (admin, NSFW and private usable or not) and execute command or not
* @param cmd Container whit all command info
*/
public static void handleCommand(CommandParser.CommandContainer cmd, UserEntity user)
{
if(!ready)
{
return;
}
if (commandes.containsKey(cmd.commande))
{
Commande cmdObj = commandes.get(cmd.commande);
boolean isAdmin;
boolean isBotAdmin = user != null && user.isBotAdmin();
if(cmd.event.isFromType(ChannelType.PRIVATE)){
isAdmin = false;
}
else
isAdmin = cmd.event.getMember().hasPermission(Permission.ADMINISTRATOR);
if((!cmdObj.isAdminCmd() || isAdmin) && (!cmdObj.isBotAdminCmd() || isBotAdmin)){
if(cmd.event.isFromType(ChannelType.PRIVATE) && commandes.get(cmd.commande).isPrivateUsable())
{
commandes.get(cmd.commande).action(cmd.args, cmd.event);
}
else if (!cmd.event.isFromType(ChannelType.PRIVATE))
{
if(!cmdObj.isNSFW() || cmd.event.getTextChannel().isNSFW()){
commandes.get(cmd.commande).action(cmd.args, cmd.event);
}
else{
cmd.event.getMessage().delete().queue();
}
}
else
cmd.event.getPrivateChannel().sendMessage(EmbedMessageUtils.getNoPrivate()).queue();
}
else{
if(cmd.event.isFromType(ChannelType.PRIVATE)){
PrivateMessage.send(cmd.event.getAuthor(),EmbedMessageUtils.getUnautorized(), logger);
}
else{
cmd.event.getTextChannel().sendMessage(EmbedMessageUtils.getUnautorized()).complete();
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer propsConfig
= new PropertySourcesPlaceholderConfigurer();
propsConfig.setLocation(new ClassPathResource("git.properties"));
propsConfig.setIgnoreResourceNotFound(true);
propsConfig.setIgnoreUnresolvablePlaceholders(true);
return propsConfig;
}
}
}
else{
logger.debug("Unknown command : " + cmd.commande);
}
}
}

View File

@ -1,43 +0,0 @@
package net.Broken.RestApi;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.reflections.Reflections;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import java.util.HashMap;
import java.util.Set;
public class ApiCommandLoader {
public static HashMap<String, CommandInterface> apiCommands = new HashMap<>();
private static Logger logger = LogManager.getLogger();
public static void load(){
logger.info("Loading Api Command...");
// Reflections reflections = new Reflections("net.Broken.RestApi.Command");
Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(
"net.Broken.RestApi.Commands",
ClasspathHelper.contextClassLoader(),
ClasspathHelper.staticClassLoader()))
);
Set<Class<? extends CommandInterface>> modules =
reflections.getSubTypesOf(CommandInterface.class);
logger.info("Find " + modules.size() + " Command:");
for (Class<? extends CommandInterface> apiClass : modules) {
String reference = apiClass.getName();
String[] splited = reference.split("\\.");
String name = splited[splited.length-1].toUpperCase();
logger.info("..." + name);
try {
apiCommands.put(name, apiClass.newInstance());
} catch (InstantiationException | IllegalAccessException e) {
logger.error("Failed to load " + name + "!");
}
}
}
}

View File

@ -1,24 +0,0 @@
package net.Broken.RestApi;
import net.Broken.Commands.Music;
import net.Broken.RestApi.Data.CommandPostData;
import net.Broken.RestApi.Data.CommandResponseData;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.User;
import org.springframework.http.ResponseEntity;
/**
* Represent RestApi command
*/
public interface CommandInterface {
/**
* Main action
* @param musicCommande Current guild music command
* @param data Received data
* @param user User who submit RestApi command
* @param guild
* @return HTTP Response
*/
ResponseEntity<CommandResponseData> action(CommandPostData data, User user, Guild guild);
}

View File

@ -1,19 +0,0 @@
package net.Broken.RestApi.Commands;
import net.Broken.RestApi.CommandInterface;
import net.Broken.RestApi.Data.CommandPostData;
import net.Broken.RestApi.Data.CommandResponseData;
import net.Broken.audio.WebLoadUtils;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.User;
import org.springframework.http.ResponseEntity;
/**
* Add track RestApi
*/
public class Add implements CommandInterface {
@Override
public ResponseEntity<CommandResponseData> action(CommandPostData data, User user, Guild guild) {
return new WebLoadUtils(data, user, guild, true).getResponse();
}
}

Some files were not shown because too many files have changed in this diff Show More