Removed twitter module

This commit is contained in:
Erik C. Thauvin 2023-05-21 00:01:01 -07:00
parent c2c5f8beae
commit 207c1b7e02
29 changed files with 360 additions and 416 deletions

View file

@ -44,11 +44,6 @@ jobs:
CHATGPT_API_KEY: ${{ secrets.CHATGPT_API_KEY }} CHATGPT_API_KEY: ${{ secrets.CHATGPT_API_KEY }}
OWM_API_KEY: ${{ secrets.OWM_API_KEY }} OWM_API_KEY: ${{ secrets.OWM_API_KEY }}
PINBOARD_API_TOKEN: ${{ secrets.PINBOARD_API_TOKEN }} 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_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }}
MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }} MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }}
MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }}

View file

@ -3,6 +3,281 @@
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="IF_BRACE_FORCE" value="1" />
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PUBLIC>true</PUBLIC>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PROTECTED>true</PROTECTED>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PRIVATE>true</PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PUBLIC>true</PUBLIC>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PROTECTED>true</PROTECTED>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PRIVATE>true</PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PUBLIC>true</PUBLIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PROTECTED>true</PROTECTED>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PRIVATE>true</PRIVATE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PUBLIC>true</PUBLIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PROTECTED>true</PROTECTED>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PRIVATE>true</PRIVATE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PRIVATE>false</PRIVATE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<FIELD>true</FIELD>
</match>
</rule>
</section>
<section>
<rule>
<match>
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
</match>
</rule>
</section>
<section>
<rule>
<match>
<CONSTRUCTOR>true</CONSTRUCTOR>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<METHOD>true</METHOD>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<METHOD>true</METHOD>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<ENUM>true</ENUM>
</match>
</rule>
</section>
<section>
<rule>
<match>
<INTERFACE>true</INTERFACE>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<CLASS>true</CLASS>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<CLASS>true</CLASS>
</match>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin"> <codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings> </codeStyleSettings>

View file

@ -1,5 +1,6 @@
<component name="ProjectCodeStyleConfiguration"> <component name="ProjectCodeStyleConfiguration">
<state> <state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" /> <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state> </state>
</component> </component>

2
.idea/kotlinc.xml generated
View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="KotlinJpsPluginSettings"> <component name="KotlinJpsPluginSettings">
<option name="version" value="1.8.10" /> <option name="version" value="1.8.21" />
</component> </component>
</project> </project>

View file

