diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 6ad0035..0034945 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -44,11 +44,6 @@ jobs: CHATGPT_API_KEY: ${{ secrets.CHATGPT_API_KEY }} OWM_API_KEY: ${{ secrets.OWM_API_KEY }} PINBOARD_API_TOKEN: ${{ secrets.PINBOARD_API_TOKEN }} - TWITTER_CONSUMERKEY: ${{ secrets.TWITTER_CONSUMERKEY }} - TWITTER_CONSUMERSECRET: ${{ secrets.TWITTER_CONSUMERSECRET }} - TWITTER_HANDLE: ${{ secrets.TWITTER_HANDLE }} - TWITTER_TOKEN: ${{ secrets.TWITTER_TOKEN }} - TWITTER_TOKENSECRET: ${{ secrets.TWITTER_TOKENSECRET }} MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }} MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 1bec35e..76b5425 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -3,6 +3,281 @@ + + diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index a55e7a1..6e6eec1 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 0fc3113..217e5c5 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/build.gradle b/build.gradle index 55c1a38..6a131ab 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,16 @@ +import io.gitlab.arturbosch.detekt.Detekt +import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask + plugins { id 'application' - id 'com.github.ben-manes.versions' version '0.45.0' + id 'com.github.ben-manes.versions' version '0.46.0' id 'idea' id 'io.gitlab.arturbosch.detekt' version '1.22.0' id 'java' id 'net.thauvin.erik.gradle.semver' version '1.0.4' - id 'org.jetbrains.kotlin.jvm' version '1.8.10' - id 'org.jetbrains.kotlin.kapt' version '1.8.10' - id 'org.jetbrains.kotlinx.kover' version '0.6.1' + id 'org.jetbrains.kotlin.jvm' version '1.8.21' + id 'org.jetbrains.kotlin.kapt' version '1.8.21' + id 'org.jetbrains.kotlinx.kover' version '0.7.0' id 'org.sonarqube' version '4.0.0.2929' id 'pmd' } @@ -29,8 +32,8 @@ def isNonStable = { String version -> mainClassName = packageName + '.Mobibot' ext.versions = [ - log4j: '2.19.0', - pmd : '6.54.0', + log4j: '2.20.0', + pmd : '6.55.0', ] repositories { @@ -61,22 +64,21 @@ dependencies { // Kotlin implementation platform('org.jetbrains.kotlin:kotlin-bom') implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1' implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.5' // Logging - implementation 'org.slf4j:slf4j-api:2.0.6' + implementation 'org.slf4j:slf4j-api:2.0.7' implementation "org.apache.logging.log4j:log4j-api:$versions.log4j" implementation "org.apache.logging.log4j:log4j-core:$versions.log4j" implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$versions.log4j" - implementation 'com.rometools:rome:1.19.0' - implementation 'com.squareup.okhttp3:okhttp:4.10.0' + implementation 'com.rometools:rome:2.1.0' + implementation 'com.squareup.okhttp3:okhttp:4.11.0' implementation 'net.aksingh:owm-japis:2.5.3.0' implementation 'net.objecthunter:exp4j:0.4.8' - implementation 'org.json:json:20220924' - implementation 'org.jsoup:jsoup:1.15.4' - implementation 'org.twitter4j:twitter4j-core:4.1.2' + implementation 'org.json:json:20230227' + implementation 'org.jsoup:jsoup:1.16.1' // Thauvin implementation 'net.thauvin.erik:cryptoprice:1.0.0' @@ -84,10 +86,10 @@ dependencies { implementation 'net.thauvin.erik:pinboard-poster:1.0.3' implementation 'net.thauvin.erik:urlencoder:1.3.0' - testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.25' + testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.26.1' // testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0' // testImplementation "org.mockito:mockito-core:4.0.0" - testImplementation 'org.testng:testng:7.7.1' + testImplementation 'org.testng:testng:7.8.0' } test { @@ -114,6 +116,12 @@ java { targetCompatibility = JavaVersion.VERSION_11 } +kotlin { + jvmToolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } +} + kapt { includeCompileClasspath = false arguments { @@ -121,15 +129,10 @@ kapt { } } -tasks.withType(JavaCompile) { +tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' } -tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { - kotlinOptions { - jvmTarget = java.targetCompatibility.toString() - } -} compileJava { dependsOn 'incrementBuildMeta' @@ -155,15 +158,14 @@ detekt { baseline = file("${projectDir}/config/detekt/baseline.xml") } -tasks.withType(io.gitlab.arturbosch.detekt.Detekt).configureEach { +tasks.withType(Detekt).configureEach { jvmTarget = java.targetCompatibility.toString() } -tasks.withType(io.gitlab.arturbosch.detekt.DetektCreateBaselineTask).configureEach { +tasks.withType(DetektCreateBaselineTask).configureEach { jvmTarget = java.targetCompatibility.toString() } - jar { manifest.attributes('Main-Class': mainClassName, 'Class-Path': '. ./lib/' + configurations.runtimeClasspath.collect { it.getName() }.join(' ./lib/')) @@ -204,19 +206,19 @@ tasks.sonar { dependsOn 'koverReport' } -task copyToDeploy(type: Copy) { +tasks.register('copyToDeploy', Copy) { from('properties', jar) into deployDir } -task copyToDeployLib(type: Copy) { +tasks.register('copyToDeployLib', Copy) { from(configurations.runtimeClasspath) { exclude 'annotations-*.jar' } into(deployDir + '/lib') } -task deploy { +tasks.register('deploy') { description = "Copies all needed files to the ${deployDir} directory." group = 'Publishing' dependsOn(assemble, jar) @@ -228,7 +230,7 @@ task deploy { mustRunAfter(clean) } -task release { +tasks.register('release') { group = 'Publishing' description = 'Releases new version.' dependsOn(clean, check, deploy) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index da082db..db7e772 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -10,7 +10,6 @@ LongMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> LongParameterList:Comment.kt$Comment$( channel: String, cmd: String, entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent ) LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList<EntryComment> = mutableListOf(), // Tags/categories val tags: MutableList<SyndCategory> = mutableListOf(), // Channel var channel: String, // Creation date var date: Date = Calendar.getInstance().time, // Link's URL var link: String, // Author's login var login: String = "", // Author's nickname var nick: String, // Link's title var title: String ) - LongParameterList:Twitter.kt$Twitter.Companion$( consumerKey: String?, consumerSecret: String?, token: String?, tokenSecret: String?, handle: String?, message: String, isDm: Boolean ) MagicNumber:ChatGpt.kt$ChatGpt$400 MagicNumber:ChatGpt.kt$ChatGpt.Companion$200 MagicNumber:ChatGpt.kt$ChatGpt.Companion$429 @@ -33,7 +32,6 @@ MagicNumber:StockQuote.kt$StockQuote.Companion$10 MagicNumber:Tell.kt$Tell$50 MagicNumber:Tell.kt$Tell$7 - MagicNumber:TwitterOAuth.kt$TwitterOAuth$401 MagicNumber:Users.kt$Users$8 MagicNumber:Utils.kt$Utils$200 MagicNumber:Utils.kt$Utils$399 @@ -47,7 +45,6 @@ MagicNumber:WorldTime.kt$WorldTime.Companion$3600 MagicNumber:WorldTime.kt$WorldTime.Companion$60 MagicNumber:WorldTime.kt$WorldTime.Companion$86.4 - MaxLineLength:TwitterOAuth.kt$TwitterOAuth$* NestedBlockDepth:Addons.kt$Addons$fun add(command: AbstractCommand): Boolean NestedBlockDepth:Addons.kt$Addons$fun add(module: AbstractModule): Boolean NestedBlockDepth:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String @@ -65,13 +62,10 @@ NestedBlockDepth:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent) - NestedBlockDepth:TwitterOAuth.kt$TwitterOAuth$@JvmStatic fun main(args: Array<String>) NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveSerialData(file: String, data: Any, logger: Logger, description: String) NestedBlockDepth:Weather2.kt$Weather2$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> - PrintStackTrace:TwitterOAuth.kt$TwitterOAuth$ioe - PrintStackTrace:TwitterOAuth.kt$TwitterOAuth$te ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException @@ -91,5 +85,6 @@ TooManyFunctions:EntryLink.kt$EntryLink : Serializable TooManyFunctions:Mobibot.kt$Mobibot : ListenerAdapter TooManyFunctions:Tell.kt$Tell : AbstractCommand + WildcardImport:FeedReaderTest.kt$import assertk.assertions.* diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cb..c1962a7 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 42defcc..37aef8d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68..aeb74cb 100755 --- a/gradlew +++ b/gradlew @@ -85,9 +85,6 @@ done APP_BASE_NAME=${0##*/} APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -144,7 +141,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +149,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,6 +194,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/properties/mobibot.properties b/properties/mobibot.properties index 0f97f3c..fa8ce50 100644 --- a/properties/mobibot.properties +++ b/properties/mobibot.properties @@ -25,28 +25,13 @@ tell-max-days=5 tell-max-size=50 #disabled-commands=die, ignore -disabled-modules=twitter +disabled-modules=mastodon # # API Token for: https://pinboard.in/settings/password # #pinboard-api-token=user\:TOKEN -# -# Configure app at: https://developer.twitter.com/ -# and then: java -cp mobibot.jar net.thauvin.erik.mobibot.TwitterOAuth -# -#twitter-consumerKey= -#twitter-consumerSecret= -#twitter-token= -#twitter-tokenSecret= - -# Twitter handle to receive channel join/leave notifications -#twitter-handle= - -# Automatically post links to Mastodon -#twitter-auto-post=true - # # Create a Mastodon application access token at: https//SERVER_INSTANCE/settings/applications # Make sure the 'write:statuses' scope is enabled. diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt index 6766f62..98ef74a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt @@ -59,6 +59,12 @@ object Constants { */ const val CLI_CMD = "java -jar ${ReleaseInfo.PROJECT}.jar" + /** + * User-Agent + */ + const val USER_AGENT = + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" + /** * The help command. */ diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt index f56af2e..d82f011 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt @@ -74,7 +74,7 @@ class FeedReader(private val url: String, val event: GenericMessageEvent) : Runn fun readFeed(url: String, maxItems: Int = 5): List { val messages = mutableListOf() val input = SyndFeedInput() - XmlReader(URL(url)).use { reader -> + XmlReader(URL(url).openStream()).use { reader -> val feed = input.build(reader) val items = feed.entries if (items.isEmpty()) { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index 2dff959..dabb7c8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -78,7 +78,6 @@ import net.thauvin.erik.mobibot.modules.Mastodon import net.thauvin.erik.mobibot.modules.Ping import net.thauvin.erik.mobibot.modules.RockPaperScissors import net.thauvin.erik.mobibot.modules.StockQuote -import net.thauvin.erik.mobibot.modules.Twitter import net.thauvin.erik.mobibot.modules.War import net.thauvin.erik.mobibot.modules.Weather2 import net.thauvin.erik.mobibot.modules.WolframAlpha @@ -438,7 +437,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro addons.add(View()) // Load social modules - LinksManager.socialManager.add(addons, Twitter(), Mastodon()) + LinksManager.socialManager.add(addons, Mastodon()) // Load the modules addons.add(Calc()) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt b/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt deleted file mode 100644 index ab078db..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt +++ /dev/null @@ -1,118 +0,0 @@ -/* - * TwitterOAuth.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import twitter4j.AccessToken -import twitter4j.OAuthAuthorization -import twitter4j.TwitterException -import java.io.BufferedReader -import java.io.IOException -import java.io.InputStreamReader -import kotlin.system.exitProcess - - -/** - * The `TwitterOAuth` class. - * - * Go to [https://developer.twitter.com/en/apps](https://developer.twitter.com/en/apps) to register your bot. - * - * Then execute: - * - * `java -cp mobibot.jar net.thauvin.erik.mobibot.TwitterOAuth ` - * - * and follow the prompts/instructions. - * - * @author [Erik C. Thauvin](https://erik.thauvin.net) - * @author [Yusuke Yamamoto](https://github.com/Twitter4J/Twitter4J/blob/main/twitter4j-examples/src/main/java/examples/oauth/GetAccessToken.java) - */ -object TwitterOAuth { - /** - * Twitter OAuth Client Registration. - * - * @param args The consumerKey and consumerSecret should be passed as arguments. - */ - @JvmStatic - fun main(args: Array) { - if (args.size == 2) { - try { - val oAuthAuthorization = OAuthAuthorization.getInstance(args[0], args[1]) - val requestToken = oAuthAuthorization.oAuthRequestToken - var accessToken: AccessToken? = null - val br = BufferedReader(InputStreamReader(System.`in`)) - while (null == accessToken) { - print( - """ - Open the following URL and grant access to your account: - - ${requestToken.authorizationURL} - - Enter the PIN (if available) or just hit enter. [PIN]: """.trimIndent() - ) - val pin = br.readLine() - try { - accessToken = if (!pin.isNullOrEmpty()) { - oAuthAuthorization.getOAuthAccessToken(requestToken, pin) - } else { - oAuthAuthorization.getOAuthAccessToken(requestToken) - } - } catch (te: TwitterException) { - if (401 == te.statusCode) { - println("Unable to get the access token.") - } else { - te.printStackTrace() - } - } - } - println( - """ - Please add the following to the bot's property file: - - twitter-consumerKey=${args[0]} - twitter-consumerSecret=${args[1]} - twitter-token=${accessToken.token} - twitter-tokenSecret=${accessToken.tokenSecret} - """.trimIndent() - ) - } catch (te: TwitterException) { - te.printStackTrace() - println("Failed to get accessToken: " + te.message) - exitProcess(-1) - } catch (ioe: IOException) { - ioe.printStackTrace() - println("Failed to read the system input.") - exitProcess(-1) - } - } else { - println("Usage: ${TwitterOAuth::class.java.name} ") - } - exitProcess(0) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index 8847bef..3647b31 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -31,6 +31,7 @@ package net.thauvin.erik.mobibot.modules +import net.thauvin.erik.mobibot.Constants import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils.sendMessage import org.apache.commons.text.WordUtils @@ -106,6 +107,7 @@ class ChatGpt : AbstractModule() { .uri(URI.create(API_URL)) .header("Content-Type", "application/json") .header("Authorization", "Bearer $apiKey") + .header("User-Agent", Constants.USER_AGENT) .POST( HttpRequest.BodyPublishers.ofString( """{ @@ -136,8 +138,10 @@ class ChatGpt : AbstractModule() { } } else { if (response.statusCode() == 429) { - throw ModuleException("$CHATGPT_CMD($query): Rate limit reached", - "Rate limit reached. Please try again later.") + throw ModuleException( + "$CHATGPT_CMD($query): Rate limit reached", + "Rate limit reached. Please try again later." + ) } else { throw IOException("HTTP Status Code: " + response.statusCode()) } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt deleted file mode 100644 index d4c02e1..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Twitter.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.social.SocialModule -import twitter4j.TwitterException - -/** - * The Twitter module. - */ -class Twitter : SocialModule() { - override val name = "Twitter" - - override val handle: String? - get() = properties[HANDLE_PROP] - - override val isAutoPost: Boolean - get() = isEnabled && properties[AUTO_POST_PROP].toBoolean() - - override val isValidProperties: Boolean - get() = !(properties[CONSUMER_KEY_PROP].isNullOrBlank() || properties[CONSUMER_SECRET_PROP].isNullOrBlank() - || properties[TOKEN_PROP].isNullOrBlank() || properties[TOKEN_SECRET_PROP].isNullOrBlank()) - - /** - * Formats the entry for posting. - */ - override fun formatEntry(entry: EntryLink): String { - return "${entry.title} ${entry.link} via ${entry.nick} on ${entry.channel}" - } - - /** - * Posts on Twitter. - */ - @Throws(ModuleException::class) - override fun post(message: String, isDm: Boolean): String { - return tweet( - consumerKey = properties[CONSUMER_KEY_PROP], - consumerSecret = properties[CONSUMER_SECRET_PROP], - token = properties[TOKEN_PROP], - tokenSecret = properties[TOKEN_SECRET_PROP], - handle = handle, - message = message, - isDm = isDm - ) - } - - companion object { - // Property keys - const val AUTO_POST_PROP = "twitter-auto-post" - const val CONSUMER_KEY_PROP = "twitter-consumerKey" - const val CONSUMER_SECRET_PROP = "twitter-consumerSecret" - const val HANDLE_PROP = "twitter-handle" - const val TOKEN_PROP = "twitter-token" - const val TOKEN_SECRET_PROP = "twitter-tokenSecret" - - // Twitter commands - private const val TWITTER_CMD = "twitter" - private const val TWEET_CMD = "tweet" - - /** - * Post on Twitter. - */ - @JvmStatic - @Throws(ModuleException::class) - fun tweet( - consumerKey: String?, - consumerSecret: String?, - token: String?, - tokenSecret: String?, - handle: String?, - message: String, - isDm: Boolean - ): String { - return try { - val twitter = twitter4j.Twitter.newBuilder() - .prettyDebugEnabled(true) - .oAuthConsumer(consumerKey, consumerSecret) - .oAuthAccessToken(token, tokenSecret) - .build() - if (!isDm) { - val status = twitter.v1().tweets().updateStatus(message) - "Your message was posted to https://twitter.com/${ - twitter.v1().users().accountSettings.screenName - }/statuses/${status.id}" - } else { - val dm = twitter.v1().directMessages().sendDirectMessage(handle, message) - dm.text - } - } catch (e: TwitterException) { - throw ModuleException("tweet($message)", "An error has occurred: ${e.message}", e) - } - } - } - - init { - commands.add(TWITTER_CMD) - commands.add(TWEET_CMD) - help.add("To $TWEET_CMD on $name:") - help.add(helpFormat("%c $TWEET_CMD ")) - properties[AUTO_POST_PROP] = "false" - initProperties(CONSUMER_KEY_PROP, CONSUMER_SECRET_PROP, HANDLE_PROP, TOKEN_PROP, TOKEN_SECRET_PROP) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt index 8662392..ebc2aa0 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt @@ -45,7 +45,6 @@ import net.thauvin.erik.mobibot.modules.Dice import net.thauvin.erik.mobibot.modules.Joke import net.thauvin.erik.mobibot.modules.Lookup import net.thauvin.erik.mobibot.modules.RockPaperScissors -import net.thauvin.erik.mobibot.modules.Twitter import net.thauvin.erik.mobibot.modules.War import org.testng.annotations.Test import java.util.Properties @@ -62,7 +61,6 @@ class AddonsTest { // Modules addons.add(Joke()) addons.add(RockPaperScissors()) - addons.add(Twitter()) // no properties, disabled. addons.add(War()) addons.add(Dice()) addons.add(Lookup()) diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt index 0d66a0d..d30977e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt @@ -31,14 +31,9 @@ package net.thauvin.erik.mobibot import assertk.all +import assertk.assertFailure import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.index -import assertk.assertions.isEqualTo -import assertk.assertions.isFailure -import assertk.assertions.isInstanceOf -import assertk.assertions.prop -import assertk.assertions.size +import assertk.assertions.* import com.rometools.rome.io.FeedException import net.thauvin.erik.mobibot.FeedReader.Companion.readFeed import net.thauvin.erik.mobibot.msg.Message @@ -66,13 +61,13 @@ class FeedReaderTest { assertThat(messages, "messages").size().isEqualTo(84) assertThat(messages.last(), "messages.last").prop(Message::msg).contains("techdigest.tv") - assertThat { readFeed("blah") }.isFailure().isInstanceOf(MalformedURLException::class.java) + assertFailure { readFeed("blah") }.isInstanceOf(MalformedURLException::class.java) - assertThat { readFeed("https://www.example.com") }.isFailure().isInstanceOf(FeedException::class.java) + assertFailure { readFeed("https://www.example.com") }.isInstanceOf(FeedException::class.java) - assertThat { readFeed("https://www.thauvin.net/foo") }.isFailure().isInstanceOf(IOException::class.java) + assertFailure { readFeed("https://www.thauvin.net/foo") }.isInstanceOf(IOException::class.java) - assertThat { readFeed("https://www.examplesfoo.com/") }.isFailure() + assertFailure { readFeed("https://www.examplesfoo.com/") } .isInstanceOf(UnknownHostException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt index fb0402e..b3bd248 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt @@ -30,6 +30,7 @@ */ package net.thauvin.erik.mobibot.modules +import assertk.assertFailure import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isFailure @@ -48,6 +49,6 @@ class CalcTest { assertThat(calculate("1 + 1"), "calculate(1+1)").isEqualTo("1+1 = ${2.bold()}") assertThat(calculate("1 -3"), "calculate(1-3)").isEqualTo("1-3 = ${(-2).bold()}") assertThat(calculate("pi+π+e+φ"), "calculate(pi+π+e+φ)").isEqualTo("pi+π+e+φ = ${"10.62".bold()}") - assertThat { calculate("one + one") }.isFailure().isInstanceOf(UnknownFunctionOrVariableException::class.java) + assertFailure { calculate("one + one") }.isInstanceOf(UnknownFunctionOrVariableException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index 5e0e1d2..e4638b9 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -30,6 +30,7 @@ */ package net.thauvin.erik.mobibot.modules +import assertk.assertFailure import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasNoCause @@ -41,8 +42,7 @@ import org.testng.annotations.Test class ChatGptTest : LocalProperties() { @Test(groups = ["modules"]) fun testApiKey() { - assertThat { ChatGpt.chat("1 gallon to liter", "", 0) } - .isFailure() + assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } .isInstanceOf(ModuleException::class.java) .hasNoCause() } @@ -57,8 +57,7 @@ class ChatGptTest : LocalProperties() { ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) ).contains("URLEncoder") - assertThat { ChatGpt.chat("1 liter to gallon", apiKey, 0) } - .isFailure() + assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) } .isInstanceOf(ModuleException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt index c2bb833..175af47 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt @@ -31,6 +31,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all +import assertk.assertFailure import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasMessage @@ -59,14 +60,13 @@ class GoogleSearchTest : LocalProperties() { "searchGoogle(empty)" ).isInstanceOf(ErrorMessage::class.java) - assertThat { searchGoogle("test", "", "apiKey") }.isFailure() + assertFailure { searchGoogle("test", "", "apiKey") } .isInstanceOf(ModuleException::class.java).hasNoCause() - assertThat { searchGoogle("test", "apiKey", "") }.isFailure() + assertFailure { searchGoogle("test", "apiKey", "") } .isInstanceOf(ModuleException::class.java).hasNoCause() - assertThat { searchGoogle("test", "apiKey", "cssKey") } - .isFailure() + assertFailure { searchGoogle("test", "apiKey", "cssKey") } .isInstanceOf(ModuleException::class.java) .hasMessage("API key not valid. Please pass a valid API key.") } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt index d464f03..34f778a 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt @@ -32,7 +32,6 @@ package net.thauvin.erik.mobibot.modules import assertk.assertThat import assertk.assertions.contains -import assertk.assertions.isSuccess import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.modules.Mastodon.Companion.toot import org.testng.annotations.Test @@ -42,7 +41,7 @@ class MastodonTest : LocalProperties() { @Throws(ModuleException::class) fun testToot() { val msg = "Testing Mastodon API from ${getHostName()}" - assertThat { + assertThat( toot( getProperty(Mastodon.ACCESS_TOKEN_PROP), getProperty(Mastodon.INSTANCE_PROP), @@ -50,6 +49,6 @@ class MastodonTest : LocalProperties() { msg, true ) - }.isSuccess().contains(msg) + ).contains(msg) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt index d35a3d3..b4a277e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt @@ -31,6 +31,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all +import assertk.assertFailure import assertk.assertThat import assertk.assertions.hasNoCause import assertk.assertions.index @@ -78,7 +79,7 @@ class StockQuoteTest : LocalProperties() { isInstanceOf(ErrorMessage::class.java) prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) } - assertThat { getQuote("test", "") }.isFailure().isInstanceOf(ModuleException::class.java).hasNoCause() + assertFailure { getQuote("test", "") }.isInstanceOf(ModuleException::class.java).hasNoCause() } catch (e: ModuleException) { // Avoid displaying api keys in CI logs if ("true" == System.getenv("CI")) { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt deleted file mode 100644 index 6e4ab27..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * TwitterTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isSuccess -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.Twitter.Companion.tweet -import org.testng.annotations.Test - -/** - * The `TwitterTest` class. - */ -class TwitterTest : LocalProperties() { - @Test(groups = ["modules", "twitter"]) - @Throws(ModuleException::class) - fun testTweet() { - val msg = "Testing Twitter API from ${getHostName()}" - assertThat { - tweet( - getProperty(Twitter.CONSUMER_KEY_PROP), - getProperty(Twitter.CONSUMER_SECRET_PROP), - getProperty(Twitter.TOKEN_PROP), - getProperty(Twitter.TOKEN_SECRET_PROP), - getProperty(Twitter.HANDLE_PROP), - msg, - true - ) - }.isSuccess().isEqualTo(msg) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt index 4c7f7e6..ca650bb 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt @@ -31,6 +31,7 @@ package net.thauvin.erik.mobibot.modules import assertk.all +import assertk.assertFailure import assertk.assertThat import assertk.assertions.contains import assertk.assertions.endsWith @@ -116,8 +117,8 @@ class Weather2Test : LocalProperties() { } query = "test" - assertThat { getWeather(query, "") }.isFailure().isInstanceOf(ModuleException::class.java).hasNoCause() - assertThat { getWeather(query, null) }.isFailure().isInstanceOf(ModuleException::class.java).hasNoCause() + assertFailure { getWeather(query, "") }.isInstanceOf(ModuleException::class.java).hasNoCause() + assertFailure { getWeather(query, null) }.isInstanceOf(ModuleException::class.java).hasNoCause() messages = getWeather("", "apikey") assertThat(messages, "getWeather(empty)").index(0).prop(Message::isError).isTrue() diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt index 4aaf620..ae1722d 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt @@ -31,10 +31,10 @@ package net.thauvin.erik.mobibot.modules +import assertk.assertFailure import assertk.assertThat import assertk.assertions.contains import assertk.assertions.hasMessage -import assertk.assertions.isFailure import assertk.assertions.isInstanceOf import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize import net.thauvin.erik.mobibot.LocalProperties @@ -44,13 +44,11 @@ import org.testng.annotations.Test class WolframAlphaTest : LocalProperties() { @Test(groups = ["modules"]) fun testAppId() { - assertThat { queryWolfram("1 gallon to liter", appId = "DEMO") } - .isFailure() + assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") } .isInstanceOf(ModuleException::class.java) .hasMessage("Error 1: Invalid appid") - assertThat { queryWolfram("1 gallon to liter", appId = "") } - .isFailure() + assertFailure { queryWolfram("1 gallon to liter", appId = "") } .isInstanceOf(ModuleException::class.java) } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt index f17ed1d..46888e3 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt @@ -30,6 +30,7 @@ */ package net.thauvin.erik.mobibot.modules +import assertk.assertFailure import assertk.assertThat import assertk.assertions.endsWith import assertk.assertions.isSuccess @@ -65,7 +66,7 @@ class WordTimeTest { @Test(groups = ["modules"]) fun testZones() { COUNTRIES_MAP.filter { it.value != BEATS_KEYWORD }.forEach { - assertThat { ZoneId.of(it.value) }.isSuccess() + assertThat(ZoneId.of(it.value)) } } } diff --git a/version.properties b/version.properties index 693db4f..27ca594 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Mon Jan 30 22:08:48 PST 2023 -version.buildmeta=986 +#Sat May 20 23:54:50 PDT 2023 +version.buildmeta=1077 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+986 +version.semver=0.8.0-rc+1077 diff --git a/website/index.html b/website/index.html index 97e337d..1ffaad2 100644 --- a/website/index.html +++ b/website/index.html @@ -46,7 +46,6 @@
  • Pinboard Poster
  • PircBotX
  • Rome
  • -
  • Twitter4J
  • UrlEncoder
  • mobibot was written by