diff --git a/.gitignore b/.gitignore index 19f55917..0c726ef1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ /target/ .idea .settings -*.xml !pom.xml src/main/java/org.jointheleague.Launcher.java .classpath @@ -10,3 +9,6 @@ src/main/java/org.jointheleague.Launcher.java .travis.yml run.sh appspec.yml +/.gradle/ +.gradle/ +build/ diff --git a/.gradle/7.3.3/checksums/checksums.lock b/.gradle/7.3.3/checksums/checksums.lock new file mode 100644 index 00000000..c73c23d9 Binary files /dev/null and b/.gradle/7.3.3/checksums/checksums.lock differ diff --git a/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock b/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 00000000..b76cddf9 Binary files /dev/null and b/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock differ diff --git a/.gradle/7.3.3/dependencies-accessors/gc.properties b/.gradle/7.3.3/dependencies-accessors/gc.properties new file mode 100644 index 00000000..e69de29b diff --git a/.gradle/7.3.3/executionHistory/executionHistory.bin b/.gradle/7.3.3/executionHistory/executionHistory.bin new file mode 100644 index 00000000..6332d1d7 Binary files /dev/null and b/.gradle/7.3.3/executionHistory/executionHistory.bin differ diff --git a/.gradle/7.3.3/executionHistory/executionHistory.lock b/.gradle/7.3.3/executionHistory/executionHistory.lock new file mode 100644 index 00000000..134fb8d2 Binary files /dev/null and b/.gradle/7.3.3/executionHistory/executionHistory.lock differ diff --git a/.gradle/7.3.3/fileChanges/last-build.bin b/.gradle/7.3.3/fileChanges/last-build.bin new file mode 100644 index 00000000..f76dd238 Binary files /dev/null and b/.gradle/7.3.3/fileChanges/last-build.bin differ diff --git a/.gradle/7.3.3/fileHashes/fileHashes.bin b/.gradle/7.3.3/fileHashes/fileHashes.bin new file mode 100644 index 00000000..11afbec0 Binary files /dev/null and b/.gradle/7.3.3/fileHashes/fileHashes.bin differ diff --git a/.gradle/7.3.3/fileHashes/fileHashes.lock b/.gradle/7.3.3/fileHashes/fileHashes.lock new file mode 100644 index 00000000..43ac14ab Binary files /dev/null and b/.gradle/7.3.3/fileHashes/fileHashes.lock differ diff --git a/.gradle/7.3.3/fileHashes/resourceHashesCache.bin b/.gradle/7.3.3/fileHashes/resourceHashesCache.bin new file mode 100644 index 00000000..bec851c3 Binary files /dev/null and b/.gradle/7.3.3/fileHashes/resourceHashesCache.bin differ diff --git a/.gradle/7.3.3/gc.properties b/.gradle/7.3.3/gc.properties new file mode 100644 index 00000000..e69de29b diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 00000000..f0287f99 Binary files /dev/null and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 00000000..630cd747 --- /dev/null +++ b/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Thu May 16 18:40:18 PDT 2024 +gradle.version=7.3.3 diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 00000000..87ca7f42 Binary files /dev/null and b/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe new file mode 100644 index 00000000..eb72c0c1 Binary files /dev/null and b/.gradle/file-system.probe differ diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties new file mode 100644 index 00000000..e69de29b diff --git a/bin/.gitignore b/bin/.gitignore new file mode 100644 index 00000000..7eed456b --- /dev/null +++ b/bin/.gitignore @@ -0,0 +1,2 @@ +/main/ +/test/ diff --git a/build.gradle b/build.gradle index bb3a859e..0e6ca45b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,11 @@ - plugins { id 'java' id 'application' + id 'com.github.johnrengelman.shadow' version '7.1.2' } repositories { - repositories { - mavenCentral() - } + mavenCentral() } dependencies { @@ -15,26 +13,44 @@ dependencies { implementation 'net.aksingh:owm-japis:2.5.3.0' implementation 'com.googlecode.json-simple:json-simple:1.1.1' implementation 'javax.json:javax.json-api:1.1' - implementation 'org.mockito:mockito-core:3.4.0' + testImplementation 'org.mockito:mockito-core:5.0.0' implementation 'org.springframework.boot:spring-boot-starter-webflux:2.4.1' implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.3' testImplementation 'org.junit.jupiter:junit-jupiter:5.7.0' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.4.2' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' + + implementation 'org.apache.logging.log4j:log4j-api:2.24.1' + implementation 'org.apache.logging.log4j:log4j-core:2.24.1' } group = 'org.jointheleague' version = '2.0' description = 'discordbot' -sourceCompatibility = '1.8' - +sourceCompatibility = '11' test { useJUnitPlatform() } +run { + //environment 'CHANNEL_NAME', 'general' +} + tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } mainClassName = 'org.jointheleague.Launcher' + +shadowJar { + archiveBaseName.set("discordbot") + archiveVersion.set(version) + archiveClassifier.set("") // No classifier + mergeServiceFiles() // Merges service files, if necessary + manifest { + attributes( + 'Main-Class': mainClassName // Ensures the manifest has the right entry + ) + } +} diff --git a/build/distributions/discordbot-2.0.tar b/build/distributions/discordbot-2.0.tar new file mode 100644 index 00000000..8b96c65b Binary files /dev/null and b/build/distributions/discordbot-2.0.tar differ diff --git a/build/distributions/discordbot-2.0.zip b/build/distributions/discordbot-2.0.zip new file mode 100644 index 00000000..a4e80169 Binary files /dev/null and b/build/distributions/discordbot-2.0.zip differ diff --git a/build/libs/discordbot-2.0.jar b/build/libs/discordbot-2.0.jar new file mode 100644 index 00000000..f00a8839 Binary files /dev/null and b/build/libs/discordbot-2.0.jar differ diff --git a/build/reports/tests/test/classes/org.jointheleague.features.examples.first_features.CurrentTimeTest.html b/build/reports/tests/test/classes/org.jointheleague.features.examples.first_features.CurrentTimeTest.html new file mode 100644 index 00000000..322d2304 --- /dev/null +++ b/build/reports/tests/test/classes/org.jointheleague.features.examples.first_features.CurrentTimeTest.html @@ -0,0 +1,116 @@ + + + + + +Test results - CurrentTimeTest + + + + + +
+

CurrentTimeTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
5
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
1.710s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
itShouldHandleMessagesWithCommand()0.012spassed
itShouldHaveACommand()1.664spassed
itShouldHaveAHelpEmbed()0.002spassed
itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed()0.002spassed
itShouldNotHandleMessagesWithoutCommand()0.030spassed
+
+
+ +
+ + diff --git a/build/reports/tests/test/classes/org.jointheleague.features.examples.first_features.RandomNumberTest.html b/build/reports/tests/test/classes/org.jointheleague.features.examples.first_features.RandomNumberTest.html new file mode 100644 index 00000000..f7ef6b05 --- /dev/null +++ b/build/reports/tests/test/classes/org.jointheleague.features.examples.first_features.RandomNumberTest.html @@ -0,0 +1,116 @@ + + + + + +Test results - RandomNumberTest + + + + + +
+

RandomNumberTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
5
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.044s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
itShouldHandleMessagesWithCommand()0.027spassed
itShouldHaveACommand()0.003spassed
itShouldHaveAHelpEmbed()0.002spassed
itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed()0.002spassed
itShouldNotHandleMessagesWithoutCommand()0.010spassed
+
+
+ +
+ + diff --git a/build/reports/tests/test/classes/org.jointheleague.features.examples.second_features.HighLowGameTest.html b/build/reports/tests/test/classes/org.jointheleague.features.examples.second_features.HighLowGameTest.html new file mode 100644 index 00000000..325e1eda --- /dev/null +++ b/build/reports/tests/test/classes/org.jointheleague.features.examples.second_features.HighLowGameTest.html @@ -0,0 +1,141 @@ + + + + + +Test results - HighLowGameTest + + + + + +
+

HighLowGameTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
10
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.050s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
itShouldHandleMessagesWithCommand()0.007spassed
itShouldHaveACommand()0.003spassed
itShouldHaveAHelpEmbed()0.002spassed
itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed()0.003spassed
itShouldNotAcceptGuessIfGameIsNotStarted()0.008spassed
itShouldNotHandleMessagesWithoutCommand()0.004spassed
itShouldSendErrorMessageIfGuessIsNotANumber()0.005spassed
itShouldTellTheUserIfTheirGuessIsCorrect()0.003spassed
itShouldTellTheUserIfTheirGuessIsTooHigh()0.011spassed
itShouldTellTheUserIfTheirGuessIsTooLow()0.004spassed
+
+
+ +
+ + diff --git a/build/reports/tests/test/classes/org.jointheleague.features.examples.third_features.CatFactsApiTest.html b/build/reports/tests/test/classes/org.jointheleague.features.examples.third_features.CatFactsApiTest.html new file mode 100644 index 00000000..821229d8 --- /dev/null +++ b/build/reports/tests/test/classes/org.jointheleague.features.examples.third_features.CatFactsApiTest.html @@ -0,0 +1,116 @@ + + + + + +Test results - CatFactsApiTest + + + + + +
+

CatFactsApiTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
5
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
1.783s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
givenMessageWithCommand_whenHandle_thenSendCatFact()1.771spassed
givenMessageWithoutCommand_whenHandle_thenDoNothing()0.004spassed
itShouldHaveACommand()0.003spassed
itShouldHaveAHelpEmbed()0.002spassed
itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed()0.003spassed
+
+
+ +
+ + diff --git a/build/reports/tests/test/classes/org.jointheleague.features.examples.third_features.NewsApiTest.html b/build/reports/tests/test/classes/org.jointheleague.features.examples.third_features.NewsApiTest.html new file mode 100644 index 00000000..2d5bf0a6 --- /dev/null +++ b/build/reports/tests/test/classes/org.jointheleague.features.examples.third_features.NewsApiTest.html @@ -0,0 +1,121 @@ + + + + + +Test results - NewsApiTest + + + + + +
+

NewsApiTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
6
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.034s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
givenMessageWithCommandAndNoTopic_whenHandle_thenSendErrorMessage()0.005spassed
givenMessageWithCommandAndTopic_whenHandle_thenSendStoryMessage()0.010spassed
givenMessageWithoutCommand_whenHandle_thenDoNothing()0.009spassed
itShouldHaveACommand()0.004spassed
itShouldHaveAHelpEmbed()0.003spassed
itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed()0.003spassed
+
+
+ +
+ + diff --git a/build/reports/tests/test/classes/org.jointheleague.features.student.first_feature.FeatureOneTest.html b/build/reports/tests/test/classes/org.jointheleague.features.student.first_feature.FeatureOneTest.html new file mode 100644 index 00000000..c8910d92 --- /dev/null +++ b/build/reports/tests/test/classes/org.jointheleague.features.student.first_feature.FeatureOneTest.html @@ -0,0 +1,116 @@ + + + + + +Test results - FeatureOneTest + + + + + +
+

FeatureOneTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
5
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.014s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
itShouldHandleMessagesWithCommand()0.006spassed
itShouldHaveACommand()0.003spassed
itShouldHaveAHelpEmbed()0.002spassed
itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed()0.001spassed
itShouldNotHandleMessagesWithoutCommand()0.002spassed
+
+
+ +
+ + diff --git a/build/reports/tests/test/classes/org.jointheleague.features.templates.FeatureTemplateTest.html b/build/reports/tests/test/classes/org.jointheleague.features.templates.FeatureTemplateTest.html new file mode 100644 index 00000000..8bfad20b --- /dev/null +++ b/build/reports/tests/test/classes/org.jointheleague.features.templates.FeatureTemplateTest.html @@ -0,0 +1,116 @@ + + + + + +Test results - FeatureTemplateTest + + + + + +
+

FeatureTemplateTest

+ +
+ + + + + +
+
+ + + + + + + +
+
+
5
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.015s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Tests

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestDurationResult
itShouldHandleMessagesWithCommand()0.006spassed
itShouldHaveACommand()0.001spassed
itShouldHaveAHelpEmbed()0.004spassed
itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed()0.001spassed
itShouldNotHandleMessagesWithoutCommand()0.003spassed
+
+
+ +
+ + diff --git a/build/reports/tests/test/css/base-style.css b/build/reports/tests/test/css/base-style.css new file mode 100644 index 00000000..4afa73e3 --- /dev/null +++ b/build/reports/tests/test/css/base-style.css @@ -0,0 +1,179 @@ + +body { + margin: 0; + padding: 0; + font-family: sans-serif; + font-size: 12pt; +} + +body, a, a:visited { + color: #303030; +} + +#content { + padding-left: 50px; + padding-right: 50px; + padding-top: 30px; + padding-bottom: 30px; +} + +#content h1 { + font-size: 160%; + margin-bottom: 10px; +} + +#footer { + margin-top: 100px; + font-size: 80%; + white-space: nowrap; +} + +#footer, #footer a { + color: #a0a0a0; +} + +#line-wrapping-toggle { + vertical-align: middle; +} + +#label-for-line-wrapping-toggle { + vertical-align: middle; +} + +ul { + margin-left: 0; +} + +h1, h2, h3 { + white-space: nowrap; +} + +h2 { + font-size: 120%; +} + +ul.tabLinks { + padding-left: 0; + padding-top: 10px; + padding-bottom: 10px; + overflow: auto; + min-width: 800px; + width: auto !important; + width: 800px; +} + +ul.tabLinks li { + float: left; + height: 100%; + list-style: none; + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; + padding-bottom: 5px; + margin-bottom: 0; + -moz-border-radius: 7px; + border-radius: 7px; + margin-right: 25px; + border: solid 1px #d4d4d4; + background-color: #f0f0f0; +} + +ul.tabLinks li:hover { + background-color: #fafafa; +} + +ul.tabLinks li.selected { + background-color: #c5f0f5; + border-color: #c5f0f5; +} + +ul.tabLinks a { + font-size: 120%; + display: block; + outline: none; + text-decoration: none; + margin: 0; + padding: 0; +} + +ul.tabLinks li h2 { + margin: 0; + padding: 0; +} + +div.tab { +} + +div.selected { + display: block; +} + +div.deselected { + display: none; +} + +div.tab table { + min-width: 350px; + width: auto !important; + width: 350px; + border-collapse: collapse; +} + +div.tab th, div.tab table { + border-bottom: solid #d0d0d0 1px; +} + +div.tab th { + text-align: left; + white-space: nowrap; + padding-left: 6em; +} + +div.tab th:first-child { + padding-left: 0; +} + +div.tab td { + white-space: nowrap; + padding-left: 6em; + padding-top: 5px; + padding-bottom: 5px; +} + +div.tab td:first-child { + padding-left: 0; +} + +div.tab td.numeric, div.tab th.numeric { + text-align: right; +} + +span.code { + display: inline-block; + margin-top: 0em; + margin-bottom: 1em; +} + +span.code pre { + font-size: 11pt; + padding-top: 10px; + padding-bottom: 10px; + padding-left: 10px; + padding-right: 10px; + margin: 0; + background-color: #f7f7f7; + border: solid 1px #d0d0d0; + min-width: 700px; + width: auto !important; + width: 700px; +} + +span.wrapped pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: break-all; +} + +label.hidden { + display: none; +} \ No newline at end of file diff --git a/build/reports/tests/test/css/style.css b/build/reports/tests/test/css/style.css new file mode 100644 index 00000000..3dc4913e --- /dev/null +++ b/build/reports/tests/test/css/style.css @@ -0,0 +1,84 @@ + +#summary { + margin-top: 30px; + margin-bottom: 40px; +} + +#summary table { + border-collapse: collapse; +} + +#summary td { + vertical-align: top; +} + +.breadcrumbs, .breadcrumbs a { + color: #606060; +} + +.infoBox { + width: 110px; + padding-top: 15px; + padding-bottom: 15px; + text-align: center; +} + +.infoBox p { + margin: 0; +} + +.counter, .percent { + font-size: 120%; + font-weight: bold; + margin-bottom: 8px; +} + +#duration { + width: 125px; +} + +#successRate, .summaryGroup { + border: solid 2px #d0d0d0; + -moz-border-radius: 10px; + border-radius: 10px; +} + +#successRate { + width: 140px; + margin-left: 35px; +} + +#successRate .percent { + font-size: 180%; +} + +.success, .success a { + color: #008000; +} + +div.success, #successRate.success { + background-color: #bbd9bb; + border-color: #008000; +} + +.failures, .failures a { + color: #b60808; +} + +.skipped, .skipped a { + color: #c09853; +} + +div.failures, #successRate.failures { + background-color: #ecdada; + border-color: #b60808; +} + +ul.linkList { + padding-left: 0; +} + +ul.linkList li { + list-style: none; + margin-bottom: 5px; +} diff --git a/build/reports/tests/test/index.html b/build/reports/tests/test/index.html new file mode 100644 index 00000000..2981cd22 --- /dev/null +++ b/build/reports/tests/test/index.html @@ -0,0 +1,233 @@ + + + + + +Test results - Test Summary + + + + + +
+

Test Summary

+
+ + + + + +
+
+ + + + + + + +
+
+
41
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
3.650s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Packages

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PackageTestsFailuresIgnoredDurationSuccess rate
+org.jointheleague.features.examples.first_features +10001.754s100%
+org.jointheleague.features.examples.second_features +10000.050s100%
+org.jointheleague.features.examples.third_features +11001.817s100%
+org.jointheleague.features.student.first_feature +5000.014s100%
+org.jointheleague.features.templates +5000.015s100%
+
+
+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+org.jointheleague.features.examples.first_features.CurrentTimeTest +5001.710s100%
+org.jointheleague.features.examples.first_features.RandomNumberTest +5000.044s100%
+org.jointheleague.features.examples.second_features.HighLowGameTest +10000.050s100%
+org.jointheleague.features.examples.third_features.CatFactsApiTest +5001.783s100%
+org.jointheleague.features.examples.third_features.NewsApiTest +6000.034s100%
+org.jointheleague.features.student.first_feature.FeatureOneTest +5000.014s100%
+org.jointheleague.features.templates.FeatureTemplateTest +5000.015s100%
+
+
+ +
+ + diff --git a/build/reports/tests/test/js/report.js b/build/reports/tests/test/js/report.js new file mode 100644 index 00000000..83bab4a1 --- /dev/null +++ b/build/reports/tests/test/js/report.js @@ -0,0 +1,194 @@ +(function (window, document) { + "use strict"; + + var tabs = {}; + + function changeElementClass(element, classValue) { + if (element.getAttribute("className")) { + element.setAttribute("className", classValue); + } else { + element.setAttribute("class", classValue); + } + } + + function getClassAttribute(element) { + if (element.getAttribute("className")) { + return element.getAttribute("className"); + } else { + return element.getAttribute("class"); + } + } + + function addClass(element, classValue) { + changeElementClass(element, getClassAttribute(element) + " " + classValue); + } + + function removeClass(element, classValue) { + changeElementClass(element, getClassAttribute(element).replace(classValue, "")); + } + + function initTabs() { + var container = document.getElementById("tabs"); + + tabs.tabs = findTabs(container); + tabs.titles = findTitles(tabs.tabs); + tabs.headers = findHeaders(container); + tabs.select = select; + tabs.deselectAll = deselectAll; + tabs.select(0); + + return true; + } + + function getCheckBox() { + return document.getElementById("line-wrapping-toggle"); + } + + function getLabelForCheckBox() { + return document.getElementById("label-for-line-wrapping-toggle"); + } + + function findCodeBlocks() { + var spans = document.getElementById("tabs").getElementsByTagName("span"); + var codeBlocks = []; + for (var i = 0; i < spans.length; ++i) { + if (spans[i].className.indexOf("code") >= 0) { + codeBlocks.push(spans[i]); + } + } + return codeBlocks; + } + + function forAllCodeBlocks(operation) { + var codeBlocks = findCodeBlocks(); + + for (var i = 0; i < codeBlocks.length; ++i) { + operation(codeBlocks[i], "wrapped"); + } + } + + function toggleLineWrapping() { + var checkBox = getCheckBox(); + + if (checkBox.checked) { + forAllCodeBlocks(addClass); + } else { + forAllCodeBlocks(removeClass); + } + } + + function initControls() { + if (findCodeBlocks().length > 0) { + var checkBox = getCheckBox(); + var label = getLabelForCheckBox(); + + checkBox.onclick = toggleLineWrapping; + checkBox.checked = false; + + removeClass(label, "hidden"); + } + } + + function switchTab() { + var id = this.id.substr(1); + + for (var i = 0; i < tabs.tabs.length; i++) { + if (tabs.tabs[i].id === id) { + tabs.select(i); + break; + } + } + + return false; + } + + function select(i) { + this.deselectAll(); + + changeElementClass(this.tabs[i], "tab selected"); + changeElementClass(this.headers[i], "selected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var h2 = document.createElement("H2"); + + h2.appendChild(document.createTextNode(this.titles[i])); + this.headers[i].appendChild(h2); + } + + function deselectAll() { + for (var i = 0; i < this.tabs.length; i++) { + changeElementClass(this.tabs[i], "tab deselected"); + changeElementClass(this.headers[i], "deselected"); + + while (this.headers[i].firstChild) { + this.headers[i].removeChild(this.headers[i].firstChild); + } + + var a = document.createElement("A"); + + a.setAttribute("id", "ltab" + i); + a.setAttribute("href", "#tab" + i); + a.onclick = switchTab; + a.appendChild(document.createTextNode(this.titles[i])); + + this.headers[i].appendChild(a); + } + } + + function findTabs(container) { + return findChildElements(container, "DIV", "tab"); + } + + function findHeaders(container) { + var owner = findChildElements(container, "UL", "tabLinks"); + return findChildElements(owner[0], "LI", null); + } + + function findTitles(tabs) { + var titles = []; + + for (var i = 0; i < tabs.length; i++) { + var tab = tabs[i]; + var header = findChildElements(tab, "H2", null)[0]; + + header.parentNode.removeChild(header); + + if (header.innerText) { + titles.push(header.innerText); + } else { + titles.push(header.textContent); + } + } + + return titles; + } + + function findChildElements(container, name, targetClass) { + var elements = []; + var children = container.childNodes; + + for (var i = 0; i < children.length; i++) { + var child = children.item(i); + + if (child.nodeType === 1 && child.nodeName === name) { + if (targetClass && child.className.indexOf(targetClass) < 0) { + continue; + } + + elements.push(child); + } + } + + return elements; + } + + // Entry point. + + window.onload = function() { + initTabs(); + initControls(); + }; +} (window, window.document)); \ No newline at end of file diff --git a/build/reports/tests/test/packages/org.jointheleague.features.examples.first_features.html b/build/reports/tests/test/packages/org.jointheleague.features.examples.first_features.html new file mode 100644 index 00000000..041b7444 --- /dev/null +++ b/build/reports/tests/test/packages/org.jointheleague.features.examples.first_features.html @@ -0,0 +1,113 @@ + + + + + +Test results - Package org.jointheleague.features.examples.first_features + + + + + +
+

Package org.jointheleague.features.examples.first_features

+ +
+ + + + + +
+
+ + + + + + + +
+
+
10
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
1.754s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+CurrentTimeTest +5001.710s100%
+RandomNumberTest +5000.044s100%
+
+
+ +
+ + diff --git a/build/reports/tests/test/packages/org.jointheleague.features.examples.second_features.html b/build/reports/tests/test/packages/org.jointheleague.features.examples.second_features.html new file mode 100644 index 00000000..36255c37 --- /dev/null +++ b/build/reports/tests/test/packages/org.jointheleague.features.examples.second_features.html @@ -0,0 +1,103 @@ + + + + + +Test results - Package org.jointheleague.features.examples.second_features + + + + + +
+

Package org.jointheleague.features.examples.second_features

+ +
+ + + + + +
+
+ + + + + + + +
+
+
10
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.050s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+HighLowGameTest +10000.050s100%
+
+
+ +
+ + diff --git a/build/reports/tests/test/packages/org.jointheleague.features.examples.third_features.html b/build/reports/tests/test/packages/org.jointheleague.features.examples.third_features.html new file mode 100644 index 00000000..204de23a --- /dev/null +++ b/build/reports/tests/test/packages/org.jointheleague.features.examples.third_features.html @@ -0,0 +1,113 @@ + + + + + +Test results - Package org.jointheleague.features.examples.third_features + + + + + +
+

Package org.jointheleague.features.examples.third_features

+ +
+ + + + + +
+
+ + + + + + + +
+
+
11
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
1.817s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+CatFactsApiTest +5001.783s100%
+NewsApiTest +6000.034s100%
+
+
+ +
+ + diff --git a/build/reports/tests/test/packages/org.jointheleague.features.student.first_feature.html b/build/reports/tests/test/packages/org.jointheleague.features.student.first_feature.html new file mode 100644 index 00000000..d8e57085 --- /dev/null +++ b/build/reports/tests/test/packages/org.jointheleague.features.student.first_feature.html @@ -0,0 +1,103 @@ + + + + + +Test results - Package org.jointheleague.features.student.first_feature + + + + + +
+

Package org.jointheleague.features.student.first_feature

+ +
+ + + + + +
+
+ + + + + + + +
+
+
5
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.014s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+FeatureOneTest +5000.014s100%
+
+
+ +
+ + diff --git a/build/reports/tests/test/packages/org.jointheleague.features.templates.html b/build/reports/tests/test/packages/org.jointheleague.features.templates.html new file mode 100644 index 00000000..59e2e3ab --- /dev/null +++ b/build/reports/tests/test/packages/org.jointheleague.features.templates.html @@ -0,0 +1,103 @@ + + + + + +Test results - Package org.jointheleague.features.templates + + + + + +
+

Package org.jointheleague.features.templates

+ +
+ + + + + +
+
+ + + + + + + +
+
+
5
+

tests

+
+
+
+
0
+

failures

+
+
+
+
0
+

ignored

+
+
+
+
0.015s
+

duration

+
+
+
+
+
+
100%
+

successful

+
+
+
+
+ +
+

Classes

+ + + + + + + + + + + + + + + + + + + +
ClassTestsFailuresIgnoredDurationSuccess rate
+FeatureTemplateTest +5000.015s100%
+
+
+ +
+ + diff --git a/build/scripts/discordbot b/build/scripts/discordbot new file mode 100755 index 00000000..040ea605 --- /dev/null +++ b/build/scripts/discordbot @@ -0,0 +1,233 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# discordbot start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh discordbot +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and DISCORDBOT_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}.." && pwd -P ) || exit + +APP_NAME="discordbot" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and DISCORDBOT_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/lib/discordbot-2.0.jar:$APP_HOME/lib/owm-japis-2.5.3.0.jar:$APP_HOME/lib/json-simple-1.1.1.jar:$APP_HOME/lib/javax.json-api-1.1.jar:$APP_HOME/lib/mockito-core-3.4.0.jar:$APP_HOME/lib/spring-boot-starter-webflux-2.4.1.jar:$APP_HOME/lib/javacord-core-3.8.0.jar:$APP_HOME/lib/spring-boot-starter-json-2.4.1.jar:$APP_HOME/lib/jackson-datatype-jsr310-2.12.7.jar:$APP_HOME/lib/jackson-annotations-2.12.7.jar:$APP_HOME/lib/jackson-datatype-jdk8-2.12.7.jar:$APP_HOME/lib/jackson-module-parameter-names-2.12.7.jar:$APP_HOME/lib/jackson-core-2.12.7.jar:$APP_HOME/lib/jackson-databind-2.12.7.1.jar:$APP_HOME/lib/javacord-api-3.8.0.jar:$APP_HOME/lib/converter-gson-2.5.0.jar:$APP_HOME/lib/gson-2.8.5.jar:$APP_HOME/lib/retrofit-2.5.0.jar:$APP_HOME/lib/logging-interceptor-4.9.3.jar:$APP_HOME/lib/okhttp-4.9.3.jar:$APP_HOME/lib/okio-jvm-2.8.0.jar:$APP_HOME/lib/kotlin-stdlib-jdk8-1.4.10.jar:$APP_HOME/lib/kotlin-stdlib-jdk7-1.4.10.jar:$APP_HOME/lib/kotlin-stdlib-1.4.10.jar:$APP_HOME/lib/junit-4.13.1.jar:$APP_HOME/lib/byte-buddy-1.10.10.jar:$APP_HOME/lib/byte-buddy-agent-1.10.10.jar:$APP_HOME/lib/objenesis-2.6.jar:$APP_HOME/lib/spring-boot-starter-2.4.1.jar:$APP_HOME/lib/spring-boot-starter-reactor-netty-2.4.1.jar:$APP_HOME/lib/spring-webflux-5.3.2.jar:$APP_HOME/lib/spring-web-5.3.2.jar:$APP_HOME/lib/nv-websocket-client-2.14.jar:$APP_HOME/lib/xsalsa20poly1305-0.11.0.jar:$APP_HOME/lib/spring-boot-starter-logging-2.4.1.jar:$APP_HOME/lib/log4j-to-slf4j-2.13.3.jar:$APP_HOME/lib/log4j-api-2.17.2.jar:$APP_HOME/lib/vavr-0.10.4.jar:$APP_HOME/lib/kotlin-stdlib-common-1.4.10.jar:$APP_HOME/lib/annotations-13.0.jar:$APP_HOME/lib/hamcrest-core-1.3.jar:$APP_HOME/lib/spring-boot-autoconfigure-2.4.1.jar:$APP_HOME/lib/spring-boot-2.4.1.jar:$APP_HOME/lib/jakarta.annotation-api-1.3.5.jar:$APP_HOME/lib/spring-context-5.3.2.jar:$APP_HOME/lib/spring-aop-5.3.2.jar:$APP_HOME/lib/spring-beans-5.3.2.jar:$APP_HOME/lib/spring-expression-5.3.2.jar:$APP_HOME/lib/spring-core-5.3.2.jar:$APP_HOME/lib/snakeyaml-1.27.jar:$APP_HOME/lib/reactor-netty-http-1.0.2.jar:$APP_HOME/lib/reactor-netty-core-1.0.2.jar:$APP_HOME/lib/reactor-core-3.4.1.jar:$APP_HOME/lib/bcprov-jdk15on-1.60.jar:$APP_HOME/lib/vavr-match-0.10.4.jar:$APP_HOME/lib/logback-classic-1.2.3.jar:$APP_HOME/lib/jul-to-slf4j-1.7.30.jar:$APP_HOME/lib/spring-jcl-5.3.2.jar:$APP_HOME/lib/netty-codec-http2-4.1.54.Final.jar:$APP_HOME/lib/netty-handler-proxy-4.1.54.Final.jar:$APP_HOME/lib/netty-codec-http-4.1.54.Final.jar:$APP_HOME/lib/netty-resolver-dns-4.1.54.Final.jar:$APP_HOME/lib/netty-transport-native-epoll-4.1.54.Final-linux-x86_64.jar:$APP_HOME/lib/reactive-streams-1.0.3.jar:$APP_HOME/lib/logback-core-1.2.3.jar:$APP_HOME/lib/slf4j-api-1.7.30.jar:$APP_HOME/lib/netty-handler-4.1.54.Final.jar:$APP_HOME/lib/netty-codec-dns-4.1.54.Final.jar:$APP_HOME/lib/netty-codec-socks-4.1.54.Final.jar:$APP_HOME/lib/netty-codec-4.1.54.Final.jar:$APP_HOME/lib/netty-transport-native-unix-common-4.1.54.Final.jar:$APP_HOME/lib/netty-transport-4.1.54.Final.jar:$APP_HOME/lib/netty-buffer-4.1.54.Final.jar:$APP_HOME/lib/netty-resolver-4.1.54.Final.jar:$APP_HOME/lib/netty-common-4.1.54.Final.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and DISCORDBOT_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $DISCORDBOT_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + -classpath "$CLASSPATH" \ + org.jointheleague.Launcher \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $DISCORDBOT_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/build/scripts/discordbot.bat b/build/scripts/discordbot.bat new file mode 100644 index 00000000..4544c9cf --- /dev/null +++ b/build/scripts/discordbot.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem discordbot startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME%.. + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and DISCORDBOT_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\lib\discordbot-2.0.jar;%APP_HOME%\lib\owm-japis-2.5.3.0.jar;%APP_HOME%\lib\json-simple-1.1.1.jar;%APP_HOME%\lib\javax.json-api-1.1.jar;%APP_HOME%\lib\mockito-core-3.4.0.jar;%APP_HOME%\lib\spring-boot-starter-webflux-2.4.1.jar;%APP_HOME%\lib\javacord-core-3.8.0.jar;%APP_HOME%\lib\spring-boot-starter-json-2.4.1.jar;%APP_HOME%\lib\jackson-datatype-jsr310-2.12.7.jar;%APP_HOME%\lib\jackson-annotations-2.12.7.jar;%APP_HOME%\lib\jackson-datatype-jdk8-2.12.7.jar;%APP_HOME%\lib\jackson-module-parameter-names-2.12.7.jar;%APP_HOME%\lib\jackson-core-2.12.7.jar;%APP_HOME%\lib\jackson-databind-2.12.7.1.jar;%APP_HOME%\lib\javacord-api-3.8.0.jar;%APP_HOME%\lib\converter-gson-2.5.0.jar;%APP_HOME%\lib\gson-2.8.5.jar;%APP_HOME%\lib\retrofit-2.5.0.jar;%APP_HOME%\lib\logging-interceptor-4.9.3.jar;%APP_HOME%\lib\okhttp-4.9.3.jar;%APP_HOME%\lib\okio-jvm-2.8.0.jar;%APP_HOME%\lib\kotlin-stdlib-jdk8-1.4.10.jar;%APP_HOME%\lib\kotlin-stdlib-jdk7-1.4.10.jar;%APP_HOME%\lib\kotlin-stdlib-1.4.10.jar;%APP_HOME%\lib\junit-4.13.1.jar;%APP_HOME%\lib\byte-buddy-1.10.10.jar;%APP_HOME%\lib\byte-buddy-agent-1.10.10.jar;%APP_HOME%\lib\objenesis-2.6.jar;%APP_HOME%\lib\spring-boot-starter-2.4.1.jar;%APP_HOME%\lib\spring-boot-starter-reactor-netty-2.4.1.jar;%APP_HOME%\lib\spring-webflux-5.3.2.jar;%APP_HOME%\lib\spring-web-5.3.2.jar;%APP_HOME%\lib\nv-websocket-client-2.14.jar;%APP_HOME%\lib\xsalsa20poly1305-0.11.0.jar;%APP_HOME%\lib\spring-boot-starter-logging-2.4.1.jar;%APP_HOME%\lib\log4j-to-slf4j-2.13.3.jar;%APP_HOME%\lib\log4j-api-2.17.2.jar;%APP_HOME%\lib\vavr-0.10.4.jar;%APP_HOME%\lib\kotlin-stdlib-common-1.4.10.jar;%APP_HOME%\lib\annotations-13.0.jar;%APP_HOME%\lib\hamcrest-core-1.3.jar;%APP_HOME%\lib\spring-boot-autoconfigure-2.4.1.jar;%APP_HOME%\lib\spring-boot-2.4.1.jar;%APP_HOME%\lib\jakarta.annotation-api-1.3.5.jar;%APP_HOME%\lib\spring-context-5.3.2.jar;%APP_HOME%\lib\spring-aop-5.3.2.jar;%APP_HOME%\lib\spring-beans-5.3.2.jar;%APP_HOME%\lib\spring-expression-5.3.2.jar;%APP_HOME%\lib\spring-core-5.3.2.jar;%APP_HOME%\lib\snakeyaml-1.27.jar;%APP_HOME%\lib\reactor-netty-http-1.0.2.jar;%APP_HOME%\lib\reactor-netty-core-1.0.2.jar;%APP_HOME%\lib\reactor-core-3.4.1.jar;%APP_HOME%\lib\bcprov-jdk15on-1.60.jar;%APP_HOME%\lib\vavr-match-0.10.4.jar;%APP_HOME%\lib\logback-classic-1.2.3.jar;%APP_HOME%\lib\jul-to-slf4j-1.7.30.jar;%APP_HOME%\lib\spring-jcl-5.3.2.jar;%APP_HOME%\lib\netty-codec-http2-4.1.54.Final.jar;%APP_HOME%\lib\netty-handler-proxy-4.1.54.Final.jar;%APP_HOME%\lib\netty-codec-http-4.1.54.Final.jar;%APP_HOME%\lib\netty-resolver-dns-4.1.54.Final.jar;%APP_HOME%\lib\netty-transport-native-epoll-4.1.54.Final-linux-x86_64.jar;%APP_HOME%\lib\reactive-streams-1.0.3.jar;%APP_HOME%\lib\logback-core-1.2.3.jar;%APP_HOME%\lib\slf4j-api-1.7.30.jar;%APP_HOME%\lib\netty-handler-4.1.54.Final.jar;%APP_HOME%\lib\netty-codec-dns-4.1.54.Final.jar;%APP_HOME%\lib\netty-codec-socks-4.1.54.Final.jar;%APP_HOME%\lib\netty-codec-4.1.54.Final.jar;%APP_HOME%\lib\netty-transport-native-unix-common-4.1.54.Final.jar;%APP_HOME%\lib\netty-transport-4.1.54.Final.jar;%APP_HOME%\lib\netty-buffer-4.1.54.Final.jar;%APP_HOME%\lib\netty-resolver-4.1.54.Final.jar;%APP_HOME%\lib\netty-common-4.1.54.Final.jar + + +@rem Execute discordbot +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %DISCORDBOT_OPTS% -classpath "%CLASSPATH%" org.jointheleague.Launcher %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable DISCORDBOT_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%DISCORDBOT_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/build/test-results/test/binary/output.bin b/build/test-results/test/binary/output.bin new file mode 100644 index 00000000..e69de29b diff --git a/build/test-results/test/binary/output.bin.idx b/build/test-results/test/binary/output.bin.idx new file mode 100644 index 00000000..f76dd238 Binary files /dev/null and b/build/test-results/test/binary/output.bin.idx differ diff --git a/build/test-results/test/binary/results.bin b/build/test-results/test/binary/results.bin new file mode 100644 index 00000000..7aae94f7 Binary files /dev/null and b/build/test-results/test/binary/results.bin differ diff --git a/build/tmp/compileJava/previous-compilation-data.bin b/build/tmp/compileJava/previous-compilation-data.bin new file mode 100644 index 00000000..ed714d82 Binary files /dev/null and b/build/tmp/compileJava/previous-compilation-data.bin differ diff --git a/build/tmp/compileTestJava/previous-compilation-data.bin b/build/tmp/compileTestJava/previous-compilation-data.bin new file mode 100644 index 00000000..5066b99f Binary files /dev/null and b/build/tmp/compileTestJava/previous-compilation-data.bin differ diff --git a/build/tmp/jar/MANIFEST.MF b/build/tmp/jar/MANIFEST.MF new file mode 100644 index 00000000..58630c02 --- /dev/null +++ b/build/tmp/jar/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/src/main/java/org/jointheleague/Launcher.java b/src/main/java/org/jointheleague/Launcher.java index 629e352c..c0788e57 100644 --- a/src/main/java/org/jointheleague/Launcher.java +++ b/src/main/java/org/jointheleague/Launcher.java @@ -6,8 +6,10 @@ public class Launcher { public static void main(String[] args) { //Initialize variables - String channelName = System.getenv("CHANNEL_NAME"); - String discordToken = System.getenv("DISCORD_TOKEN"); + //String channelName = System.getenv("CHANNEL_NAME"); + String channelName = "general"; + // String discordToken = System.getenv("DISCORD_TOKEN"); + String discordToken = "not sigma"; boolean printDiscordInvite = true; //Instantiate DiscordBot and connect diff --git a/src/main/java/org/jointheleague/discord_bot/DiscordBot.java b/src/main/java/org/jointheleague/discord_bot/DiscordBot.java index ae863505..de059ea6 100644 --- a/src/main/java/org/jointheleague/discord_bot/DiscordBot.java +++ b/src/main/java/org/jointheleague/discord_bot/DiscordBot.java @@ -11,6 +11,8 @@ import org.jointheleague.features.examples.first_features.RandomNumber; import org.jointheleague.features.help_embed.HelpListener; import org.jointheleague.features.student.first_feature.FeatureOne; +import org.jointheleague.features.whale.ApiGetter; +import org.jointheleague.features.whale.Schedule; public class DiscordBot { @@ -30,7 +32,9 @@ public DiscordBot(String token, String channelName) { public void connect(boolean printInvite) { - api = new DiscordApiBuilder().setToken(token).addIntents(Intent.MESSAGE_CONTENT).login().join(); + api = new DiscordApiBuilder().setToken(token).setAllIntents().login().join(); + //api = new DiscordApiBuilder().setToken(token).addAllIntents(Intent.MESSAGE_CONTENT).login().join(); + //Print the URL to invite the bot if (printInvite) { @@ -39,21 +43,25 @@ public void connect(boolean printInvite) { } //Send bot connected message in channel - api.getServerTextChannelsByName(channelName).forEach(e -> e.sendMessage(api.getYourself().getName() + " has connected")); + api.getServerTextChannelsByName(channelName).forEach(e -> e.sendMessage(api.getYourself().getName() + " has connected, \nDo !help for all commands")); + //add help listener to bot api.addMessageCreateListener(helpListener); //add features - addFeature(new FeatureOne(channelName)); - addFeature(new CurrentTime(channelName)); - addFeature(new HighLowGame(channelName)); - addFeature(new NewsApi(channelName)); - addFeature(new CatFactsApi(channelName)); +// addFeature(new FeatureOne(channelName)); +// addFeature(new CurrentTime(channelName)); +// addFeature(new HighLowGame(channelName)); +// addFeature(new NewsApi(channelName)); +// addFeature(new CatFactsApi(channelName)); +// addFeature(new RandomNumber(channelName)); + addFeature(new Schedule(channelName, new ApiGetter(api))); } private void addFeature(Feature feature){ api.addMessageCreateListener(feature); helpListener.addHelpEmbed(feature.getHelpEmbed()); + } } diff --git a/src/main/java/org/jointheleague/features/help_embed/plain_old_java_objects/help_embed/HelpEmbed.java b/src/main/java/org/jointheleague/features/help_embed/plain_old_java_objects/help_embed/HelpEmbed.java index 50e902ac..5ed2d0fd 100644 --- a/src/main/java/org/jointheleague/features/help_embed/plain_old_java_objects/help_embed/HelpEmbed.java +++ b/src/main/java/org/jointheleague/features/help_embed/plain_old_java_objects/help_embed/HelpEmbed.java @@ -5,7 +5,7 @@ public class HelpEmbed { - private final Color color = Color.green; + private final Color color = Color.getHSBColor((float) 0.48878205, (float)1.0, (float)0.40784314); private final String command; diff --git a/src/main/java/org/jointheleague/features/whale/ApiGetter.java b/src/main/java/org/jointheleague/features/whale/ApiGetter.java new file mode 100644 index 00000000..d3b4724a --- /dev/null +++ b/src/main/java/org/jointheleague/features/whale/ApiGetter.java @@ -0,0 +1,14 @@ +package org.jointheleague.features.whale; + +import org.javacord.api.DiscordApi; + +public class ApiGetter { + + private DiscordApi api; + public ApiGetter(DiscordApi api) { + this.api = api; + } + DiscordApi getApi() { + return api; + } +} diff --git a/src/main/java/org/jointheleague/features/whale/BetterEmbedBuilder.java b/src/main/java/org/jointheleague/features/whale/BetterEmbedBuilder.java new file mode 100644 index 00000000..ef539518 --- /dev/null +++ b/src/main/java/org/jointheleague/features/whale/BetterEmbedBuilder.java @@ -0,0 +1,14 @@ +package org.jointheleague.features.whale; + +import org.javacord.api.entity.message.embed.EmbedBuilder; + +public class BetterEmbedBuilder extends EmbedBuilder{ + public String title; +@Override +public EmbedBuilder setTitle(String title) { + // TODO Auto-generated method stub + this.title = title; + return super.setTitle(title); +} + +} diff --git a/src/main/java/org/jointheleague/features/whale/Event.java b/src/main/java/org/jointheleague/features/whale/Event.java new file mode 100644 index 00000000..2bb47a28 --- /dev/null +++ b/src/main/java/org/jointheleague/features/whale/Event.java @@ -0,0 +1,88 @@ +package org.jointheleague.features.whale; + +import java.util.ArrayList; + +import org.javacord.api.entity.user.User; + +public class Event { + private String name; + private Time time; + private Time endTime; + private String date; + private ArrayList people; + private boolean isLive; + private boolean ReminderSent; + private String iconUrl = "none"; + + Event(String name, Time time, String date) { + this.name = name; + this.time = time; + this.date = date; + people = new ArrayList(); + setLive(false); + } + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public Time getTime() { + return time; + } + public void setTime(Time time) { + this.time = time; + } + public String getDate() { + return date; + } + public void setDate(String date) { + this.date = date; + } + public ArrayList getPeople() { + return people; + } + public void addPeople(Person people) { + this.people.add(people); + } + public void removePeople(User people) { + this.people.remove(people); + } + public void removePeople(int index) { + this.people.remove(index); + } + + public Time getEndTime() { + return endTime; + } + + public void setEndTime(Time endTime) { + this.endTime = endTime; + } + + public boolean isLive() { + return isLive; + } + + public void setLive(boolean isLive) { + this.isLive = isLive; + } + + public boolean isReminderSent() { + return ReminderSent; + } + + public void setReminderSent(boolean hasReminderBeenSent) { + this.ReminderSent = hasReminderBeenSent; + } + + public String getIconUrl() { + return iconUrl; + } + + public void setIconUrl(String iconUrl) { + this.iconUrl = iconUrl; + } + +} diff --git a/src/main/java/org/jointheleague/features/whale/EventConverter.java b/src/main/java/org/jointheleague/features/whale/EventConverter.java new file mode 100644 index 00000000..6241be01 --- /dev/null +++ b/src/main/java/org/jointheleague/features/whale/EventConverter.java @@ -0,0 +1,38 @@ +package org.jointheleague.features.whale; + +public class EventConverter { + + public static String convertToISO8601(Event event) { + // Get date from Event object + String date = event.getDate(); + + // Get time from Event object + Time time = event.getTime(); + String hour = time.getHour(); + String min = time.getMin(); + Boolean isPm = time.getIsPm(); + + // Convert time to 24-hour format if it's in PM + if (isPm) { + int hourInt = Integer.parseInt(hour); + if (hourInt != 12) { + hourInt += 12; + hour = String.valueOf(hourInt); + } + } + + // Construct ISO 8601 formatted date-time string + StringBuilder iso8601 = new StringBuilder(); + iso8601.append(date).append("T").append(hour).append(":").append(min).append(":00"); + + // Append timezone offset (assuming system default timezone) + int offsetMinutes = java.util.TimeZone.getDefault().getOffset(System.currentTimeMillis()) / (60 * 1000); + iso8601.append(offsetMinutes >= 0 ? "+" : "-"); + offsetMinutes = Math.abs(offsetMinutes); + int hoursOffset = offsetMinutes / 60; + int minutesOffset = offsetMinutes % 60; + iso8601.append(String.format("%02d", hoursOffset)).append(":").append(String.format("%02d", minutesOffset)); + + return iso8601.toString(); + } +} diff --git a/src/main/java/org/jointheleague/features/whale/LevenshteinDistance.java b/src/main/java/org/jointheleague/features/whale/LevenshteinDistance.java new file mode 100644 index 00000000..a5f5109e --- /dev/null +++ b/src/main/java/org/jointheleague/features/whale/LevenshteinDistance.java @@ -0,0 +1,37 @@ +package org.jointheleague.features.whale; + +import java.util.Arrays; + +public class LevenshteinDistance { + + public static int calculate(String s1, String s2) { + int[][] dp = new int[s1.length() + 1][s2.length() + 1]; + + for (int i = 0; i <= s1.length(); i++) { + for (int j = 0; j <= s2.length(); j++) { + if (i == 0) { + dp[i][j] = j; + } else if (j == 0) { + dp[i][j] = i; + } else { + dp[i][j] = min( + dp[i - 1][j - 1] + costOfSubstitution(s1.charAt(i - 1), s2.charAt(j - 1)), + dp[i - 1][j] + 1, + dp[i][j - 1] + 1 + ); + } + } + } + + return dp[s1.length()][s2.length()]; + } + + private static int costOfSubstitution(char a, char b) { + return a == b ? 0 : 1; + } + + private static int min(int... numbers) { + return Arrays.stream(numbers) + .min().orElse(Integer.MAX_VALUE); + } +} \ No newline at end of file diff --git a/src/main/java/org/jointheleague/features/whale/Person.java b/src/main/java/org/jointheleague/features/whale/Person.java new file mode 100644 index 00000000..a6abe14a --- /dev/null +++ b/src/main/java/org/jointheleague/features/whale/Person.java @@ -0,0 +1,81 @@ +package org.jointheleague.features.whale; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.javacord.api.entity.permission.Role; +import org.javacord.api.entity.user.User; + +public class Person { + private User user; + private String nickname = "err"; + private String username = "err"; + private ArrayList tags; + private String timezone; + + + public Person(User userById) { + // TODO Auto-generated constructor stub + user = userById; + tags = new ArrayList(); + timezone = "none"; + username = user.getName(); + } + + + public String getNickname() { + // its empt and not Optional.Empty because of the substring on line 45 + if (nickname.equalsIgnoreCase("empt")) { + return username; + } else { + return nickname; + } + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public void setNickname(String nickname) { + this.nickname = nickname.substring(9, nickname.length() - 1); + ; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public ArrayList getTags() { + return tags; + } + public void removeTags(String tag) { + this.tags.remove(tag); + } + public void removeTags(int index) { + this.tags.remove(index); + } + public void addTags(String[] tags) { + + for (int i = 0; i < tags.length; i++) { + this.tags.add(tags[i].trim()); + } + } + + public String getTimezone() { + return timezone; + } + + public void setTimezone(String timezone) { + this.timezone = timezone; + } + +} diff --git a/src/main/java/org/jointheleague/features/whale/Schedule.java b/src/main/java/org/jointheleague/features/whale/Schedule.java new file mode 100644 index 00000000..7aad46cf --- /dev/null +++ b/src/main/java/org/jointheleague/features/whale/Schedule.java @@ -0,0 +1,1259 @@ +package org.jointheleague.features.whale; + +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ExecutionException; + +import javax.imageio.ImageIO; + +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.permission.Role; +import org.javacord.api.entity.server.Server; +import org.javacord.api.entity.user.User; +import org.javacord.api.event.message.MessageCreateEvent; +import org.jointheleague.features.abstract_classes.Feature; +import org.jointheleague.features.help_embed.plain_old_java_objects.help_embed.HelpEmbed; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + + +//To fix +//adding a tag to an event making the date setting not work +//TODO +//allow a "all" command when setting tags +public class Schedule extends Feature { + // + //private static final Logger logger = LogManager.getLogger(Schedule.class); + + Timezones timeZones = new Timezones(); + ArrayList users = new ArrayList(); + ArrayList printedUsers = new ArrayList(); + ArrayList printedUsers2 = new ArrayList(); + List roles = new ArrayList(); + DiscordApi api; + ApiGetter get; + Boolean AMRmode = false; + public final String add = "!addevent"; + public final String remove = "!removeevent"; + public final String[] edit = { "!editevent", "!edit" }; + public final String editTags = "!tags"; + public final String schedule = "!schedule"; + public final String start = "!startevent"; + public final String settings = "!settings"; + // removing + boolean areWeRemoving; + + // shutdown + boolean shutDown; + + // edit events + boolean areWeEditing; + boolean isEventSelected; + boolean setName; + boolean setTime; + boolean setDate; + boolean setPeople; + boolean setIconChange; + int indexOfEvent; + + // tags + String lastRoleUsed; + boolean areWePeopleing; + boolean areTagsBeingSet; + boolean nextTags; + String mostRecentUserName; + int mostRecentUserIndex2; + String lastRoleUsed2; + + // start events + boolean areWeSelectingStartEvent; + int closestDayAsInt; + List closestEvents = new ArrayList<>(); + int howManyMinBeforeEventShouldReminderBeSent = 15; + + ArrayList eventList = new ArrayList(); + + public Schedule(String channelName, ApiGetter get) { + super(channelName); + this.get = get; + + // Create a help embed to describe feature when !help command is sent + helpEmbed = new HelpEmbed("Schedule Bot", "" + + "!addEvent: Adds an event. Start with the event name, time, date, tag(optional but recomended(!tags)) \n\n" + + "!removeEvent: Removes an event\n\n" + + "!editEvent: change the name, time, date, or people attending an event\n\n" + + "!tags: edit the tags of users in an event (add a role name to only show users with that role)\n\n" + + "!timezones: edit users timezones so the bot knows what time for them the events will start (add a role name to only show users with that role)\n\n" + + "!schedule: lists all events \n\n" + "!startEvent: starts the nearest event early\n\n" + + "!endEvent: ends the current event \n\n" + + "!iCan/!imAvailable: allows you to choose what event(s) you can make it to \n\n" + + "!examples: shows examples for every command \n\n" + "!settings: configure the bot\n\n"); + } + + @Override + public void handle(MessageCreateEvent discord) { + String detectedTag = "null"; + api = get.getApi(); + String messageContent = discord.getMessageContent(); + try { + if (messageContent.contains(api.getYourself().getName() + " has connected")) { + setup(discord); + checkTime(discord); + //System.out.println("setup ran"); + } + } catch (Exception e) { + e.printStackTrace(); + } + if (messageContent.toLowerCase().startsWith("!examples") + || messageContent.toLowerCase().startsWith("!example")) { + String examples = "Examples: \n" + + "a /'->/' will mean a new messgae and (\"message\" or \"message\") will mean 2 possible commands to send \n" + + "!addEvent Valorant Grind 9:30pm pdt fri &val \n" + "!removeEvent -> 1\n" + + "!tags member -> 1 -> spectator\n" + "!timezones -> 2 timezones -> GMT\n" + "!schedule \n" + + "!pollEvent -> 2\n" + "!iCan/!imAvailable -> (1,2/3)\n" + "!examples \n" + + "!settings -> addTimeZone IST +12:30"; + discord.getChannel().sendMessage(examples); + } + // thsi will add the strings to the eventList + // ADD + // ADD + // ADD + // ADD + if (messageContent.toLowerCase().startsWith(add) || messageContent.toLowerCase().startsWith("!addevnt")) { + //System.out.println("!addEvent called"); + String eventString = messageContent.substring(add.length()).trim(); + if (eventString.contains(" ")) { + //System.out.println("message contains a space"); + String[] values = eventString.split(" "); + ArrayList usersForEvent = new ArrayList(); + String time = ""; + Time realTime; + String name = ""; + String date = ""; + String realDate = ""; + + // get tbe time/date from the rest of the string + boolean isThereTime = false; + ArrayList indexOfTimes = new ArrayList(); + for (int i = 0; i < 10; i++) { + if (eventString.contains(i + ":")) { + indexOfTimes.add(eventString.indexOf(i + ":") + 1); + //System.out.println("A \':\' was found at index" + (eventString.indexOf(i + ":") + 1)); + isThereTime = true; + } + } + if (isThereTime == false) { + discord.getChannel().sendMessage("No time included!"); + discord.addReactionsToMessage("❌"); + //System.out.println("No time found"); + } else { + //System.out.println("A time was found "); + } + int indexOfTime = Integer.MAX_VALUE; + for (int i = 0; i < indexOfTimes.size(); i++) { + if (indexOfTimes.get(i) < indexOfTime) { + indexOfTime = indexOfTimes.get(i); + //System.out.println("The index of the time was found(" + indexOfTime + ")"); + } + } + if (isANumber(eventString.charAt(indexOfTime - 2) + "")) { + //System.out.println("found at indexoftime -2"); + + name = eventString.substring(0, indexOfTime - 3); + time = eventString.substring(indexOfTime - 2, eventString.length()).trim(); + + realTime = new Time(time.charAt(0) + "" + time.charAt(1) + "", + time.charAt(3) + "" + time.charAt(4) + ""); + + for (int i = 0; i < timeZones.usTimezoneMap.size(); i++) { + if (time.toUpperCase().contains(" " + timeZones.usTimezoneMap.keySet().toArray()[i])) { + //System.out.println("Found timezone"); + realTime.setTimeZone((String) timeZones.usTimezoneMap.keySet().toArray()[i]); + //System.out.println("realTime timezone " + realTime.getTimeZone()); + break; + } + } + } else if (isANumber(eventString.charAt(indexOfTime - 1) + "")) { + + //System.out.println("found at indexoftime -1"); + name = eventString.substring(0, indexOfTime - 2); + time = eventString.substring(indexOfTime - 1, eventString.length()).trim(); + realTime = new Time(time.charAt(0) + "", time.charAt(2) + "" + time.charAt(3) + ""); + for (int i = 0; i < timeZones.usTimezoneMap.size(); i++) { + if (time.toUpperCase().contains("" + timeZones.usTimezoneMap.keySet().toArray()[i])) { + //System.out.println("Found timezone"); + realTime.setTimeZone((String) timeZones.usTimezoneMap.keySet().toArray()[i]); + //System.out.println("realTime timezone " + realTime.getTimeZone()); + break; + } + } + + } else { + //System.out.println("invalid time format"); + discord.getChannel().sendMessage("Invalid Format"); + discord.addReactionsToMessage("❌"); + realTime = null; + } + if (time.toLowerCase().contains("am")) { + realTime.setIsPm(false); + } else if (time.toLowerCase().contains("pm")) { + realTime.setIsPm(true); + } + + if (time.toLowerCase().contains("&")) { + String tag = time.substring(time.indexOf('&') + 1, time.length()); + tag = tag.trim(); + for (int i = 0; i < users.size(); i++) { + for (int o = 0; o < users.get(i).getTags().size(); o++) { + if (tag.equalsIgnoreCase(users.get(i).getTags().get(o))) { + usersForEvent.add(users.get(i).getUser()); + + } + } + } + time = time.substring(0, time.indexOf('&') - 1); + detectedTag = tag; + } + //System.out.println("time after prossesing is " + realTime.getHour() + " " + realTime.getMin()); + + //System.out.println("name and realtime values set"); + // get the date from the time var -Done + // tmr will be the next day - Done + // nothing will be same day or tmr depending on if the time is in the past + // all days of the week(mon) will be the next day that is that day of the week + // a maunual date (5/21) set that date in the same year + String[] dateTime = time.split(" "); + //System.out.println("Time is " + time); + date = dateTime[dateTime.length - 1]; + if (date.toLowerCase().contains("tmr")) { + //System.out.println("the string \"tmr\" was found"); + Date d = new Date(); + d.setMonth(d.getMonth()); + + realDate = ((d.getMonth() + 1) + "/" + (d.getDate() + 1) + "/" + + (d.getYear() + "").substring(1, (d.getYear() + "").length())); + //System.out.println("realDate set"); + } else if (date.toLowerCase().contains("mon") || date.toLowerCase().contains("monday")) { + //System.out.println("\'mon\' was found"); + Date d = new Date(); + d.setMonth(d.getMonth()); + //System.out.println("Current Date " + (d.getMonth() + "/" + (d.getDate()) + "/" + // + (d.getYear() + "").substring(1, (d.getYear() + "").length()))); + if (d.getDay() == 1) { + d.setDate(d.getDate() + 1); + //System.out.println("Same day detected and day added"); + } + while (d.getDay() != 1) { + d.setDate(d.getDate() + 1); + //System.out.println("day added " + d.getDate()); + } + realDate = ((d.getMonth() + 1) + "/" + (d.getDate()) + "/" + + (d.getYear() + "").substring(1, (d.getYear() + "").length())); + } else if (date.toLowerCase().contains("tue") || date.toLowerCase().contains("tues") + || date.toLowerCase().contains("tuesday")) { + //System.out.println("\'tue\' was found"); + Date d = new Date(); + d.setMonth(d.getMonth()); + //System.out.println("Current Date " + (d.getMonth() + "/" + (d.getDate()) + "/" + // + (d.getYear() + "").substring(1, (d.getYear() + "").length()))); + + if (d.getDay() == 2) { + d.setDate(d.getDate() + 1); + //System.out.println("Same day detected and day added"); + } + while (d.getDay() != 2) { + d.setDate(d.getDate() + 1); + //System.out.println("day added " + d.getDate()); + } + realDate = ((d.getMonth() + 1) + "/" + (d.getDate()) + "/" + + (d.getYear() + "").substring(1, (d.getYear() + "").length())); + } else if (date.toLowerCase().contains("wed") || date.toLowerCase().contains("wednesday")) { + //System.out.println("\'tue\' was found"); + Date d = new Date(); + d.setMonth(d.getMonth()); + //System.out.println("Current Date " + (d.getMonth() + "/" + (d.getDate()) + "/" + // + (d.getYear() + "").substring(1, (d.getYear() + "").length()))); + + if (d.getDay() == 3) { + d.setDate(d.getDate() + 1); + //System.out.println("Same day detected and day added"); + } + while (d.getDay() != 3) { + d.setDate(d.getDate() + 1); + //System.out.println("day added " + d.getDate()); + } + realDate = ((d.getMonth() + 1) + "/" + (d.getDate()) + "/" + + (d.getYear() + "").substring(1, (d.getYear() + "").length())); + } else if (date.toLowerCase().contains("thurs") || date.toLowerCase().contains("thu") + || date.toLowerCase().contains("thur") || date.toLowerCase().contains("thursday")) { + //System.out.println("\'thurs\' was found"); + Date d = new Date(); + d.setMonth(d.getMonth()); + //System.out.println("Current Date " + (d.getMonth() + "/" + (d.getDate()) + "/" + // + (d.getYear() + "").substring(1, (d.getYear() + "").length()))); + + if (d.getDay() == 4) { + d.setDate(d.getDate() + 1); + //System.out.println("Same day detected and day added"); + } + while (d.getDay() != 4) { + d.setDate(d.getDate() + 1); + //System.out.println("day added " + d.getDate()); + } + realDate = ((d.getMonth() + 1) + "/" + (d.getDate()) + "/" + + (d.getYear() + "").substring(1, (d.getYear() + "").length())); + } else if (date.toLowerCase().contains("fri") || date.toLowerCase().contains("friday")) { + //System.out.println("\'fri\' was found"); + Date d = new Date(); + d.setMonth(d.getMonth()); + //System.out.println("Current Date " + (d.getMonth() + "/" + (d.getDate()) + "/" + // + (d.getYear() + "").substring(1, (d.getYear() + "").length()))); + + if (d.getDay() == 5) { + d.setDate(d.getDate() + 1); + //System.out.println("Same day detected and day added"); + } + while (d.getDay() != 5) { + d.setDate(d.getDate() + 1); + //System.out.println("day added " + d.getDate()); + } + realDate = ((d.getMonth() + 1) + "/" + (d.getDate()) + "/" + + (d.getYear() + "").substring(1, (d.getYear() + "").length())); + } else if (date.toLowerCase().contains("sat") || date.toLowerCase().contains("saturday")) { + //System.out.println("\'sat\' was found"); + Date d = new Date(); + int currentDate = d.getDate(); + d.setMonth(d.getMonth()); + //System.out.println("Current Date " + (d.getMonth() + "/" + (d.getDate()) + "/" + // + (d.getYear() + "").substring(1, (d.getYear() + "").length()))); + if (d.getDay() == 6) { + d.setDate(d.getDate() + 1); + //System.out.println("Same day detected and day added"); + } + while (d.getDay() != 6) { + d.setDate(d.getDate() + 1); + //System.out.println("day added " + d.getDate()); + } + realDate = ((d.getMonth() + 1) + "/" + (d.getDate()) + "/" + + (d.getYear() + "").substring(1, (d.getYear() + "").length())); + } else if (date.toLowerCase().contains("sun") || date.toLowerCase().contains("sunday")) { + //System.out.println("\'sun\' was found"); + Date d = new Date(); + d.setMonth(d.getMonth()); + //System.out.println("Current Date " + (d.getMonth() + "/" + (d.getDate()) + "/" + // + (d.getYear() + "").substring(1, (d.getYear() + "").length()))); + + if (d.getDay() == 0) { + d.setDate(d.getDate() + 1); + //System.out.println("Same day detected and day added"); + + } + while (d.getDay() != 0) { + d.setDate(d.getDate() + 1); + //System.out.println("day added " + d.getDate()); + } + realDate = ((d.getMonth() + 1) + "/" + (d.getDate()) + "/" + + (d.getYear() + "").substring(1, (d.getYear() + "").length())); + } else if (date.toLowerCase().contains("/") || date.toLowerCase().contains("-")) { + String[] fullDate; + Date d = new Date(); + if (date.toLowerCase().contains("/")) { + fullDate = date.split("/"); + } else if (date.toLowerCase().contains("-")) { + fullDate = date.split("-"); + } else { + discord.getChannel().sendMessage("Add a \"/\" or \"-\" between numbers in the date"); + discord.addReactionsToMessage("❌"); + fullDate = null; + } + if (fullDate.length == 2) { + realDate = (fullDate[0] + "/" + fullDate[1] + "/" + + (d.getYear() + "").substring(1, (d.getYear() + "").length())); + } else if (fullDate.length == 3) { + realDate = (fullDate[0] + "/" + fullDate[1] + "/" + fullDate[2]); + } else { + discord.getChannel().sendMessage("Invalid Date"); + discord.addReactionsToMessage("❌"); + } + } else { + Date d = new Date(); + realDate = ((d.getMonth() + 1) + "/" + (d.getDate()) + "/" + + (d.getYear() + "").substring(1, (d.getYear() + "").length())); + } + + Event event = new Event(name, realTime, realDate); + for (int i = 0; i < usersForEvent.size(); i++) { + Person p = new Person(usersForEvent.get(i)); + event.addPeople(p); + } + eventList.add(event); + + //System.out.println("Date = " + realDate); + //System.out.println("Timezone " + eventList.get(eventList.size() - 1).getTime().getTimeZone()); + //System.out.println("event constructed"); + discord.addReactionsToMessage("✅"); + + } else { + discord.getChannel().sendMessage("Invalid Format"); + discord.addReactionsToMessage("❌"); + } + + discord.getChannel() + .sendMessage("The Event recived was Name = |" + eventList.get(eventList.size() - 1).getName() + + "| Time = |" + eventList.get(eventList.size() - 1).getTime().getTimeAsString() + + "| Zone = |" + eventList.get(eventList.size() - 1).getTime().getTimeZone() + "|" + + " |Date = |" + eventList.get(eventList.size() - 1).getDate() + "|" + " |Tag = |" + + detectedTag + "|"); + //System.out.println("Message sent to channel"); + + // event.getChannel().sendMessage("Sending a message to the channel"); + for (int i = 0; i < eventList.size(); i++) { + if (eventList.get(i).isLive() == true) { + eventList.remove(i); + i = 0; + } + } + } + + // this will remove an event from the list + // REMOVE + // REMOVE + // REMOVE + // REMOVE + if (messageContent.toLowerCase().startsWith(remove) || messageContent.toLowerCase().startsWith("!removeevnt")) { + areWeRemoving = true; + String listOfEvents = "Enter the number next to the event to remove it sperate numbers with commas to remove multiple\n\n"; + for (int i = 0; i < eventList.size(); i++) { + listOfEvents += (i + 1) + ": " + eventList.get(i).getName() + " " + + eventList.get(i).getTime().getTimeAsString() + " " + eventList.get(i).getDate() + "\n"; + } + + discord.getChannel().sendMessage(listOfEvents); + + } else if (areWeRemoving) { + int index = -1; + if (isANumber(discord.getMessageContent())) { + //System.out.println("No commas"); + index = Integer.parseInt(discord.getMessageContent()); + eventList.remove(index - 1); + discord.getChannel().sendMessage("Event Removed"); + areWeRemoving = false; + } else if (discord.getMessageContent().contains(",")) { + //System.out.println("Has commas"); + String[] indexesString = discord.getMessageContent().split(","); + //System.out.println("split"); + Integer[] indexes = new Integer[indexesString.length]; + //System.out.println("int array made"); + int smallest = Integer.MAX_VALUE; + for (int i = 0; i < indexesString.length; i++) { + //System.out.println("parseInt for " + indexesString[i]); + indexes[i] = Integer.parseInt(indexesString[i]); + } + Event[] events = new Event[indexes.length]; + //System.out.println("Event List created"); + for (int i = 0; i < events.length; i++) { + events[i] = eventList.get(indexes[i] - 1); + //System.out.println("Setting" + (indexes[i] - 1)); + } + for (int i = 0; i < events.length; i++) { + eventList.remove(events[i]); + //System.out.println("removing " + events[i].getName()); + } + areWeRemoving = false; + } + + } + + // EDIT EVENT + if (messageContent.toLowerCase().startsWith(edit[0]) + || messageContent.toLowerCase().startsWith(edit[1]) && !discord.getMessage().getAuthor().isBotUser()) { + areWeEditing = true; + String listOfEvents = "Enter the number next to the event to edit it\n\n"; + for (int i = 0; i < eventList.size(); i++) { + listOfEvents += (i + 1) + ": " + eventList.get(i).getName() + " " + + eventList.get(i).getTime().getTimeAsString() + " " + eventList.get(i).getDate() + "\n"; + } + discord.getChannel().sendMessage(listOfEvents); + } else if (areWeEditing && !discord.getMessage().getAuthor().isBotUser()) { + int index = -1; + if (isANumber(discord.getMessageContent())) { + index = Integer.parseInt(discord.getMessageContent()); + discord.getChannel() + .sendMessage("Event: " + eventList.get(index - 1).getName() + " " + + eventList.get(index - 1).getTime().getTimeAsString() + " " + + eventList.get(index - 1).getDate() + " selected"); + indexOfEvent = index - 1; + discord.getChannel().sendMessage("Enter \n 1: name \n 2: time \n 3: date \n 4: people \n 5: icon"); + isEventSelected = true; + areWeEditing = false; + } + } else if (isEventSelected && isANumber(discord.getMessageContent()) + && !discord.getMessage().getAuthor().isBotUser()) { + int option = Integer.parseInt(discord.getMessageContent()); + if (option == 1) { + discord.getChannel().sendMessage("Enter the new name for the event"); + setName = true; + areWeEditing = false; + } else if (option == 2) { + discord.getChannel().sendMessage( + "Enter the new time for the event (ex. 10:30am PT) or add an end time by saying end time (ex. end time 12:30pm PT) format exactly like the examples"); + setTime = true; + areWeEditing = false; + } else if (option == 3) { + discord.getChannel() + .sendMessage("Enter the new date for the event (ex. 10/12/24) format exactly like this"); + setDate = true; + areWeEditing = false; + } else if (option == 4) { + Event event = eventList.get(indexOfEvent); + long serverId = discord.getServer().get().getId(); + Server server = api.getServerById(serverId).get(); + discord.getChannel().sendMessage( + "Enter the number next to the user then remove (ex. 3 remove) to add say a username then add (ex. whale1929 add) make sure to use the username not the nickname. Use commas to add and remove multiple people (ex. whale1929 add, 4 remove)"); + String peopleInEvent = ""; + if (event.getPeople().size() == 0) { + peopleInEvent += "\n There are no users in this event"; + } else { + for (int i = 0; i < event.getPeople().size(); i++) { + String nickname = "err"; + try { + nickname = api.getUserById(event.getPeople().get(i).getUser().getId()).get() + .getNickname(server) + ""; + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + event.getPeople().get(i).setNickname(nickname); + peopleInEvent += (i + 1) + ": " + event.getPeople().get(i).getNickname() + "(" + + event.getPeople().get(i).getUsername() + ")\n"; + } + } + discord.getChannel().sendMessage(peopleInEvent); + setPeople = true; + areWeEditing = false; + } else if (option == 5) { + Event event = eventList.get(indexOfEvent); + if (event.getIconUrl() == "none") { + EmbedBuilder embedBuilder = new EmbedBuilder().setTitle(event.getName()) + // \nEnter a description of your image that will go to google and get the first + // result(ex. valorant) + .setDescription("Current Icon: \"none\"").setColor(Color.WHITE); + discord.getChannel().sendMessage(embedBuilder); + discord.getChannel().sendMessage( + "Enter a description of your image that will go to google and get the first result(ex. valorant) or an image url"); + } else { + EmbedBuilder embedBuilder = new EmbedBuilder().setTitle(event.getName()) + // \nEnter a description of your image that will go to google and get the first + // result(ex. valorant) + .setDescription("Current Icon:").setThumbnail(event.getIconUrl()).setColor(Color.WHITE); + discord.getChannel().sendMessage(embedBuilder); + discord.getChannel().sendMessage( + "Enter a description of your image that will go to google and get the first result(ex. valorant) or an image url"); + } + + setIconChange = true; + areWeEditing = false; + } + isEventSelected = false; + } + + else if (setName && !discord.getMessage().getAuthor().isBotUser()) { + eventList.get(indexOfEvent).setName(messageContent.trim()); + discord.getChannel().sendMessage("Name changed to " + eventList.get(indexOfEvent).getName()); + setName = false; + } else if (setTime && !discord.getMessage().getAuthor().isBotUser()) { + boolean endEvent = false; + if (messageContent.toLowerCase().contains("end event")) { + messageContent = messageContent.toLowerCase(); + messageContent.replace("end event", ""); + endEvent = true; + } + String[] time = messageContent.trim().split(":"); + String hour = time[0]; + String[] time2 = time[1].split(""); + String min = time2[0] + time2[1]; + Time t = new Time(hour, min); + if (time2[3].equalsIgnoreCase("a")) { + t.setIsPm(false); + } else if (time2[3].equalsIgnoreCase("p")) { + t.setIsPm(true); + } + String timezone = time[1].split(" ")[1].trim(); + t.setTimeZone(timezone); + if (endEvent == false) { + eventList.get(indexOfEvent).setTime(t); + } else if (endEvent == true) { + eventList.get(indexOfEvent).setEndTime(t); + } + discord.getChannel() + .sendMessage("Time changed to " + eventList.get(indexOfEvent).getTime().getTimeAsString() + " " + + eventList.get(indexOfEvent).getTime().getTimeZone()); + setTime = false; + } else if (setDate && !discord.getMessage().getAuthor().isBotUser()) { + eventList.get(indexOfEvent).setDate(messageContent.trim()); + discord.getChannel().sendMessage("Date changed to " + eventList.get(indexOfEvent).getDate()); + setDate = false; + } else if (setPeople && !discord.getMessage().getAuthor().isBotUser()) { + String[] split = null; + if (messageContent.contains(",")) { + split = messageContent.trim().split(","); + } else { + split = new String[1]; + split[0] = messageContent.trim(); + } + for (int i = 0; i < split.length; i++) { + String[] msg = split[i].trim().split(" "); + if (msg[1].contains("add")) { + //System.out.println("adding"); + int indexOfClosest = -1; + String name = msg[0]; + LevenshteinDistance distance = new LevenshteinDistance(); + //System.out.println("LevenshteinDistance made"); + int closest = Integer.MAX_VALUE; + //System.out.println("User size " + users.size()); + for (int o = 0; o < users.size(); o++) { + //System.out.println("checking distance"); + int howFar = distance.calculate(name, users.get(o).getUsername()); + if (howFar < closest) { + //System.out.println("new distance found"); + closest = howFar; + indexOfClosest = o; + } + } + if (eventList.get(indexOfEvent).getPeople().contains(users.get(indexOfClosest))) { + discord.getChannel().sendMessage(users.get(indexOfClosest).getNickname() + "(" + + users.get(indexOfClosest).getUsername() + ") is already in the event"); + } else { + eventList.get(indexOfEvent).addPeople(users.get(indexOfClosest)); + discord.getChannel().sendMessage(users.get(indexOfClosest).getNickname() + "(" + + users.get(indexOfClosest).getUsername() + ") was added to the event"); + } + } else if (msg[1].contains("remove")) { + int index = Integer.parseInt(msg[0].trim()) - (1 + i); + + discord.getChannel() + .sendMessage(eventList.get(indexOfEvent).getPeople().get(index).getNickname() + "(" + + eventList.get(indexOfEvent).getPeople().get(index).getUsername() + + ") was removed from the event"); + eventList.get(indexOfEvent).removePeople(index); + } else { + discord.getChannel().sendMessage("Message must contain a number/name then add/remove"); + discord.addReactionsToMessage("❌"); + } + + } + setPeople = false; + } else if (setIconChange && !discord.getMessage().getAuthor().isBotUser()) { + SerpAPI imageSearch = new SerpAPI(); + Event event = eventList.get(indexOfEvent); + if (discord.getMessageContent().contains("/") && discord.getMessageContent().contains(".")) { + event.setIconUrl(discord.getMessageContent().trim()); + EmbedBuilder embedBuilder = new EmbedBuilder().setTitle(event.getName()).setDescription("New Icon:") + .setThumbnail(event.getIconUrl()).setColor(Color.WHITE); + discord.getChannel().sendMessage(embedBuilder); + discord.getChannel().sendMessage("Btw there is only 100 icon searches a month so use them wisely"); + } else { + //System.out.println("image search on " + discord.getMessageContent()); + Long messageID = (long) 0.0; + try { + messageID = discord.getChannel().sendMessage("Getting Image . . .").get().getId(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + String iconUrl = imageSearch.getImage(discord.getMessageContent()); + discord.getChannel().deleteMessages(messageID); + event.setIconUrl(iconUrl); + EmbedBuilder embedBuilder = new EmbedBuilder().setTitle(event.getName()).setDescription("New Icon:") + .setThumbnail(event.getIconUrl()).setColor(Color.WHITE); + discord.getChannel().sendMessage(embedBuilder); + } + setIconChange = false; + } + + //System.out.println(areWeRemoving); + // SCHEDULE + // SCHEDULE + // SCHEDULE + // SCHEDULE + if (messageContent.toLowerCase().startsWith(schedule)) { + BetterEmbedBuilder[] embedBuilderArr = new BetterEmbedBuilder[eventList.size()]; + for (int i = 0; i < eventList.size(); i++) { + BetterEmbedBuilder embedBuilder = embedCreator(eventList.get(i)); + embedBuilderArr[i] = embedBuilder; + } + + discord.getChannel().sendMessage(embedBuilderArr); + } + +// START EVENT +// START EVENT +// START EVENT +// START EVENT + if (messageContent.toLowerCase().startsWith(start)) { + try { + //System.out.println("start event called"); + + Double[] closestDay = { Double.MAX_VALUE, -1.0 }; + for (int i = 0; i < eventList.size(); i++) { + String[] tempDate = eventList.get(i).getDate().split("/"); + double hour = Integer.parseInt(eventList.get(i).getTime().getHour()); + hour -= timeZones.usTimezoneMap.get(eventList.get(i).getTime().getTimeZone()); + int min = Integer.parseInt(eventList.get(i).getTime().getMin()); + double dateAsInt = Double.parseDouble(tempDate[2] + tempDate[0] + tempDate[1]) + hour + min; + if (dateAsInt < closestDay[0]) { + closestDay[0] = dateAsInt; + closestDay[1] = i + 0.0; + closestEvents.clear(); + closestEvents.add(eventList.get(i)); + } else if (dateAsInt == closestDay[0]) { + closestEvents.add(eventList.get(i)); + } + } + if (closestEvents.size() > 1) { + String msg = ""; + int i = 0; + for (Event event : closestEvents) { + msg += i + ": " + event.getName() + " " + event.getTime().getTimeAsString() + " " + + event.getTime().getTimeZone() + " " + event.getDate() + "\n"; + i++; + } + discord.getChannel().sendMessage("There are " + closestEvents.size() + + " events, enter the number next to the event to start it \n" + msg); + areWeSelectingStartEvent = true; + } else { + closestDayAsInt = Integer + .parseInt((closestDay[1] + "").substring(0, (closestDay[1] + "").indexOf('.'))); + discord.getChannel() + .sendMessage("Closest event is " + eventList.get(closestDayAsInt).getName() + " " + + eventList.get(closestDayAsInt).getTime().getTimeAsString() + " " + + eventList.get(closestDayAsInt).getTime().getTimeZone() + " " + + eventList.get(closestDayAsInt).getDate() + "\nEnter \'start\' to start it"); + areWeSelectingStartEvent = true; + } + } catch (Exception e) { + e.printStackTrace(); + } + } else if (areWeSelectingStartEvent) { + if (messageContent.toLowerCase().contains("start") && !discord.getMessage().getAuthor().isBotUser()) { + startEvent(eventList.get(closestDayAsInt), discord); + } else { + int index = Integer.parseInt(messageContent.trim()); + for (int i = 0; i < eventList.size(); i++) { + if (eventList.get(i).equals(closestEvents.get(index))) { + startEvent(eventList.get(i), discord); + break; + } + } + } + areWeSelectingStartEvent = false; + } + // TAGS + // tagshere + String listOfPeople = "err"; + if (messageContent.toLowerCase().startsWith(editTags) || nextTags) { + nextTags = false; + areTagsBeingSet = false; + String role = null; + + if (messageContent.contains(" ")) { + role = messageContent.substring(6, messageContent.length()).trim(); + + } + if (messageContent.contains(" ") && !nextTags) { + + } else { + role = "everyone"; + } + if (discord.getMessage().getAuthor().isBotUser()) { + role = lastRoleUsed; + } + //System.out.println("role string created"); + //System.out.println("!tags called"); + long serverId = discord.getMessage().getServer().get().getId(); + //System.out.println("server id is " + discord.getMessage().getServer().get().getId()); + listOfPeople = "Tags are used to categorize people for easy event management \n add an \'&(insert your tage here)\' at the end of the message when creating an event \n Everyone with that tag will be added to that event and pinged when it starts \n\n" + + "Enter the number next to the user, say \"end tags\" to stop editing tags\n"; + if (users.size() <= 0) { + api.getServerById(serverId).ifPresent(server -> { + //System.out.println(server.getMemberCount()); + for (int i = 0; i < server.getMemberCount(); i++) { + //System.out.println(server.getMembers().toArray()[i]); + String userInfo = server.getMembers().toArray()[i].toString(); + String userId = userInfo.substring(userInfo.indexOf("id") + 4, userInfo.indexOf(',')); + Person p = null; + try { + p = new Person(api.getUserById(userId).get()); + p.setNickname(api.getUserById(userId).get().getNickname(server) + ""); + p.setUsername(api.getUserById(userId).get().getName() + ""); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + users.add(p); + } + + }); + //System.out.println("users in list"); + } + Server server = api.getServerById(serverId).get(); + //System.out.println("user list size " + users.size()); + int indexOfClosest = -1; + if (role != null) { + LevenshteinDistance distance = new LevenshteinDistance(); + int closest = Integer.MAX_VALUE; + roles = server.getRoles(); + //System.out.println("Roles list size = " + role.length()); + for (int i = 0; i < roles.size(); i++) { + //System.out.println("checking distance"); + int howFar = distance.calculate(role, roles.get(i).getName()); + howFar = 1; + //System.out.println("howFar = " + howFar); + if (howFar < closest) { + //System.out.println("new distance found"); + closest = howFar; + //System.out.println("role = " + role); + indexOfClosest = i; + } + } + + + + //System.out.println("Org Role: " + role); + //System.out.println("indexofClosest: " + indexOfClosest); + //System.out.println("Closest Role name: " + roles.get(indexOfClosest).getName()); + lastRoleUsed = roles.get(indexOfClosest).getName(); + //System.out.println("Found distance"); + } + int numberForList = 0; + //System.out.println("Users.size = " + users.size()); + for (int i = 0; i < users.size(); i++) { + //System.out.println("users.size > 0"); + try { + if (role != null) { + //System.out.println("role is not null"); + roles = server.getRoles(); + users.get(i).setUser(api.getUserById(users.get(i).getUser().getId()).get()); + if (users.get(i).getUser().getRoles(server).contains(roles.get(indexOfClosest))) { + //System.out.println("a role in the server matched the closest role"); + users.get(i).setNickname( + api.getUserById(users.get(i).getUser().getId()).get().getNickname(server) + ""); + users.get(i).setUsername(api.getUserById(users.get(i).getUser().getId()).get().getName() + ""); + //System.out.println("users.get i name = " + users.get(i).getNickname()); + printedUsers.add(users.get(i)); + //System.out.println("updated users with specific roles"); + listOfPeople += ((numberForList + 1) + ": " + users.get(i).getNickname() + " (" + + users.get(i).getUsername() + ")\n"); + numberForList++; + } + } else { + continue; + } + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + //System.out.println("list of people string is made"); + + //System.out.println("List of people updated"); + //System.out.println(listOfPeople); + discord.getChannel().sendMessage(listOfPeople); + areWePeopleing = true; + }else if(areWePeopleing&&!discord.getMessage().getAuthor().isBotUser()) + + { + if (messageContent.equalsIgnoreCase("end tags")) { + discord.getChannel().sendMessage("Stopped Modifying Tags"); + areWePeopleing = false; + areTagsBeingSet = false; + nextTags = false; + } + if (areTagsBeingSet && !discord.getMessage().getAuthor().isBotUser()) { + int index = 0; + for (int i = 0; i < users.size(); i++) { + if (mostRecentUserName.equals(users.get(i).getUsername())) { + index = i; + break; + } + } + if (messageContent.contains(",")) { + + //System.out.println("Most recent user index is " + index); + //System.out.println("Person at " + users.get(index)); + String[] tags = messageContent.trim().split(", "); + users.get(index).addTags(tags); + String whatTagsAreSet = "Tags "; + for (int i = 0; i < tags.length; i++) { + whatTagsAreSet += tags[i] + ", "; + } + whatTagsAreSet = whatTagsAreSet.substring(0, whatTagsAreSet.lastIndexOf(',')); + areTagsBeingSet = false; + discord.getChannel().sendMessage(whatTagsAreSet + " set to " + users.get(index).getNickname()); + nextTags = true; + + } else if (messageContent.toLowerCase().contains("no tag")) { + discord.getChannel().sendMessage("No tags set"); + areTagsBeingSet = false; + nextTags = true; + } else { + //System.out.println("Most recent user index is " + index); + //System.out.println("Person at " + users.get(index)); + String[] tags = { messageContent.trim() }; + users.get(index).addTags(tags); + //System.out.println("Tags of user: " + users.get(index).getTags().get(0)); + areTagsBeingSet = false; + discord.getChannel().sendMessage("Tag " + tags[0] + " set to " + users.get(index).getNickname()); + nextTags = true; + } + } else { + int index = -1; + String[] msg = discord.getMessageContent().split(" "); + if (isANumber(msg[0].trim())) { + //System.out.println("No commas"); + index = Integer.parseInt(msg[0].trim()); + //System.out.println("parse"); + // if (discord.getMessageContent().toLowerCase().contains("tags")) { + //System.out.println("printedUsers size = " + printedUsers.size() + " index = " + index); + String userStatus = printedUsers.get(index - 1).getNickname() + "(" + + printedUsers.get(index - 1).getUsername() + ")\n"; + //System.out.println("user status made"); + userStatus += "Current Tags: "; + if (printedUsers.get(index - 1).getTags().size() == 0) { + userStatus += "none"; + } else { + for (int i = 0; i < printedUsers.get(index - 1).getTags().size(); i++) { + userStatus += printedUsers.get(index - 1).getTags().get(i) + ", "; + userStatus = userStatus.substring(0, userStatus.length() - 2); + } + //System.out.println("for loop ran"); + } + discord.getChannel().sendMessage( + "enter a list of tags to add or just one (ex. gamer, all) say \"no tag\" to not add a tag\n" + + userStatus); + + areTagsBeingSet = true; + mostRecentUserName = printedUsers.get(index - 1).getUsername(); + //System.out.println("message sent "); + //System.out.println(printedUsers.size()); + // printedUsers.get(index - 1).setTags(tags); + //System.out.println("set tags"); + + printedUsers = new ArrayList(); + } + + // update list + for (int i = 0; i < printedUsers.size(); i++) { + for (int o = 0; o < users.size(); o++) { + if (printedUsers.get(i).getUser().getId() == users.get(o).getUser().getId()) { + users.remove(o); + users.add(printedUsers.get(i)); + } + } + } + } + } + +// SETTINGS +// SETTINGS +// SETTINGS +// SETTINGS + if(messageContent.toLowerCase().startsWith(settings)) + { + discord.getChannel().sendMessage( + "Welcome to Settings here is the list of settings(for all commands say the command then a space then the value) \n" + + "!addTimeZone: Enter a timezone abbreviation then the time diiffrence from PT (ex. IST +12:30)\n" + + "!setReminder: Enter a number that will be the number of minutes before an event a reminder will go out\n" + ); + }else if(messageContent.toLowerCase().startsWith("!addtimezone")) + { + //System.out.println("add time zone called"); + String[] time = messageContent.split(" "); + //System.out.println("split"); + if (time[2].contains("+")) { + time[2] = time[2].substring(1).trim(); + //System.out.println("+ removed and trimed"); + } + if (time[2].contains(":30")) { + time[2] = time[2].replace(":30", ".5"); + } + if (time[2].contains(":45")) { + time[2] = time[2].replace(":45", ".75"); + } + //System.out.println("time at 1 " + time[1] + ", time at 2 " + time[2]); + timeZones.addTimezone(time[1], Double.parseDouble(time[2])); + //System.out.println("timezone added"); + discord.getChannel().sendMessage("Timezone " + time[1] + " with a " + time[2] + " hour difference to PT"); + }else if(messageContent.toLowerCase().startsWith("!setreminder")) + { + try { + //System.out.println("set reminder called"); + String[] time = messageContent.split(" "); + //System.out.println("split"); + int reminderTime = Integer.parseInt(time[1].trim()); + howManyMinBeforeEventShouldReminderBeSent = reminderTime; + discord.getChannel().sendMessage("Reminder changed to " + howManyMinBeforeEventShouldReminderBeSent + " mins"); + } catch (Exception e) { + discord.getChannel().sendMessage("Make sure you are entering a number"); + } + } + + if(messageContent.toLowerCase().startsWith("!test")) + { + EmbedBuilder embedBuilder = embedCreator(eventList.get(0)); + api.getTextChannelById("1240524647674548306").ifPresent(channel -> { + channel.sendMessage(embedBuilder); + }); +// if (messageContent.toLowerCase().contains("2")) { +// discord.getChannel().sendMessage("sending a image"); +// discord.getChannel().sendMessage("here is your image", imageFile); +// discord.getChannel().sendMessage("sent"); +// } else { +// discord.getChannel().sendMessage("sending a image"); +// ByteArrayInputStream bais = new ByteArrayInputStream(ba); +// discord.getChannel().sendMessage("here is your image", bais, "Scary.jpeg"); +// discord.getChannel().sendMessage("sent"); +// } + //System.out.println("test"); +// try { +// Date d = new Date(); +// Event e = eventList.get(0); +// d.setDate(Integer.parseInt(e.getDate().split("/")[1])); +// d.setMonth(Integer.parseInt(e.getDate().split("/")[0]) - 1); +// d.setYear(Integer.parseInt("1" + e.getDate().split("/")[2])); +// d.setMinutes(Integer.parseInt(e.getTime().getMin())); +// discord.getChannel().sendMessage(timeZones.getTimeForStamp(d)); +// } catch (Exception e) { +// e.printStackTrace(); +// } + + }if(messageContent.toLowerCase().startsWith("!stop")) + { + discord.getChannel().sendMessage("Are you sure you want the bot to shut down and delete all data \n !yes, !no"); + shutDown = true; + + }if(shutDown==true&&messageContent.toLowerCase().startsWith("!yes")) + { + discord.getChannel().sendMessage("bye"); + shutDown = false; + System.exit(0); + }else if(shutDown==true&&messageContent.toLowerCase().startsWith("!no")){ + shutDown = false; + } + + checkTime(discord); + } + + BetterEmbedBuilder embedCreator(Event e) { + String listOfPeople = "Participants: "; + if (e.getPeople().size() == 0) { + listOfPeople = "No participants added"; + } else if (e.getPeople().size() <= 5) { + for (int i = 0; i < e.getPeople().size(); i++) { + if (i == e.getPeople().size() - 1) { + listOfPeople += e.getPeople().get(i).getNickname(); + } else { + listOfPeople += e.getPeople().get(i).getNickname() + ", "; + } + } + } else { + for (int i = 0; i < e.getPeople().size(); i++) { + if (i + 1 > 5) { + listOfPeople += "and " + (e.getPeople().size() - i) + " more."; + break; + } else { + listOfPeople += e.getPeople().get(i).getNickname() + ", "; + } + } + } + if (listOfPeople.charAt(listOfPeople.length() - 2) == ',') { + listOfPeople = listOfPeople.substring(0, listOfPeople.length() - 2); + } + BetterEmbedBuilder embedBuilder = (BetterEmbedBuilder) new BetterEmbedBuilder().setTitle(e.getName()) + .setDescription(getTimeStamp(e) + "\n" + "" + e.getDate() + "" + "\n" + listOfPeople) + .setThumbnail(e.getIconUrl()) + .setColor(Color.getHSBColor((float) 0.48878205, (float) 1.0, (float) 0.40784314)); + + return embedBuilder; + } + + String getTimeStamp(Event e) { + Date d = new Date(); + d.setDate(Integer.parseInt(e.getDate().split("/")[1])); + d.setMonth(Integer.parseInt(e.getDate().split("/")[0]) - 1); + d.setYear(Integer.parseInt("1" + e.getDate().split("/")[2])); + d.setMinutes(Integer.parseInt(e.getTime().getMin())); + if (e.getTime().getIsPm() == true) { + // PM + if (Integer.parseInt(e.getTime().getHour()) + 12 == 24) { + d.setHours(Integer.parseInt(e.getTime().getHour())); + } else { + d.setHours(Integer.parseInt(e.getTime().getHour()) + 12); + } + } else { + // AM + if (Integer.parseInt(e.getTime().getHour()) + 12 == 24) { + d.setHours(Integer.parseInt(e.getTime().getHour()) - 12); + } else { + d.setHours(Integer.parseInt(e.getTime().getHour())); + } + + } + return timeZones.getTimeForStamp(d); + } + + void checkTime(MessageCreateEvent discord) { + Date d = new Date(); + Date d2 = new Date(); + for (int i = 0; i < eventList.size(); i++) { + Event e = eventList.get(i); + if (e.isLive() == true) { + continue; + } + d.setDate(Integer.parseInt(e.getDate().split("/")[1])); + // //System.out.println("Date" + Integer.parseInt(e.getDate().split("/")[1])); + d.setMonth(Integer.parseInt(e.getDate().split("/")[0]) - 1); + // //System.out.println("Month" + Integer.parseInt(e.getDate().split("/")[0])); + d.setYear(Integer.parseInt("1" + e.getDate().split("/")[2])); + // //System.out.println("Year" + Integer.parseInt(e.getDate().split("/")[2])); + d.setMinutes(Integer.parseInt(e.getTime().getMin())); + if (e.isReminderSent() == false) { + d.setMinutes(d.getMinutes() - howManyMinBeforeEventShouldReminderBeSent); + } + if (e.getTime().getIsPm() == true) { + d.setHours(Integer.parseInt(e.getTime().getHour()) + 12); + } else { + d.setHours(Integer.parseInt(e.getTime().getHour())); + } +// d2.setTime(Instant.now().getEpochSecond()); + if (d.getYear() == (d2.getYear())) { + // //System.out.println("same year"); + if (d.getMonth() == d2.getMonth()) { + // //System.out.println("same month"); + if (d.getDate() == d2.getDate()) { + // //System.out.println("same date"); + if (d.getHours() == d2.getHours()) { + // //System.out.println("same hours"); + // //System.out.println("d: " + d.getMinutes() + " d2: " + d2.getMinutes()); + if (d.getMinutes() == d2.getMinutes()) { + //System.out.println("same min and event starting"); + if (e.isReminderSent() == false) { + sendReminder(eventList.get(i), discord); + } else { + startEvent(eventList.get(i), discord); + } + } + } + } + } + } + } + Timer timer = new Timer(); + TimerTask task = new TimerTask() { + @Override + public void run() { + checkTime(discord); + } + }; + timer.schedule(task, 1000 * 5); + } + + void startEvent(Event event, MessageCreateEvent discord) { + if (event.isLive() == false) { + event.setLive(true); + discord.getChannel().sendMessage("Event **" + event.getName() + "** started"); + } + } + + void sendReminder(Event event, MessageCreateEvent discord) { + if (event.isReminderSent() == false) { + event.setReminderSent(true); + discord.getChannel().sendMessage("Event **" + event.getName() + "** is starting in " + + howManyMinBeforeEventShouldReminderBeSent + " minutes"); + String people = ""; + for (int i = 0; i < event.getPeople().size(); i++) { + people += event.getPeople().get(i).getUser().getMentionTag() + "\n"; + } + if (people.equals("")) { + people = "none"; + } + discord.getChannel().sendMessage("People Participating: \n" + people); + } + } + + public static boolean isANumber(String str) { + try { + Integer.parseInt(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + public void sendDm(String userId, String message, MessageCreateEvent discord) { + discord.getApi().getUserById(userId).thenAccept(user -> user.sendMessage(message)); + } + + public void createTimeStamp() { + //System.out.println(timeZones.getCurrentTime(true)); + long currentTime = Instant.parse(timeZones.getCurrentTimeForStamp()).getEpochSecond(); + // Format for Discord timestamp + String discordTimestamp = ""; // 'f' is the format for date and time + } + + public void setup(MessageCreateEvent discord) { + //System.out.println("setup run from method"); + long serverId = discord.getMessage().getServer().get().getId(); + if (users.size() <= 0) { + api.getServerById(serverId).ifPresent(server -> { + //System.out.println("memeber count = " + server.getMemberCount()); + for (int i = 0; i < server.getMemberCount(); i++) { + //System.out.println(server.getMembers().toArray()[i]); + String userInfo = server.getMembers().toArray()[i].toString(); + String userId = userInfo.substring(userInfo.indexOf("id") + 4, userInfo.indexOf(',')); + Person p = null; + try { + p = new Person(api.getUserById(userId).get()); + p.setNickname(api.getUserById(userId).get().getNickname(server) + ""); + p.setUsername(api.getUserById(userId).get().getName() + ""); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + users.add(p); + } + + }); + //System.out.println("users in list"); + } + } + +} \ No newline at end of file diff --git a/src/main/java/org/jointheleague/features/whale/SerpAPI.java b/src/main/java/org/jointheleague/features/whale/SerpAPI.java new file mode 100644 index 00000000..59aca58c --- /dev/null +++ b/src/main/java/org/jointheleague/features/whale/SerpAPI.java @@ -0,0 +1,76 @@ +package org.jointheleague.features.whale; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +public class SerpAPI { + private static final String baseUrl = "https://serpapi.com/search.json?engine=google&q=%searchhere%&location=United+States&google_domain=google.com&gl=us&hl=en&tbm=isch&api_key=5d839296455a3e7b9dcc3d060fb7ad2584f9dc2eb413c98089ce0a51d756bb25"; + private WebClient webClient; + + public SerpAPI() { + this.webClient = WebClient.builder().defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .build(); + } + + public static void main(String[] args) { + SerpAPI api = new SerpAPI(); + //api.getImage("valorant"); + } + + public String getImage(String q) { + String url = baseUrl.replace("%searchhere%", q); + + // Make the request and retrieve the response as an ImageSearchResult +// Mono ISRMono = webClient.get() +// .uri(url) +// .retrieve() +// .bodyToMono(ImageSearchResult.class); +// +// // Block and get the response +// ImageSearchResult response = ISRMono.block(); +// +// if (response != null && response.getImagesResults() != null && !response.getImagesResults().isEmpty()) { +// String imageURL = response.getImagesResults().get(1).getOriginal(); +// System.out.println(response.getImagesResults().size()); +// System.out.println("URL of 1st image: " + imageURL); +// } else { +// System.out.println("No image results found."); +// } + + // Optionally, you can print the raw JSON response as a string if needed + Mono stringMono = webClient.get().uri(url).retrieve().bodyToMono(String.class); + + String responseS = stringMono.block(); + // System.out.println("Raw JSON response: " + responseS); + String imgUrl = findUrl(responseS); + + while (isImageFormatGood(imgUrl) == false) { + imgUrl = findUrl(responseS.substring(imgUrl.indexOf("original")+8, responseS.length() - 1)); + responseS = responseS.substring(imgUrl.indexOf("original")+8, responseS.length() - 1); + } + System.out.println("filtered image url: " + imgUrl); + return imgUrl.substring(4, imgUrl.length()-2); + } + + boolean isImageFormatGood(String imgUrl) { + if (imgUrl.contains(".png") || imgUrl.contains(".jpeg") || imgUrl.contains(".jpg")) { + return true; + } else { + return false; + } + } + + String findUrl(String responseS) { + int indexOfOrgStr = responseS.indexOf("original"); + int index = indexOfOrgStr + 8; + String imgUrl = ""; + while (responseS.charAt(index) != ',') { + imgUrl = imgUrl + responseS.charAt(index); + index = index + 1; + } + imgUrl = imgUrl.trim(); + return imgUrl; + } +} diff --git a/src/main/java/org/jointheleague/features/whale/Time.java b/src/main/java/org/jointheleague/features/whale/Time.java new file mode 100644 index 00000000..7b1acd02 --- /dev/null +++ b/src/main/java/org/jointheleague/features/whale/Time.java @@ -0,0 +1,67 @@ +package org.jointheleague.features.whale; + +public class Time { + private String hour; + private String min; + private Boolean isPm; + private String timeZone; + + public String getTimeZone() { + return timeZone; + } + + public void setTimeZone(String timeZone) { + this.timeZone = timeZone; + } + + Time(String hour, String min) { + this.hour = hour; + this.min = min; + isPm = true; + } + + public String getHour() { + return hour; + } + + public String get24Hour() { + if (isPm == true) { + String time = (Integer.parseInt(hour) + 12) + ""; + if (time.length() == 1) { + time = "0" + time; + } + return time; + } else { + return hour; + } + } + + public void setHour(String hour) { + this.hour = hour; + } + + public String getMin() { + return min; + } + + public void setMin(String min) { + this.min = min; + } + + public Boolean getIsPm() { + return isPm; + } + + public void setIsPm(Boolean isPm) { + this.isPm = isPm; + } + + public String getTimeAsString() { + if (isPm) { + return hour + ":" + min + "pm"; + } else { + return hour + ":" + min + "am"; + } + } + +} diff --git a/src/main/java/org/jointheleague/features/whale/Timezones.java b/src/main/java/org/jointheleague/features/whale/Timezones.java new file mode 100644 index 00000000..6789a9ce --- /dev/null +++ b/src/main/java/org/jointheleague/features/whale/Timezones.java @@ -0,0 +1,83 @@ +package org.jointheleague.features.whale; + +import java.nio.file.spi.FileSystemProvider; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class Timezones { + Map usTimezoneMap; + + public Timezones() { + initializeTimezoneMap(); + displayCurrentTime("America/Los_Angeles"); + } + + private void initializeTimezoneMap() { + usTimezoneMap = new HashMap<>(); + // US Timezones relative to Pacific Time (PT) + usTimezoneMap.put("PT", 0.0); + usTimezoneMap.put("MT", +1.0); + usTimezoneMap.put("CT", +2.0); + usTimezoneMap.put("ET", +3.0); + } + + public void addTimezone(String abbreviation, Double differenceFromPT) { + usTimezoneMap.put(abbreviation.toUpperCase(), differenceFromPT); + } + + public String[] getTimezones() { + Object[] zones = usTimezoneMap.keySet().toArray(); + String[] zonesStrArr = new String[zones.length]; + for (int i = 0; i < usTimezoneMap.size(); i++) { + zonesStrArr[i] = zones[i] + ""; + } + return zonesStrArr; + } + + public void displayCurrentTime(String timezoneId) { + LocalDateTime currentTime = LocalDateTime.now(ZoneId.of(timezoneId)); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm d/M/YY"); + String formattedTime = currentTime.format(formatter); + System.out.println("Current time in " + timezoneId + ": " + formattedTime); + + } + + public String getCurrentTime(boolean getAMPM) { + LocalDateTime currentTime = LocalDateTime.now(ZoneId.of("America/Los_Angeles")); + DateTimeFormatter formatter; + if (getAMPM) { + formatter = DateTimeFormatter.ofPattern("hh:mm:a"); + } else { + formatter = DateTimeFormatter.ofPattern("HH:mm"); + } + String formattedTime = currentTime.format(formatter); + return formattedTime; + } + public String getCurrentTimeForStamp() { + LocalDateTime currentTime = LocalDateTime.now(ZoneId.of("America/Los_Angeles")); + DateTimeFormatter formatter; + formatter = DateTimeFormatter.ISO_INSTANT; + String formattedTime = currentTime.format(formatter); + formattedTime = ""; + return formattedTime; + } + public String getTimeForStamp(Date d) { + Instant i = d.toInstant(); + String formattedTime; + formattedTime = ""; + return formattedTime; + } + + public String getCurrentDate() { + LocalDateTime currentTime = LocalDateTime.now(ZoneId.of("America/Los_Angeles")); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/YY"); + String formattedTime = currentTime.format(formatter); + return formattedTime; + } +} diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 00000000..9d25ca83 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,15 @@ + diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml deleted file mode 100644 index bbc1ec3c..00000000 --- a/src/main/resources/logback.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/test/java/org/jointheleague/features/whale/SchedulingBotTest.java b/src/test/java/org/jointheleague/features/whale/SchedulingBotTest.java new file mode 100644 index 00000000..f197ffca --- /dev/null +++ b/src/test/java/org/jointheleague/features/whale/SchedulingBotTest.java @@ -0,0 +1,404 @@ +package org.jointheleague.features.whale; + +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.Message; +import org.javacord.api.entity.message.MessageAuthor; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.permission.Role; +import org.javacord.api.entity.server.Server; +import org.javacord.api.entity.user.User; +import org.javacord.api.event.message.MessageCreateEvent; +import org.jointheleague.features.abstract_classes.Feature; +import org.jointheleague.features.help_embed.plain_old_java_objects.help_embed.HelpEmbed; +import org.jointheleague.features.templates.FeatureTemplate; +import org.jointheleague.features.whale.Schedule; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.never; + +class SchedulingBotTest { + + @Mock + DiscordApi api; + @Mock + User user; + @Mock + Message msg; + @Mock + MessageAuthor author; + @Mock + Optional Oserver; + @Mock + Server server; + @Mock + ApiGetter get; + @Mock + List roles; + @Mock + Role role; + @Mock + ArrayList printedUsersMock; + @Mock + Person person; + @Mock + CompletableFuture Cuser; + + private Schedule schedule = new Schedule("general", get); + + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + private final PrintStream originalOut = System.out; + + + @Mock + private MessageCreateEvent messageCreateEvent; + + @Mock + private TextChannel textChannel; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + //System.setOut(new PrintStream(outContent)); + when(messageCreateEvent.getChannel()).thenReturn((textChannel)); + when(get.getApi()).thenReturn(api); + when(api.getYourself()).thenReturn(user); + when(user.getName()).thenReturn("Whale's Bot"); + schedule = new Schedule("general", get); + + + } + + @AfterEach + public void itShouldNotPrintToSystemOut() { + String expected = ""; + String actual = outContent.toString(); + + //assertEquals(expected, actual); + System.setOut(originalOut); + } + + @Test + void itShouldAddEvents() { + when(messageCreateEvent.getMessageContent()).thenReturn("!addEvent valorant 9:30pm pt tmr"); + + // When + schedule.handle(messageCreateEvent); + Date d = new Date(); + String day = (d.getDate()+1)+""; + String month = (d.getMonth()+1)+""; + String year = (d.getYear()+"").substring(1,3); + System.out.println(day + " " + month + " " + year); + // Then + verify(textChannel, times(1)).sendMessage("The Event recived was Name = |valorant| Time = |9:30pm| Zone = |PT| |Date = |"+month+"/"+day+"/"+year+"| |Tag = |null|"); + } + @Test + void itShouldRemoveEvents() { + when(messageCreateEvent.getMessageContent()).thenReturn("!addEvent valorant 9:30pm pt tmr"); + schedule.handle(messageCreateEvent); + when(messageCreateEvent.getMessageContent()).thenReturn("!removeEvent"); + schedule.handle(messageCreateEvent); + when(messageCreateEvent.getMessageContent()).thenReturn("1"); + schedule.handle(messageCreateEvent); + // When + + + // Then + verify(textChannel, times(1)).sendMessage("Event Removed"); + } + @Test + void itShouldEditEvents() { + when(messageCreateEvent.getMessageContent()).thenReturn("!addEvent valorant 9:30pm pt tmr"); + schedule.handle(messageCreateEvent); + + + when(messageCreateEvent.getMessage()).thenReturn(msg); + when(msg.getAuthor()).thenReturn(author); + when(author.isBotUser()).thenReturn(false); + + when(messageCreateEvent.getMessageContent()).thenReturn("!editEvent"); + schedule.handle(messageCreateEvent); + + + + when(messageCreateEvent.getMessageContent()).thenReturn("1"); + schedule.handle(messageCreateEvent); + + //schedule.areWeEditing = true; + when(messageCreateEvent.getMessageContent()).thenReturn("1"); + schedule.handle(messageCreateEvent); + + when(messageCreateEvent.getMessageContent()).thenReturn("Minecraft"); + //schedule.setName = true; + schedule.handle(messageCreateEvent); + // When + + // Then + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(String.class); + verify(textChannel, times(6)).sendMessage(messageCaptor.capture()); + List messages = messageCaptor.getAllValues(); + assertTrue(messages.contains("Name changed to Minecraft")); + + } + @Test + void itShouldCreateTags() { + when(messageCreateEvent.getMessageContent()).thenReturn("Whale's Bot has connected"); + schedule.handle(messageCreateEvent); + + when(messageCreateEvent.getMessage()).thenReturn(msg); + when(msg.getAuthor()).thenReturn(author); + when(author.isBotUser()).thenReturn(false); + + when(msg.getServer()).thenReturn(Oserver); + when(Oserver.get()).thenReturn(server); + long ID = 1240487344063385702L; + when(server.getId()).thenReturn(ID); + + + when(api.getServerById(anyLong())).thenReturn(Oserver); + when(Oserver.get()).thenReturn(server); + when(Oserver.isPresent()).thenReturn(true); + + when(server.getRoles()).thenReturn(roles); + when(roles.get(anyInt())).thenReturn(role); + when(role.getName()).thenReturn("everyone"); + + +// schedule.printedUsers = printedUsersMock; +// when(printedUsersMock.get(anyInt())).thenReturn(person); +// when(person.getNickname()).thenReturn("Bob"); + Person p = new Person(user); + ArrayList users = new ArrayList(); + users.add(p); + + when(api.getUserById(anyLong())).thenReturn(Cuser); + try { + when(Cuser.get()).thenReturn(user); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + schedule.printedUsers = users; + schedule.users = users; + when(messageCreateEvent.getMessageContent()).thenReturn("!tags"); + schedule.handle(messageCreateEvent); + + + when(messageCreateEvent.getMessageContent()).thenReturn("1"); + schedule.handle(messageCreateEvent); + + //schedule.areWeEditing = true; + when(messageCreateEvent.getMessageContent()).thenReturn("gamer"); + schedule.handle(messageCreateEvent); + + when(messageCreateEvent.getMessageContent()).thenReturn("end tags"); + schedule.handle(messageCreateEvent); + when(messageCreateEvent.getMessageContent()).thenReturn("end tags"); + schedule.handle(messageCreateEvent); + // When + + // Then + + when(messageCreateEvent.getChannel()).thenReturn(textChannel); + verify(messageCreateEvent, atLeastOnce()).getChannel(); + + // Capture messages sent to the text channel + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(String.class); + verify(textChannel, atLeastOnce()).sendMessage(messageCaptor.capture()); + + // Get all captured messages + List messages = messageCaptor.getAllValues(); + System.out.println("Messages.size = " + messages.size()); + for (int i = 0; i < messages.size(); i++) { + System.out.println("Message " + i + ": " + messages.get(i)); + } + // Check if the specific message is present + assertTrue(messages.contains("Stopped Modifying Tags"), "Expected message was not sent."); + + } + @Test + void itShouldPrintSchedule() { + when(messageCreateEvent.getMessageContent()).thenReturn("!addEvent valorant 9:30pm pt tmr"); + schedule.handle(messageCreateEvent); + + + when(messageCreateEvent.getMessage()).thenReturn(msg); + when(msg.getAuthor()).thenReturn(author); + when(author.isBotUser()).thenReturn(false); + + when(messageCreateEvent.getMessageContent()).thenReturn("!schedule"); + schedule.handle(messageCreateEvent); + + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(BetterEmbedBuilder[].class); + verify(textChannel, atLeastOnce()).sendMessage(messageCaptor.capture()); + List messages = messageCaptor.getAllValues(); + System.err.println("Messages size = " + messages.size()); + for (int i = 0 ; i < messages.size(); i++) { + System.err.println(messages.get(i)); + } + BetterEmbedBuilder emb = new BetterEmbedBuilder(); + emb = schedule.embedCreator(schedule.eventList.get(0)); + System.err.println("Messages Title: " + messages.get(0)[0].title); + System.err.println("Wanted Title: " + emb.title); + assertTrue(messages.get(0)[0].title.equals(emb.title)); + } + + @Test + void itShouldStartEvent() { + when(messageCreateEvent.getMessageContent()).thenReturn("!addEvent valorant 9:30pm pt tmr"); + schedule.handle(messageCreateEvent); + + when(messageCreateEvent.getMessage()).thenReturn(msg); + when(msg.getAuthor()).thenReturn(author); + when(author.isBotUser()).thenReturn(false); + + when(messageCreateEvent.getMessageContent()).thenReturn("!startEvent"); + schedule.handle(messageCreateEvent); + + when(messageCreateEvent.getMessageContent()).thenReturn("start"); + schedule.handle(messageCreateEvent); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(String.class); + verify(textChannel, atLeastOnce()).sendMessage(messageCaptor.capture()); + + // Get all captured messages + List messages = messageCaptor.getAllValues(); + System.out.println("Messages.size = " + messages.size()); + for (int i = 0; i < messages.size(); i++) { + System.out.println("Message " + i + ": " + messages.get(i)); + } + // Check if the specific message is present + assertTrue(messages.contains("Event **valorant** started"), "Expected message was not sent."); + } + + @Test + void itShouldAdjustTimeZoneSettings() { + when(messageCreateEvent.getMessageContent()).thenReturn("!addTimeZone IST +12:30"); + schedule.handle(messageCreateEvent); + + when(messageCreateEvent.getMessage()).thenReturn(msg); + when(msg.getAuthor()).thenReturn(author); + when(author.isBotUser()).thenReturn(false); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(String.class); + verify(textChannel, atLeastOnce()).sendMessage(messageCaptor.capture()); + List messages = messageCaptor.getAllValues(); + System.out.println("Messages.size = " + messages.size()); + for (int i = 0; i < messages.size(); i++) { + System.out.println("Message " + i + ": " + messages.get(i)); + } + // Check if the specific message is present + assertTrue(messages.contains("Timezone IST with a 12.5 hour difference to PT"), "Expected message was not sent."); + } + + @Test + void itShouldAdjustReminderSettings() { + when(messageCreateEvent.getMessageContent()).thenReturn("!setReminder 10"); + schedule.handle(messageCreateEvent); + + when(messageCreateEvent.getMessage()).thenReturn(msg); + when(msg.getAuthor()).thenReturn(author); + when(author.isBotUser()).thenReturn(false); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(String.class); + verify(textChannel, atLeastOnce()).sendMessage(messageCaptor.capture()); + List messages = messageCaptor.getAllValues(); + System.out.println("Messages.size = " + messages.size()); + for (int i = 0; i < messages.size(); i++) { + System.out.println("Message " + i + ": " + messages.get(i)); + } + // Check if the specific message is present + assertTrue(messages.contains("Reminder changed to 10 mins"), "Expected message was not sent."); + } + + @Test + void itShouldHaveACommand() { + // Given + + // When + String command = schedule.add; + + // Then + assertNotEquals("", command); + assertNotEquals("!", command); + assertEquals('!', command.charAt(0)); + assertNotNull(command); + } + + @Test + void itShouldHandleMessagesWithCommand() { + // Given + HelpEmbed helpEmbed = new HelpEmbed(schedule.helpEmbed.getTitle(), schedule.helpEmbed.getDescription()); + when(messageCreateEvent.getMessageContent()).thenReturn("!example"); + + // When + schedule.handle(messageCreateEvent); + + // Then + verify(textChannel, times(1)).sendMessage(anyString()); + } + + @Test + void itShouldNotHandleMessagesWithoutCommand() { + // Given + String command = "hi"; + when(messageCreateEvent.getMessageContent()).thenReturn(command); + + // When + schedule.handle(messageCreateEvent); + + // Then + verify(textChannel, never()).sendMessage(""); + } + + @Test + void itShouldHaveAHelpEmbed() { + // Given + + // When + HelpEmbed actualHelpEmbed = schedule.getHelpEmbed(); + + // Then + assertNotNull(actualHelpEmbed); + } + + @Test + void itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed() { + // Given + + // When + String helpEmbedTitle = schedule.getHelpEmbed().getDescription(); + helpEmbedTitle = helpEmbedTitle.substring(0, schedule.add.length()).trim().toLowerCase(); + String command = schedule.add; + + // Then + assertEquals(command, helpEmbedTitle); + } + +} \ No newline at end of file