@ -1,13 +1,16 @@
import io.gitlab.arturbosch.detekt.Detekt
import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask
plugins { plugins {
id 'application' 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 'idea'
id 'io.gitlab.arturbosch.detekt' version '1.22.0' id 'io.gitlab.arturbosch.detekt' version '1.22.0'
id 'java' id 'java'
id 'net.thauvin.erik.gradle.semver' version '1.0.4' id 'net.thauvin.erik.gradle.semver' version '1.0.4'
id 'org.jetbrains.kotlin.jvm' version '1.8.10' id 'org.jetbrains.kotlin.jvm' version '1.8.21'
id 'org.jetbrains.kotlin.kapt' version '1.8.10' id 'org.jetbrains.kotlin.kapt' version '1.8.21'
id 'org.jetbrains.kotlinx.kover' version '0.6.1' id 'org.jetbrains.kotlinx.kover' version '0.7.0'
id 'org.sonarqube' version '4.0.0.2929' id 'org.sonarqube' version '4.0.0.2929'
id 'pmd' id 'pmd'
} }
@ -29,8 +32,8 @@ def isNonStable = { String version ->
mainClassName = packageName + '.Mobibot' mainClassName = packageName + '.Mobibot'
ext.versions = [ ext.versions = [
log4j: '2.19.0', log4j: '2.20.0',
pmd : '6.54.0', pmd : '6.55.0',
] ]
repositories { repositories {
@ -61,22 +64,21 @@ dependencies {
// Kotlin // Kotlin
implementation platform('org.jetbrains.kotlin:kotlin-bom') implementation platform('org.jetbrains.kotlin:kotlin-bom')
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' 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' implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.5'
// Logging // 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-api:$versions.log4j"
implementation "org.apache.logging.log4j:log4j-core:$versions.log4j" implementation "org.apache.logging.log4j:log4j-core:$versions.log4j"
implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$versions.log4j" implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$versions.log4j"
implementation 'com.rometools:rome:1.19.0' implementation 'com.rometools:rome:2.1.0'
implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'com.squareup.okhttp3:okhttp:4.11.0'
implementation 'net.aksingh:owm-japis:2.5.3.0' implementation 'net.aksingh:owm-japis:2.5.3.0'
implementation 'net.objecthunter:exp4j:0.4.8' implementation 'net.objecthunter:exp4j:0.4.8'
implementation 'org.json:json:20220924' implementation 'org.json:json:20230227'
implementation 'org.jsoup:jsoup:1.15.4' implementation 'org.jsoup:jsoup:1.16.1'
implementation 'org.twitter4j:twitter4j-core:4.1.2'
// Thauvin // Thauvin
implementation 'net.thauvin.erik:cryptoprice:1.0.0' 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:pinboard-poster:1.0.3'
implementation 'net.thauvin.erik:urlencoder:1.3.0' 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.kotlin:mockito-kotlin:4.0.0'
// testImplementation "org.mockito:mockito-core: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 { test {
@ -114,6 +116,12 @@ java {
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11
} }
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(11))
}
}
kapt { kapt {
includeCompileClasspath = false includeCompileClasspath = false
arguments { arguments {
@ -121,15 +129,10 @@ kapt {
} }
} }
tasks.withType(JavaCompile) { tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' options.encoding = 'UTF-8'
} }
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
jvmTarget = java.targetCompatibility.toString()
}
}
compileJava { compileJava {
dependsOn 'incrementBuildMeta' dependsOn 'incrementBuildMeta'
@ -155,15 +158,14 @@ detekt {
baseline = file("${projectDir}/config/detekt/baseline.xml") baseline = file("${projectDir}/config/detekt/baseline.xml")
} }
tasks.withType(io.gitlab.arturbosch.detekt.Detekt).configureEach { tasks.withType(Detekt).configureEach {
jvmTarget = java.targetCompatibility.toString() jvmTarget = java.targetCompatibility.toString()
} }
tasks.withType(io.gitlab.arturbosch.detekt.DetektCreateBaselineTask).configureEach { tasks.withType(DetektCreateBaselineTask).configureEach {
jvmTarget = java.targetCompatibility.toString() jvmTarget = java.targetCompatibility.toString()
} }
jar { jar {
manifest.attributes('Main-Class': mainClassName, manifest.attributes('Main-Class': mainClassName,
'Class-Path': '. ./lib/' + configurations.runtimeClasspath.collect { it.getName() }.join(' ./lib/')) 'Class-Path': '. ./lib/' + configurations.runtimeClasspath.collect { it.getName() }.join(' ./lib/'))
@ -204,19 +206,19 @@ tasks.sonar {
dependsOn 'koverReport' dependsOn 'koverReport'
} }
task copyToDeploy(type: Copy) { tasks.register('copyToDeploy', Copy) {
from('properties', jar) from('properties', jar)
into deployDir into deployDir
} }
task copyToDeployLib(type: Copy) { tasks.register('copyToDeployLib', Copy) {
from(configurations.runtimeClasspath) { from(configurations.runtimeClasspath) {
exclude 'annotations-*.jar' exclude 'annotations-*.jar'
} }
into(deployDir + '/lib') into(deployDir + '/lib')
} }
task deploy { tasks.register('deploy') {
description = "Copies all needed files to the ${deployDir} directory." description = "Copies all needed files to the ${deployDir} directory."
group = 'Publishing' group = 'Publishing'
dependsOn(assemble, jar) dependsOn(assemble, jar)
@ -228,7 +230,7 @@ task deploy {
mustRunAfter(clean) mustRunAfter(clean)
} }
task release { tasks.register('release') {
group = 'Publishing' group = 'Publishing'
description = 'Releases new version.' description = 'Releases new version.'
dependsOn(clean, check, deploy) dependsOn(clean, check, deploy)

View file

@ -10,7 +10,6 @@
<ID>LongMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message&gt;</ID> <ID>LongMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message&gt;</ID>
<ID>LongParameterList:Comment.kt$Comment$( channel: String, cmd: String, entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent )</ID> <ID>LongParameterList:Comment.kt$Comment$( channel: String, cmd: String, entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent )</ID>
<ID>LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList&lt;EntryComment&gt; = mutableListOf(), // Tags/categories val tags: MutableList&lt;SyndCategory&gt; = 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 )</ID> <ID>LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList&lt;EntryComment&gt; = mutableListOf(), // Tags/categories val tags: MutableList&lt;SyndCategory&gt; = 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 )</ID>
<ID>LongParameterList:Twitter.kt$Twitter.Companion$( consumerKey: String?, consumerSecret: String?, token: String?, tokenSecret: String?, handle: String?, message: String, isDm: Boolean )</ID>
<ID>MagicNumber:ChatGpt.kt$ChatGpt$400</ID> <ID>MagicNumber:ChatGpt.kt$ChatGpt$400</ID>
<ID>MagicNumber:ChatGpt.kt$ChatGpt.Companion$200</ID> <ID>MagicNumber:ChatGpt.kt$ChatGpt.Companion$200</ID>
<ID>MagicNumber:ChatGpt.kt$ChatGpt.Companion$429</ID> <ID>MagicNumber:ChatGpt.kt$ChatGpt.Companion$429</ID>
@ -33,7 +32,6 @@
<ID>MagicNumber:StockQuote.kt$StockQuote.Companion$10</ID> <ID>MagicNumber:StockQuote.kt$StockQuote.Companion$10</ID>
<ID>MagicNumber:Tell.kt$Tell$50</ID> <ID>MagicNumber:Tell.kt$Tell$50</ID>
<ID>MagicNumber:Tell.kt$Tell$7</ID> <ID>MagicNumber:Tell.kt$Tell$7</ID>
<ID>MagicNumber:TwitterOAuth.kt$TwitterOAuth$401</ID>
<ID>MagicNumber:Users.kt$Users$8</ID> <ID>MagicNumber:Users.kt$Users$8</ID>
<ID>MagicNumber:Utils.kt$Utils$200</ID> <ID>MagicNumber:Utils.kt$Utils$200</ID>
<ID>MagicNumber:Utils.kt$Utils$399</ID> <ID>MagicNumber:Utils.kt$Utils$399</ID>
@ -47,7 +45,6 @@
<ID>MagicNumber:WorldTime.kt$WorldTime.Companion$3600</ID> <ID>MagicNumber:WorldTime.kt$WorldTime.Companion$3600</ID>
<ID>MagicNumber:WorldTime.kt$WorldTime.Companion$60</ID> <ID>MagicNumber:WorldTime.kt$WorldTime.Companion$60</ID>
<ID>MagicNumber:WorldTime.kt$WorldTime.Companion$86.4</ID> <ID>MagicNumber:WorldTime.kt$WorldTime.Companion$86.4</ID>
<ID>MaxLineLength:TwitterOAuth.kt$TwitterOAuth$*</ID>
<ID>NestedBlockDepth:Addons.kt$Addons$fun add(command: AbstractCommand): Boolean</ID> <ID>NestedBlockDepth:Addons.kt$Addons$fun add(command: AbstractCommand): Boolean</ID>
<ID>NestedBlockDepth:Addons.kt$Addons$fun add(module: AbstractModule): Boolean</ID> <ID>NestedBlockDepth:Addons.kt$Addons$fun add(module: AbstractModule): Boolean</ID>
<ID>NestedBlockDepth:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String</ID> <ID>NestedBlockDepth:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String</ID>
@ -65,13 +62,10 @@
<ID>NestedBlockDepth:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID> <ID>NestedBlockDepth:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
<ID>NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List&lt;Message&gt;</ID> <ID>NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List&lt;Message&gt;</ID>
<ID>NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent)</ID> <ID>NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent)</ID>
<ID>NestedBlockDepth:TwitterOAuth.kt$TwitterOAuth$@JvmStatic fun main(args: Array&lt;String&gt;)</ID>
<ID>NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any</ID> <ID>NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any</ID>
<ID>NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveSerialData(file: String, data: Any, logger: Logger, description: String)</ID> <ID>NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveSerialData(file: String, data: Any, logger: Logger, description: String)</ID>
<ID>NestedBlockDepth:Weather2.kt$Weather2$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID> <ID>NestedBlockDepth:Weather2.kt$Weather2$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID>
<ID>NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message&gt;</ID> <ID>NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message&gt;</ID>
<ID>PrintStackTrace:TwitterOAuth.kt$TwitterOAuth$ioe</ID>
<ID>PrintStackTrace:TwitterOAuth.kt$TwitterOAuth$te</ID>
<ID>ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean</ID> <ID>ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean</ID>
<ID>ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean</ID> <ID>ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean</ID>
<ID>ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException</ID> <ID>ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException</ID>
@ -91,5 +85,6 @@
<ID>TooManyFunctions:EntryLink.kt$EntryLink : Serializable</ID> <ID>TooManyFunctions:EntryLink.kt$EntryLink : Serializable</ID>
<ID>TooManyFunctions:Mobibot.kt$Mobibot : ListenerAdapter</ID> <ID>TooManyFunctions:Mobibot.kt$Mobibot : ListenerAdapter</ID>
<ID>TooManyFunctions:Tell.kt$Tell : AbstractCommand</ID> <ID>TooManyFunctions:Tell.kt$Tell : AbstractCommand</ID>
<ID>WildcardImport:FeedReaderTest.kt$import assertk.assertions.*</ID>
</CurrentIssues> </CurrentIssues>
</SmellBaseline> </SmellBaseline>

Binary file not shown.

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists 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 networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

7
gradlew vendored
View file

@ -85,9 +85,6 @@ done
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@ -197,6 +194,10 @@ if "$cygwin" || "$msys" ; then
done done
fi 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; # Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in # shell script including quotes and variable substitutions, so put them in

View file

@ -25,28 +25,13 @@ tell-max-days=5
tell-max-size=50 tell-max-size=50
#disabled-commands=die, ignore #disabled-commands=die, ignore
disabled-modules=twitter disabled-modules=mastodon
# #
# API Token for: https://pinboard.in/settings/password # API Token for: https://pinboard.in/settings/password
# #
#pinboard-api-token=user\:TOKEN #pinboard-api-token=user\:TOKEN
#
# Configure app at: https://developer.twitter.com/
# and then: java -cp mobibot.jar net.thauvin.erik.mobibot.TwitterOAuth <consumerKey> <consumerSecret>
#
#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 # Create a Mastodon application access token at: https//SERVER_INSTANCE/settings/applications
# Make sure the 'write:statuses' scope is enabled. # Make sure the 'write:statuses' scope is enabled.

View file

@ -59,6 +59,12 @@ object Constants {
*/ */
const val CLI_CMD = "java -jar ${ReleaseInfo.PROJECT}.jar" 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. * The help command.
*/ */

View file

@ -74,7 +74,7 @@ class FeedReader(private val url: String, val event: GenericMessageEvent) : Runn
fun readFeed(url: String, maxItems: Int = 5): List<Message> { fun readFeed(url: String, maxItems: Int = 5): List<Message> {
val messages = mutableListOf<Message>() val messages = mutableListOf<Message>()
val input = SyndFeedInput() val input = SyndFeedInput()
XmlReader(URL(url)).use { reader -> XmlReader(URL(url).openStream()).use { reader ->
val feed = input.build(reader) val feed = input.build(reader)
val items = feed.entries val items = feed.entries
if (items.isEmpty()) { if (items.isEmpty()) {

View file

@ -78,7 +78,6 @@ import net.thauvin.erik.mobibot.modules.Mastodon
import net.thauvin.erik.mobibot.modules.Ping import net.thauvin.erik.mobibot.modules.Ping
import net.thauvin.erik.mobibot.modules.RockPaperScissors import net.thauvin.erik.mobibot.modules.RockPaperScissors
import net.thauvin.erik.mobibot.modules.StockQuote 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.War
import net.thauvin.erik.mobibot.modules.Weather2 import net.thauvin.erik.mobibot.modules.Weather2
import net.thauvin.erik.mobibot.modules.WolframAlpha 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()) addons.add(View())
// Load social modules // Load social modules
LinksManager.socialManager.add(addons, Twitter(), Mastodon()) LinksManager.socialManager.add(addons, Mastodon())
// Load the modules // Load the modules
addons.add(Calc()) addons.add(Calc())

View file

@ -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 <consumerKey> <consumerSecret>`
*
* 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<String>) {
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} <consumerKey> <consumerSecret>")
}
exitProcess(0)
}
}

View file

@ -31,6 +31,7 @@
package net.thauvin.erik.mobibot.modules package net.thauvin.erik.mobibot.modules
import net.thauvin.erik.mobibot.Constants
import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils
import net.thauvin.erik.mobibot.Utils.sendMessage import net.thauvin.erik.mobibot.Utils.sendMessage
import org.apache.commons.text.WordUtils import org.apache.commons.text.WordUtils
@ -106,6 +107,7 @@ class ChatGpt : AbstractModule() {
.uri(URI.create(API_URL)) .uri(URI.create(API_URL))
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Authorization", "Bearer $apiKey") .header("Authorization", "Bearer $apiKey")
.header("User-Agent", Constants.USER_AGENT)
.POST( .POST(
HttpRequest.BodyPublishers.ofString( HttpRequest.BodyPublishers.ofString(
"""{ """{
@ -136,8 +138,10 @@ class ChatGpt : AbstractModule() {
} }
} else { } else {
if (response.statusCode() == 429) { if (response.statusCode() == 429) {
throw ModuleException("$CHATGPT_CMD($query): Rate limit reached", throw ModuleException(
"Rate limit reached. Please try again later.") "$CHATGPT_CMD($query): Rate limit reached",
"Rate limit reached. Please try again later."
)
} else { } else {
throw IOException("HTTP Status Code: " + response.statusCode()) throw IOException("HTTP Status Code: " + response.statusCode())
} }

View file

@ -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 <message>"))
properties[AUTO_POST_PROP] = "false"
initProperties(CONSUMER_KEY_PROP, CONSUMER_SECRET_PROP, HANDLE_PROP, TOKEN_PROP, TOKEN_SECRET_PROP)
}
}

View file

@ -45,7 +45,6 @@ import net.thauvin.erik.mobibot.modules.Dice
import net.thauvin.erik.mobibot.modules.Joke import net.thauvin.erik.mobibot.modules.Joke
import net.thauvin.erik.mobibot.modules.Lookup import net.thauvin.erik.mobibot.modules.Lookup
import net.thauvin.erik.mobibot.modules.RockPaperScissors import net.thauvin.erik.mobibot.modules.RockPaperScissors
import net.thauvin.erik.mobibot.modules.Twitter
import net.thauvin.erik.mobibot.modules.War import net.thauvin.erik.mobibot.modules.War
import org.testng.annotations.Test import org.testng.annotations.Test
import java.util.Properties import java.util.Properties
@ -62,7 +61,6 @@ class AddonsTest {
// Modules // Modules
addons.add(Joke()) addons.add(Joke())
addons.add(RockPaperScissors()) addons.add(RockPaperScissors())
addons.add(Twitter()) // no properties, disabled.
addons.add(War()) addons.add(War())
addons.add(Dice()) addons.add(Dice())
addons.add(Lookup()) addons.add(Lookup())

View file

@ -31,14 +31,9 @@
package net.thauvin.erik.mobibot package net.thauvin.erik.mobibot
import assertk.all import assertk.all
import assertk.assertFailure
import assertk.assertThat import assertk.assertThat
import assertk.assertions.contains import assertk.assertions.*
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 com.rometools.rome.io.FeedException import com.rometools.rome.io.FeedException
import net.thauvin.erik.mobibot.FeedReader.Companion.readFeed import net.thauvin.erik.mobibot.FeedReader.Companion.readFeed
import net.thauvin.erik.mobibot.msg.Message import net.thauvin.erik.mobibot.msg.Message
@ -66,13 +61,13 @@ class FeedReaderTest {
assertThat(messages, "messages").size().isEqualTo(84) assertThat(messages, "messages").size().isEqualTo(84)
assertThat(messages.last(), "messages.last").prop(Message::msg).contains("techdigest.tv") 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) .isInstanceOf(UnknownHostException::class.java)
} }
} }

View file

@ -30,6 +30,7 @@
*/ */
package net.thauvin.erik.mobibot.modules package net.thauvin.erik.mobibot.modules
import assertk.assertFailure
import assertk.assertThat import assertk.assertThat
import assertk.assertions.isEqualTo import assertk.assertions.isEqualTo
import assertk.assertions.isFailure 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 + 1"), "calculate(1+1)").isEqualTo("1+1 = ${2.bold()}")
assertThat(calculate("1 -3"), "calculate(1-3)").isEqualTo("1-3 = ${(-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("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)
} }
} }

View file

@ -30,6 +30,7 @@
*/ */
package net.thauvin.erik.mobibot.modules package net.thauvin.erik.mobibot.modules
import assertk.assertFailure
import assertk.assertThat import assertk.assertThat
import assertk.assertions.contains import assertk.assertions.contains
import assertk.assertions.hasNoCause import assertk.assertions.hasNoCause
@ -41,8 +42,7 @@ import org.testng.annotations.Test
class ChatGptTest : LocalProperties() { class ChatGptTest : LocalProperties() {
@Test(groups = ["modules"]) @Test(groups = ["modules"])
fun testApiKey() { fun testApiKey() {
assertThat { ChatGpt.chat("1 gallon to liter", "", 0) } assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) }
.isFailure()
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
.hasNoCause() .hasNoCause()
} }
@ -57,8 +57,7 @@ class ChatGptTest : LocalProperties() {
ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) ChatGpt.chat("how do I encode a URL in java?", apiKey, 60)
).contains("URLEncoder") ).contains("URLEncoder")
assertThat { ChatGpt.chat("1 liter to gallon", apiKey, 0) } assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) }
.isFailure()
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
} }
} }

View file

@ -31,6 +31,7 @@
package net.thauvin.erik.mobibot.modules package net.thauvin.erik.mobibot.modules
import assertk.all import assertk.all
import assertk.assertFailure
import assertk.assertThat import assertk.assertThat
import assertk.assertions.contains import assertk.assertions.contains
import assertk.assertions.hasMessage import assertk.assertions.hasMessage
@ -59,14 +60,13 @@ class GoogleSearchTest : LocalProperties() {
"searchGoogle(empty)" "searchGoogle(empty)"
).isInstanceOf(ErrorMessage::class.java) ).isInstanceOf(ErrorMessage::class.java)
assertThat { searchGoogle("test", "", "apiKey") }.isFailure() assertFailure { searchGoogle("test", "", "apiKey") }
.isInstanceOf(ModuleException::class.java).hasNoCause() .isInstanceOf(ModuleException::class.java).hasNoCause()
assertThat { searchGoogle("test", "apiKey", "") }.isFailure() assertFailure { searchGoogle("test", "apiKey", "") }
.isInstanceOf(ModuleException::class.java).hasNoCause() .isInstanceOf(ModuleException::class.java).hasNoCause()
assertThat { searchGoogle("test", "apiKey", "cssKey") } assertFailure { searchGoogle("test", "apiKey", "cssKey") }
.isFailure()
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
.hasMessage("API key not valid. Please pass a valid API key.") .hasMessage("API key not valid. Please pass a valid API key.")
} }

View file

@ -32,7 +32,6 @@ package net.thauvin.erik.mobibot.modules
import assertk.assertThat import assertk.assertThat
import assertk.assertions.contains import assertk.assertions.contains
import assertk.assertions.isSuccess
import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.LocalProperties
import net.thauvin.erik.mobibot.modules.Mastodon.Companion.toot import net.thauvin.erik.mobibot.modules.Mastodon.Companion.toot
import org.testng.annotations.Test import org.testng.annotations.Test
@ -42,7 +41,7 @@ class MastodonTest : LocalProperties() {
@Throws(ModuleException::class) @Throws(ModuleException::class)
fun testToot() { fun testToot() {
val msg = "Testing Mastodon API from ${getHostName()}" val msg = "Testing Mastodon API from ${getHostName()}"
assertThat { assertThat(
toot( toot(
getProperty(Mastodon.ACCESS_TOKEN_PROP), getProperty(Mastodon.ACCESS_TOKEN_PROP),
getProperty(Mastodon.INSTANCE_PROP), getProperty(Mastodon.INSTANCE_PROP),
@ -50,6 +49,6 @@ class MastodonTest : LocalProperties() {
msg, msg,
true true
) )
}.isSuccess().contains(msg) ).contains(msg)
} }
} }

View file

@ -31,6 +31,7 @@
package net.thauvin.erik.mobibot.modules package net.thauvin.erik.mobibot.modules
import assertk.all import assertk.all
import assertk.assertFailure
import assertk.assertThat import assertk.assertThat
import assertk.assertions.hasNoCause import assertk.assertions.hasNoCause
import assertk.assertions.index import assertk.assertions.index
@ -78,7 +79,7 @@ class StockQuoteTest : LocalProperties() {
isInstanceOf(ErrorMessage::class.java) isInstanceOf(ErrorMessage::class.java)
prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) 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) { } catch (e: ModuleException) {
// Avoid displaying api keys in CI logs // Avoid displaying api keys in CI logs
if ("true" == System.getenv("CI")) { if ("true" == System.getenv("CI")) {

View file

@ -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)
}
}

View file

@ -31,6 +31,7 @@
package net.thauvin.erik.mobibot.modules package net.thauvin.erik.mobibot.modules
import assertk.all import assertk.all
import assertk.assertFailure
import assertk.assertThat import assertk.assertThat
import assertk.assertions.contains import assertk.assertions.contains
import assertk.assertions.endsWith import assertk.assertions.endsWith
@ -116,8 +117,8 @@ class Weather2Test : LocalProperties() {
} }
query = "test" query = "test"
assertThat { getWeather(query, "") }.isFailure().isInstanceOf(ModuleException::class.java).hasNoCause() assertFailure { getWeather(query, "") }.isInstanceOf(ModuleException::class.java).hasNoCause()
assertThat { getWeather(query, null) }.isFailure().isInstanceOf(ModuleException::class.java).hasNoCause() assertFailure { getWeather(query, null) }.isInstanceOf(ModuleException::class.java).hasNoCause()
messages = getWeather("", "apikey") messages = getWeather("", "apikey")
assertThat(messages, "getWeather(empty)").index(0).prop(Message::isError).isTrue() assertThat(messages, "getWeather(empty)").index(0).prop(Message::isError).isTrue()

View file

@ -31,10 +31,10 @@
package net.thauvin.erik.mobibot.modules package net.thauvin.erik.mobibot.modules
import assertk.assertFailure
import assertk.assertThat import assertk.assertThat
import assertk.assertions.contains import assertk.assertions.contains
import assertk.assertions.hasMessage import assertk.assertions.hasMessage
import assertk.assertions.isFailure
import assertk.assertions.isInstanceOf import assertk.assertions.isInstanceOf
import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize
import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.LocalProperties
@ -44,13 +44,11 @@ import org.testng.annotations.Test
class WolframAlphaTest : LocalProperties() { class WolframAlphaTest : LocalProperties() {
@Test(groups = ["modules"]) @Test(groups = ["modules"])
fun testAppId() { fun testAppId() {
assertThat { queryWolfram("1 gallon to liter", appId = "DEMO") } assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") }
.isFailure()
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
.hasMessage("Error 1: Invalid appid") .hasMessage("Error 1: Invalid appid")
assertThat { queryWolfram("1 gallon to liter", appId = "") } assertFailure { queryWolfram("1 gallon to liter", appId = "") }
.isFailure()
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
} }

View file

@ -30,6 +30,7 @@
*/ */
package net.thauvin.erik.mobibot.modules package net.thauvin.erik.mobibot.modules
import assertk.assertFailure
import assertk.assertThat import assertk.assertThat
import assertk.assertions.endsWith import assertk.assertions.endsWith
import assertk.assertions.isSuccess import assertk.assertions.isSuccess
@ -65,7 +66,7 @@ class WordTimeTest {
@Test(groups = ["modules"]) @Test(groups = ["modules"])
fun testZones() { fun testZones() {
COUNTRIES_MAP.filter { it.value != BEATS_KEYWORD }.forEach { COUNTRIES_MAP.filter { it.value != BEATS_KEYWORD }.forEach {
assertThat { ZoneId.of(it.value) }.isSuccess() assertThat(ZoneId.of(it.value))
} }
} }
} }

View file

@ -1,9 +1,9 @@
#Generated by the Semver Plugin for Gradle #Generated by the Semver Plugin for Gradle
#Mon Jan 30 22:08:48 PST 2023 #Sat May 20 23:54:50 PDT 2023
version.buildmeta=986 version.buildmeta=1077
version.major=0 version.major=0
version.minor=8 version.minor=8
version.patch=0 version.patch=0
version.prerelease=rc version.prerelease=rc
version.project=mobibot version.project=mobibot
version.semver=0.8.0-rc+986 version.semver=0.8.0-rc+1077

View file

@ -46,7 +46,6 @@
<li><a href="https://github.com/ethauvin/pinboard-poster">Pinboard Poster</a></li> <li><a href="https://github.com/ethauvin/pinboard-poster">Pinboard Poster</a></li>
<li><a href="https://github.com/pircbotx/pircbotx">PircBotX</a></li> <li><a href="https://github.com/pircbotx/pircbotx">PircBotX</a></li>
<li><a href="https://rometools.github.io/rome/">Rome</a></li> <li><a href="https://rometools.github.io/rome/">Rome</a></li>
<li><a href="http://twitter4j.org/en/index.html">Twitter4J</a></li>
<li><a href="https://github.com/ethauvin/urlencoder">UrlEncoder</a></li> <li><a href="https://github.com/ethauvin/urlencoder">UrlEncoder</a></li>
</ul> </ul>
<p>mobibot was written by <p>mobibot was written by