diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 8920634..75b7aaa 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -31,5 +31,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/mobibot.iml b/.idea/mobibot.iml
new file mode 100644
index 0000000..b03a311
--- /dev/null
+++ b/.idea/mobibot.iml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 3207f2a..020006e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,12 +2,12 @@ plugins {
id 'application'
id 'com.github.ben-manes.versions' version '0.39.0'
id 'idea'
- id 'io.gitlab.arturbosch.detekt' version '1.18.1'
+ id 'io.gitlab.arturbosch.detekt' version '1.19.0-RC1'
id 'jacoco'
id 'java'
id 'net.thauvin.erik.gradle.semver' version '1.0.4'
- id 'org.jetbrains.kotlin.jvm' version '1.6.0-RC'
- id 'org.jetbrains.kotlin.kapt' version '1.6.0-RC'
+ id 'org.jetbrains.kotlin.jvm' version '1.6.0-RC2'
+ id 'org.jetbrains.kotlin.kapt' version '1.6.0-RC2'
id 'org.sonarqube' version '3.3'
id 'pmd'
}
@@ -22,12 +22,13 @@ mainClassName = packageName + '.Mobibot'
ext.versions = [
log4j: '2.14.1',
- pmd : '6.35.0',
+ pmd : '6.40.0',
]
repositories {
mavenLocal()
mavenCentral()
+ maven { url 'https://jitpack.io' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
}
@@ -35,8 +36,13 @@ dependencies {
kapt(semverProcessor)
compileOnly(semverProcessor)
- implementation 'pircbot:pircbot:1.5.0'
- compileOnly 'pircbot:pircbot:1.5.0:sources'
+ implementation 'com.github.pircbotx:pircbotx:-SNAPSHOT'
+
+ implementation 'org.apache.commons:commons-text:1.9'
+ implementation 'org.apache.commons:commons-lang3:3.12.0'
+ implementation 'org.slf4j:slf4j-api:1.7.32'
+ implementation 'commons-codec:commons-codec:1.15'
+ implementation 'com.google.guava:guava:31.0.1-jre'
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
@@ -44,11 +50,12 @@ dependencies {
implementation "org.apache.logging.log4j:log4j-api:$versions.log4j"
implementation "org.apache.logging.log4j:log4j-core:$versions.log4j"
implementation "org.apache.logging.log4j:log4j-slf4j-impl:$versions.log4j"
- implementation 'commons-cli:commons-cli:1.4'
+
+ implementation 'commons-cli:commons-cli:1.5.0'
implementation 'commons-net:commons-net:3.8.0'
implementation 'com.rometools:rome:1.16.0'
- implementation 'com.squareup.okhttp3:okhttp:4.9.1'
+ implementation 'com.squareup.okhttp3:okhttp:4.9.2'
implementation 'net.aksingh:owm-japis:2.5.3.0'
implementation 'net.objecthunter:exp4j:0.4.8'
@@ -59,7 +66,9 @@ dependencies {
implementation 'org.jsoup:jsoup:1.14.3'
implementation 'org.twitter4j:twitter4j-core:4.0.7'
- testImplementation 'org.assertj:assertj-core:3.21.0'
+ testImplementation 'com.willowtreeapps.assertk:assertk-jvm:0.25'
+// testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0'
+// testImplementation "org.mockito:mockito-core:4.0.0"
testImplementation 'org.testng:testng:7.4.0'
}
@@ -117,6 +126,7 @@ jar {
manifest.attributes('Main-Class': mainClassName,
'Class-Path': '. ./lib/' + configurations.runtimeClasspath.collect { it.getName() }.join(' ./lib/'))
archiveVersion.set("")
+ exclude('log4j2.xml')
}
clean {
diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml
index c3f468f..9bc0b96 100644
--- a/config/detekt/baseline.xml
+++ b/config/detekt/baseline.xml
@@ -2,54 +2,76 @@
- ComplexMethod:EntriesMgr.kt$EntriesMgr$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )
+ ComplexMethod:FeedsMgr.kt$FeedsMgr.Companion$ fun saveFeed(entries: Entries, currentFile: String = currentXml)
ComplexMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message>
- LongMethod:EntriesMgr.kt$EntriesMgr$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )
- LongMethod:Mobibot.kt$Mobibot.Companion$ @JvmStatic fun main(args: Array<String>)
+ LongMethod:FeedsMgr.kt$FeedsMgr.Companion$ fun saveFeed(entries: Entries, currentFile: String = currentXml)
+ LongMethod:Mobibot.kt$Mobibot.Companion$@Throws(Exception::class) @JvmStatic fun main(args: Array<String>)
LongMethod:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message>
LongMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message>
- LongParameterList:Addons.kt$Addons$(sender: String, login: String, cmd: String, args: String, isOp: Boolean, isPrivate: Boolean)
- LongParameterList:Comment.kt$Comment$( bot: Mobibot, cmd: String, sender: String, isOp: Boolean, entry: EntryLink, index: Int, commentIndex: Int )
- LongParameterList:Comment.kt$Comment$( bot: Mobibot, sender: String, isOp: Boolean, entry: EntryLink, index: Int, commentIndex: Int )
- LongParameterList:Comment.kt$Comment$(bot: Mobibot, cmd: String, sender: String, entry: EntryLink, index: Int, commentIndex: Int)
- LongParameterList:Mobibot.kt$Mobibot$( nick: String, list: List<String>, maxPerLine: Int, separator: String = " ", isPrivate: Boolean, isBold: Boolean = false, isIndent: Boolean = false )
+ LongParameterList:Comment.kt$Comment$( channel: String, cmd: String, entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent )
LongParameterList:Twitter.kt$Twitter.Companion$( consumerKey: String?, consumerSecret: String?, token: String?, tokenSecret: String?, handle: String?, message: String, isDm: Boolean )
+ MagicNumber:Comment.kt$Comment$3
+ MagicNumber:CurrencyConverter.kt$CurrencyConverter$11
+ MagicNumber:CurrencyConverter.kt$CurrencyConverter$3
+ MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$3
+ MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$4
+ MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$8
+ MagicNumber:Cycle.kt$Cycle$10
+ MagicNumber:Cycle.kt$Cycle$1000L
+ MagicNumber:Ignore.kt$Ignore$8
+ MagicNumber:Mobibot.kt$Mobibot$8
+ MagicNumber:Modules.kt$Modules$7
+ MagicNumber:Recap.kt$Recap.Companion$10
+ MagicNumber:StockQuote.kt$StockQuote.Companion$10
+ MagicNumber:Tell.kt$Tell$50
+ MagicNumber:Tell.kt$Tell$7
+ MagicNumber:Twitter.kt$Twitter$1000L
+ MagicNumber:Twitter.kt$Twitter$60L
+ MagicNumber:TwitterOAuth.kt$TwitterOAuth$401
+ MagicNumber:Users.kt$Users$8
+ MagicNumber:Utils.kt$Utils$30
+ MagicNumber:Utils.kt$Utils$365
+ MagicNumber:Utils.kt$Utils$7
+ MagicNumber:View.kt$View$6
+ MagicNumber:Weather2.kt$Weather2.Companion$1.60934
+ MagicNumber:Weather2.kt$Weather2.Companion$32
+ MagicNumber:Weather2.kt$Weather2.Companion$5
+ MagicNumber:Weather2.kt$Weather2.Companion$9
+ MagicNumber:WorldTime.kt$WorldTime$14
+ MagicNumber:WorldTime.kt$WorldTime$4
+ MagicNumber:WorldTime.kt$WorldTime.Companion$3
+ MagicNumber:WorldTime.kt$WorldTime.Companion$3600
+ MagicNumber:WorldTime.kt$WorldTime.Companion$60
+ MagicNumber:WorldTime.kt$WorldTime.Companion$86.4
NestedBlockDepth:Addons.kt$Addons$ fun add(command: AbstractCommand, props: Properties)
- NestedBlockDepth:Calc.kt$Calc$override fun commandResponse( sender: String, cmd: String, args: String, isPrivate: Boolean )
- NestedBlockDepth:Comment.kt$Comment$override fun commandResponse( sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean )
- NestedBlockDepth:CryptoPrices.kt$CryptoPrices$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)
- NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)
- NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter$override fun helpResponse(sender: String, isPrivate: Boolean): Boolean
- NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$ @Suppress("MagicNumber") @JvmStatic fun convertCurrency(query: String): Message
- NestedBlockDepth:EntriesMgr.kt$EntriesMgr$ @Throws(IOException::class, FeedException::class) fun loadEntries(file: String, channel: String, entries: MutableList<EntryLink>): String
- NestedBlockDepth:EntriesMgr.kt$EntriesMgr$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )
- NestedBlockDepth:EntriesMgr.kt$EntriesMgr$// Daily backup private fun dailyBackup( bot: Mobibot, history: MutableList<String> )
+ NestedBlockDepth:Comment.kt$Comment$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)
+ NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$ @JvmStatic fun convertCurrency(query: String): Message
NestedBlockDepth:EntryLink.kt$EntryLink$ private fun setTags(tags: List<String?>)
- NestedBlockDepth:GoogleSearch.kt$GoogleSearch$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)
- NestedBlockDepth:LinksMgr.kt$LinksMgr$override fun commandResponse( sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean )
- NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse( sender: String, cmd: String, args: String, isPrivate: Boolean )
- NestedBlockDepth:Mobibot.kt$Mobibot$ fun connect()
- NestedBlockDepth:StockQuote.kt$StockQuote$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)
+ NestedBlockDepth:FeedsMgr.kt$FeedsMgr.Companion$ @Throws(IOException::class, FeedException::class) fun loadFeed(entries: Entries, currentFile: String = currentXml): String
+ NestedBlockDepth:FeedsMgr.kt$FeedsMgr.Companion$ fun saveFeed(entries: Entries, currentFile: String = currentXml)
+ NestedBlockDepth:GoogleSearch.kt$GoogleSearch.Companion$ @JvmStatic @Throws(ModuleException::class) fun searchGoogle(query: String, apiKey: String?, cseKey: String?): List<Message>
+ NestedBlockDepth:LinksMgr.kt$LinksMgr$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)
+ NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)
+ NestedBlockDepth:Posting.kt$Posting$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$ @JvmOverloads fun send(nickname: String, isMessage: Boolean = false)
- NestedBlockDepth:Tell.kt$Tell$// Delete message. private fun deleteMessage(sender: String, args: String, isOp: Boolean, isPrivate: Boolean)
- NestedBlockDepth:TellMessagesMgr.kt$TellMessagesMgr$ fun save(file: String, messages: List<TellMessage?>?, logger: Logger)
+ NestedBlockDepth:Tell.kt$Tell$ fun send(event: GenericUserEvent)
+ NestedBlockDepth:Tell.kt$Tell$// Delete message. private fun deleteMessage(channel: String, args: String, event: GenericMessageEvent)
+ NestedBlockDepth:TellMessagesMgr.kt$TellMessagesMgr$ fun load(file: String): List<TellMessage>
+ NestedBlockDepth:TellMessagesMgr.kt$TellMessagesMgr$ fun save(file: String, messages: List<TellMessage?>?)
NestedBlockDepth:TwitterOAuth.kt$TwitterOAuth$ @Throws(TwitterException::class, IOException::class) @JvmStatic fun main(args: Array<String>)
- NestedBlockDepth:Weather2.kt$Weather2$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)
+ NestedBlockDepth:Weather2.kt$Weather2$ override fun run(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>
- NestedBlockDepth:WorldTime.kt$WorldTime$override fun commandResponse( sender: String, cmd: String, args: String, isPrivate: Boolean )
- ReturnCount:Addons.kt$Addons$ fun exec(sender: String, login: String, cmd: String, args: String, isOp: Boolean, isPrivate: Boolean): Boolean
- ReturnCount:Addons.kt$Addons$ fun help(sender: String, topic: String, isOp: Boolean, isPrivate: Boolean): Boolean
+ 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
+ SwallowedException:GoogleSearchTest.kt$GoogleSearchTest$e: ModuleException
+ SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException
ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$ @JvmStatic @Throws(ModuleException::class) fun searchGoogle(query: String, apiKey: String?, cseKey: String?): List<Message>
ThrowsCount:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message>
ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject
ThrowsCount:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message>
- TooGenericExceptionCaught:CryptoPrices.kt$CryptoPrices$e: Exception
- TooGenericExceptionCaught:Mobibot.kt$Mobibot$e: Exception
- TooGenericExceptionCaught:Mobibot.kt$Mobibot$ex: Exception
TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException
TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException
- TooManyFunctions:Mobibot.kt$Mobibot : PircBot
TooManyFunctions:Tell.kt$Tell : AbstractCommand
diff --git a/properties/log4j2.xml b/properties/log4j2.xml
index 2842592..0aa95bf 100644
--- a/properties/log4j2.xml
+++ b/properties/log4j2.xml
@@ -1,16 +1,38 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/properties/mobibot.properties b/properties/mobibot.properties
index 8089d08..67326f3 100644
--- a/properties/mobibot.properties
+++ b/properties/mobibot.properties
@@ -3,9 +3,13 @@ server=irc.freenode.net
#port=6667
login=mobibot
nick=mobibot
+#realname=mobibot
+
+# Die command password, if any
+#die=changeme
# NickServ password
-ident=changepwd
+ident=changeme
#ident-nick=nickserv
#ident-msg=IDENTIFY changepwd
@@ -14,7 +18,6 @@ ignore=chanserv,nickserv
tags=mobile mobitopia
tags-keywords=android ios apple google
-weblog=http://www.mobitopia.org/
feed=http://www.mobitopia.org/rss.xml
backlogs=http://www.mobitopia.org/mobibot/logs
diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/War.java b/src/main/java/net/thauvin/erik/mobibot/modules/War.java
index 2e83533..c286091 100644
--- a/src/main/java/net/thauvin/erik/mobibot/modules/War.java
+++ b/src/main/java/net/thauvin/erik/mobibot/modules/War.java
@@ -32,9 +32,9 @@
package net.thauvin.erik.mobibot.modules;
-import net.thauvin.erik.mobibot.Mobibot;
import net.thauvin.erik.mobibot.Utils;
import org.jetbrains.annotations.NotNull;
+import org.pircbotx.hooks.types.GenericMessageEvent;
import java.security.SecureRandom;
@@ -66,8 +66,8 @@ public final class War extends AbstractModule {
/**
* The default constructor.
*/
- public War(final Mobibot bot) {
- super(bot);
+ public War() {
+ super();
commands.add(WAR_CMD);
@@ -79,10 +79,8 @@ public final class War extends AbstractModule {
* {@inheritDoc}
*/
@Override
- public void commandResponse(@NotNull final String sender,
- @NotNull final String cmd,
- @NotNull final String args,
- final boolean isPrivate) {
+ public void commandResponse(@NotNull final String channel, @NotNull final String cmd, @NotNull final String args,
+ @NotNull final GenericMessageEvent event) {
int i;
int y;
@@ -90,20 +88,20 @@ public final class War extends AbstractModule {
i = RANDOM.nextInt(HEARTS.length);
y = RANDOM.nextInt(HEARTS.length);
- getBot().send(sender + " drew: " + DECK[RANDOM.nextInt(DECK.length)][i]);
- getBot().action("drew: " + DECK[RANDOM.nextInt(DECK.length)][y]);
+ event.respond("you drew " + DECK[RANDOM.nextInt(DECK.length)][i]);
+ event.getBot().sendIRC().action(channel, "drew " + DECK[RANDOM.nextInt(DECK.length)][y]);
if (i != y) {
break;
}
- getBot().send("This means " + bold("WAR") + '!');
+ event.respond("This means " + bold("WAR") + '!');
}
if (i < y) {
- getBot().action("lost.");
+ event.getBot().sendIRC().action(channel, "lost.");
} else {
- getBot().action("wins.");
+ event.getBot().sendIRC().action(channel, "wins.");
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt
index 1a0e8dd..bc527f0 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt
@@ -33,6 +33,8 @@ package net.thauvin.erik.mobibot
import net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.modules.AbstractModule
+import org.pircbotx.hooks.events.PrivateMessageEvent
+import org.pircbotx.hooks.types.GenericMessageEvent
import java.util.Properties
/**
@@ -77,7 +79,7 @@ class Addons {
if (isEnabled()) {
commands.add(this)
if (isVisible) {
- if (isOp) {
+ if (isOpOnly) {
ops.add(name)
} else {
names.add(name)
@@ -90,17 +92,18 @@ class Addons {
/**
* Execute a command or module.
*/
- fun exec(sender: String, login: String, cmd: String, args: String, isOp: Boolean, isPrivate: Boolean): Boolean {
- for (command in commands) {
+ fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean {
+ val cmds = if (event is PrivateMessageEvent) commands else commands.filter { it.isPublic }
+ for (command in cmds) {
if (command.name.startsWith(cmd)) {
- command.commandResponse(sender, login, args, isOp, isPrivate)
+ command.commandResponse(channel, args, event)
return true
}
}
- val mods = if (isPrivate) modules.filter { it.isPrivateMsgEnabled } else modules
+ val mods = if (event is PrivateMessageEvent) modules.filter { it.isPrivateMsgEnabled } else modules
for (module in mods) {
if (module.commands.contains(cmd)) {
- module.commandResponse(sender, cmd, args, isPrivate)
+ module.commandResponse(channel, cmd, args, event)
return true
}
}
@@ -110,10 +113,10 @@ class Addons {
/**
* Match a command.
*/
- fun match(sender: String, login: String, message: String, isOp: Boolean, isPrivate: Boolean): Boolean {
+ fun match(channel: String, event: GenericMessageEvent): Boolean {
for (command in commands) {
- if (command.matches(message)) {
- command.commandResponse(sender, login, message, isOp, isPrivate)
+ if (command.matches(event.message)) {
+ command.commandResponse(channel, event.message, event)
return true
}
}
@@ -123,15 +126,15 @@ class Addons {
/**
* Commands and Modules help.
*/
- fun help(sender: String, topic: String, isOp: Boolean, isPrivate: Boolean): Boolean {
+ fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean {
for (command in commands) {
if (command.isVisible && command.name.startsWith(topic)) {
- return command.helpResponse(topic, sender, isOp, isPrivate)
+ return command.helpResponse(channel, topic, event)
}
}
for (module in modules) {
if (module.commands.contains(topic)) {
- return module.helpResponse(sender, isPrivate)
+ return module.helpResponse(event)
}
}
return false
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt
index 2ae420d..dfe25dc 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt
@@ -45,11 +45,6 @@ object Constants {
*/
const val DEBUG_ARG = "debug"
- /**
- * The debug command.
- */
- const val DEBUG_CMD = "debug"
-
/**
* Default IRC Port.
*/
@@ -58,12 +53,7 @@ object Constants {
/**
* Default IRC Server.
*/
- const val DEFAULT_SERVER = "irc.freenode.net"
-
- /**
- * The die command.
- */
- const val DIE_CMD = "die"
+ const val DEFAULT_SERVER = "irc.libera.chat"
/**
* Help command line argument.
@@ -75,11 +65,6 @@ object Constants {
*/
const val HELP_CMD = "help"
- /**
- * The kill command.
- */
- const val KILL_CMD = "kill"
-
/**
* The link command.
*/
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt
index 3ee5aad..16c8e6b 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt
@@ -36,38 +36,36 @@ import com.rometools.rome.io.SyndFeedInput
import com.rometools.rome.io.XmlReader
import net.thauvin.erik.mobibot.Utils.green
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendMessage
+import net.thauvin.erik.mobibot.entries.FeedsMgr
import net.thauvin.erik.mobibot.msg.Message
-import net.thauvin.erik.mobibot.msg.PublicMessage
+import net.thauvin.erik.mobibot.msg.NoticeMessage
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import java.io.IOException
import java.net.URL
/**
* Reads an RSS feed.
*/
-class FeedReader(
- // Bot
- private val bot: Mobibot,
- // Nick of the person who sent the message
- private val sender: String,
- // URL to fetch
- private val url: String
-) : Runnable {
+class FeedReader(private val url: String, val event: GenericMessageEvent) : Runnable {
+ private val logger: Logger = LoggerFactory.getLogger(FeedsMgr::class.java)
+
/**
* Fetches the Feed's items.
*/
override fun run() {
- with(bot) {
- try {
- readFeed(url).forEach {
- send(sender, it)
- }
- } catch (e: FeedException) {
- if (logger.isDebugEnabled) logger.debug("Unable to parse the feed at $url", e)
- send(sender, "An error has occurred while parsing the feed: ${e.message}", false)
- } catch (e: IOException) {
- if (logger.isDebugEnabled) logger.debug("Unable to fetch the feed at $url", e)
- send(sender, "An error has occurred while fetching the feed: ${e.message}", false)
+ try {
+ readFeed(url).forEach {
+ event.sendMessage("", it)
}
+ } catch (e: FeedException) {
+ if (logger.isWarnEnabled) logger.warn("Unable to parse the feed at $url", e)
+ event.sendMessage("An error has occurred while parsing the feed: ${e.message}")
+ } catch (e: IOException) {
+ if (logger.isWarnEnabled) logger.warn("Unable to fetch the feed at $url", e)
+ event.sendMessage("An error has occurred while fetching the feed: ${e.message}")
}
}
@@ -81,11 +79,11 @@ class FeedReader(
val feed = input.build(reader)
val items = feed.entries
if (items.isEmpty()) {
- messages.add(PublicMessage("There is currently nothing to view."))
+ messages.add(NoticeMessage("There is currently nothing to view."))
} else {
items.take(maxItems).forEach {
- messages.add(PublicMessage(it.title))
- messages.add(PublicMessage(helpFormat(green(it.link), false)))
+ messages.add(NoticeMessage(it.title))
+ messages.add(NoticeMessage(helpFormat(green(it.link), false)))
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt
index 6bfbe8a..574366a 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt
@@ -29,23 +29,21 @@
* 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 net.thauvin.erik.mobibot.Utils.appendIfMissing
-import net.thauvin.erik.mobibot.Utils.buildCmdSyntax
-import net.thauvin.erik.mobibot.Utils.colorize
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.getIntProperty
-import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import net.thauvin.erik.mobibot.Utils.sendList
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.Utils.toIsoLocalDate
-import net.thauvin.erik.mobibot.Utils.today
-import net.thauvin.erik.mobibot.commands.AddLog
import net.thauvin.erik.mobibot.commands.ChannelFeed
import net.thauvin.erik.mobibot.commands.Cycle
-import net.thauvin.erik.mobibot.commands.Debug
import net.thauvin.erik.mobibot.commands.Die
import net.thauvin.erik.mobibot.commands.Ignore
import net.thauvin.erik.mobibot.commands.Info
-import net.thauvin.erik.mobibot.commands.Kill
import net.thauvin.erik.mobibot.commands.Me
import net.thauvin.erik.mobibot.commands.Modules
import net.thauvin.erik.mobibot.commands.Msg
@@ -61,8 +59,6 @@ import net.thauvin.erik.mobibot.commands.links.Posting
import net.thauvin.erik.mobibot.commands.links.Tags
import net.thauvin.erik.mobibot.commands.links.View
import net.thauvin.erik.mobibot.commands.tell.Tell
-import net.thauvin.erik.mobibot.entries.EntriesMgr
-import net.thauvin.erik.mobibot.entries.EntryLink
import net.thauvin.erik.mobibot.modules.Calc
import net.thauvin.erik.mobibot.modules.CryptoPrices
import net.thauvin.erik.mobibot.modules.CurrencyConverter
@@ -73,12 +69,9 @@ import net.thauvin.erik.mobibot.modules.Lookup
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.WorldTime
-import net.thauvin.erik.mobibot.msg.Message
-import net.thauvin.erik.pinboard.PinboardPoster
import net.thauvin.erik.semver.Version
import org.apache.commons.cli.CommandLine
import org.apache.commons.cli.CommandLineParser
@@ -87,10 +80,19 @@ import org.apache.commons.cli.HelpFormatter
import org.apache.commons.cli.Option
import org.apache.commons.cli.Options
import org.apache.commons.cli.ParseException
-import org.apache.logging.log4j.Level
-import org.apache.logging.log4j.LogManager
-import org.apache.logging.log4j.Logger
-import org.jibble.pircbot.PircBot
+import org.pircbotx.Configuration
+import org.pircbotx.PircBotX
+import org.pircbotx.hooks.ListenerAdapter
+import org.pircbotx.hooks.events.ActionEvent
+import org.pircbotx.hooks.events.DisconnectEvent
+import org.pircbotx.hooks.events.JoinEvent
+import org.pircbotx.hooks.events.MessageEvent
+import org.pircbotx.hooks.events.NickChangeEvent
+import org.pircbotx.hooks.events.PartEvent
+import org.pircbotx.hooks.events.PrivateMessageEvent
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileNotFoundException
@@ -100,427 +102,139 @@ import java.io.PrintStream
import java.nio.file.Files
import java.nio.file.Paths
import java.util.Properties
-import java.util.Timer
-import java.util.logging.ConsoleHandler
import java.util.regex.Pattern
import kotlin.system.exitProcess
-/**
- * Implements the #mobitopia bot.
- */
@Version(properties = "version.properties", className = "ReleaseInfo", template = "version.mustache", type = "kt")
-class Mobibot(nickname: String, channel: String, logsDirPath: String, p: Properties) : PircBot() {
+class Mobibot(nickname: String, channel: String, logsDirPath: String, p: Properties) : ListenerAdapter() {
+ // The bot configuration.
+ private val config: Configuration
+
// Commands and Modules
private val addons = Addons()
+ // Tell module
+ private val tell: Tell
+
/** Main channel. */
val channel: String
- // IRC port
- private val ircPort: Int
-
- /** IRC server. */
- val ircServer: String
-
/** Logger. */
- val logger: Logger = LogManager.getLogger(Mobibot::class.java)
-
- /** Logger default level. */
- val loggerLevel: Level
-
- /** Log directory. */
- val logsDir: String
-
- // Pinboard posts handler
- private val pinboard: PinboardPoster = PinboardPoster()
-
- /** Tell command. */
- val tell: Tell
-
- /** Today's date. */
- val today = today()
-
- /** Twitter module. */
- val twitter: Twitter
-
- /** The backlogs URL. */
- val backlogsUrl: String
-
- // Ident message
- private val identMsg: String
-
- // Ident nick
- private val identNick: String
-
- // NickServ ident password
- private val identPwd: String
-
- // Is pinboard enabled?
- private var isPinboardEnabled = false
-
- /** Timer. */
- val timer = Timer(true)
-
- /** Weblog URL */
- val weblogUrl: String
-
- /** The current channel name. */
- private val channelName: String
- get() = channel.substring(1)
-
- /** The enabled modules names. */
- val modulesNames: List
- get() = addons.modulesNames
-
- /**
- * Sends an action to the current channel.
- */
- fun action(action: String) {
- action(channel, action)
- }
-
- /**
- * Sends an action to the channel.
- */
- private fun action(channel: String, action: String) {
- if (channel.isNotBlank() && action.isNotBlank()) {
- sendAction(channel, action)
- }
- }
-
- /**
- * Adds pin on pinboard.
- */
- fun addPin(entry: EntryLink) {
- if (isPinboardEnabled) {
- PinboardUtils.addPin(pinboard, ircServer, entry)
- }
- }
+ val logger: Logger = LoggerFactory.getLogger(Mobibot::class.java)
/**
* Connects to the server and joins the channel.
*/
fun connect() {
- try {
- connect(ircServer, ircPort)
- } catch (e: Exception) {
- if (logger.isDebugEnabled) {
- logger.debug("Unable to connect to $ircServer, will try again.", e)
- }
- var retries = 0
- while (retries++ < MAX_RECONNECT && !isConnected) {
- @Suppress("MagicNumber")
- sleep(10)
- try {
- connect(ircServer, ircPort)
- } catch (ex: Exception) {
- if (retries == MAX_RECONNECT) {
- if (logger.isDebugEnabled) {
- logger.debug("Unable to reconnect to $ircServer, after $MAX_RECONNECT retries.", ex)
- }
- System.err.println("An error has occurred while reconnecting; ${ex.message}")
- exitProcess(1)
- }
- }
- }
- }
- identify()
- joinChannel()
- }
-
- /**
- * Deletes pin on pinboard.
- */
- fun deletePin(index: Int, entry: EntryLink) {
- if (isPinboardEnabled) {
- PinboardUtils.deletePin(pinboard, entry)
- }
- if (twitter.isAutoPost) {
- twitter.removeEntry(index)
- }
+ PircBotX(config).startBot()
}
/**
* Responds with the default help.
*/
- @Suppress("MagicNumber")
- fun helpDefault(sender: String, isOp: Boolean, isPrivate: Boolean) {
- send(sender, "Type a URL on $channel to post it.", isPrivate)
- send(sender, "For more information on a specific command, type:", isPrivate)
- send(
- sender,
- helpFormat(buildCmdSyntax("%c ${Constants.HELP_CMD} ", nick, isPrivate)),
- isPrivate
+ private fun helpDefault(event: GenericMessageEvent) {
+ event.sendMessage("Type a URL on $channel to post it.")
+ event.sendMessage("For more information on a specific command, type:")
+ event.sendMessage(
+ Utils.helpFormat(
+ Utils.buildCmdSyntax(
+ "%c ${Constants.HELP_CMD} ",
+ event.bot().nick,
+ event is PrivateMessageEvent
+ )
+ ),
)
- send(sender, "The commands are:", isPrivate)
- sendList(sender, addons.names, 8, isPrivate = isPrivate, isBold = true, isIndent = true)
- if (isOp) {
- send(sender, "The op commands are:", isPrivate)
- sendList(sender, addons.ops, 8, isPrivate = isPrivate, isBold = true, isIndent = true)
+ event.sendMessage("The commands are:")
+ event.sendList(addons.names, 8, isBold = true, isIndent = true)
+ if (isChannelOp(channel, event)) {
+ event.sendMessage("The op commands are:")
+ event.sendList(addons.ops, 8, isBold = true, isIndent = true)
}
}
/**
* Responds with the default, commands or modules help.
*/
- private fun helpResponse(sender: String, topic: String, isPrivate: Boolean) {
- val isOp = isOp(sender)
- if (topic.isBlank() || !addons.help(sender, topic.lowercase().trim(), isOp, isPrivate)) {
- helpDefault(sender, isOp, isPrivate)
+ private fun helpResponse(event: GenericMessageEvent, topic: String) {
+ if (topic.isBlank() || !addons.help(channel, topic.lowercase().trim(), event)) {
+ helpDefault(event)
}
}
- /**
- * Identifies the bot.
- */
- private fun identify() {
- // Identify with NickServ
- if (identPwd.isNotBlank()) {
- identify(identPwd)
- }
- // Identify with a specified nick
- if (identNick.isNotBlank() && identMsg.isNotBlank()) {
- sendMessage(identNick, identMsg)
+ override fun onAction(event: ActionEvent?) {
+ if (channel == event?.channel?.name) {
+ storeRecap(event.user!!.nick, event.action, true)
}
}
- /**
- * Returns {@code true} if the specified sender is an Op on the [channel][.ircChannel].
- */
- fun isOp(sender: String): Boolean {
- for (user in getUsers(channel)) {
- if (user.nick == sender) {
- return user.isOp
+ override fun onDisconnect(event: DisconnectEvent?) {
+ with(event!!.getBot()) {
+ LinksMgr.twitter.notification("$nick disconnected from irc://$serverHostname")
+ }
+ LinksMgr.twitter.shutdown()
+ }
+
+ override fun onPrivateMessage(event: PrivateMessageEvent?) {
+ if (logger.isTraceEnabled) logger.trace("<<< ${event!!.user!!.nick}: ${event.message}")
+ val cmds = event!!.message.trim().split(" ".toRegex(), 2)
+ val cmd = cmds[0].lowercase()
+ val args = if (cmds.size > 1) {
+ cmds[1].trim()
+ } else ""
+ if (cmd.startsWith(Constants.HELP_CMD)) { // help
+ helpResponse(event, args)
+ } else if (!addons.exec(channel, cmd, args, event)) { // Execute command or module
+ helpDefault(event)
+ }
+ }
+
+ override fun onJoin(event: JoinEvent?) {
+ with(event!!.getBot()) {
+ if (event.user!!.nick == nick) {
+ LinksMgr.twitter.notification("$nick has joined ${event.channel.name} on irc://$serverHostname")
+ } else {
+ tell.send(event)
}
}
- return false
}
- /**
- * Joins the bot's channel.
- */
- private fun joinChannel() {
- joinChannel(channel)
- twitter.notification("$name ${ReleaseInfo.VERSION} has joined $channel")
- }
-
- override fun onDisconnect() {
- if (weblogUrl.isNotBlank()) {
- version = weblogUrl
- }
- @Suppress("MagicNumber")
- sleep(5)
- connect()
- }
-
- override fun onMessage(
- channel: String,
- sender: String,
- login: String,
- hostname: String,
- message: String
- ) {
- if (logger.isDebugEnabled) logger.debug(">>> $sender: $message")
- tell.send(sender, true)
- if (message.matches("(?i)${Pattern.quote(nick)}:.*".toRegex())) { // mobibot:
+ override fun onMessage(event: MessageEvent?) {
+ val sender = event!!.user!!.nick
+ val message = event.message
+ tell.send(event)
+ if (message.matches("(?i)${Pattern.quote(event.bot().nick)}:.*".toRegex())) { // mobibot:
+ if (logger.isTraceEnabled) logger.trace(">>> $sender: $message")
val cmds = message.substring(message.indexOf(':') + 1).trim().split(" ".toRegex(), 2)
val cmd = cmds[0].lowercase()
val args = if (cmds.size > 1) {
cmds[1].trim()
} else ""
if (cmd.startsWith(Constants.HELP_CMD)) { // mobibot: help
- helpResponse(sender, args, false)
+ helpResponse(event, args)
} else {
// Execute module or command
- addons.exec(sender, login, cmd, args, isOp(sender), false)
+ addons.exec(channel, cmd, args, event)
}
- } else {
- // Links, e.g.: https://www.example.com/ or L1: , etc.
- addons.match(sender, login, message, isOp(sender), false)
+ } else if (addons.match(channel, event)) { // Links, e.g.: https://www.example.com/ or L1: , etc.
+ if (logger.isTraceEnabled) logger.trace(">>> $sender: $message")
}
storeRecap(sender, message, false)
}
- override fun onPrivateMessage(
- sender: String,
- login: String,
- hostname: String,
- message: String
- ) {
- if (logger.isDebugEnabled) logger.debug(">>> $sender : $message")
- val cmds = message.trim().split(" ".toRegex(), 2)
- val cmd = cmds[0].lowercase()
- val args = if (cmds.size > 1) {
- cmds[1].trim()
- } else ""
- val isOp = isOp(sender)
- if (cmd.startsWith(Constants.HELP_CMD)) { // help
- helpResponse(sender, args, true)
- } else if (isOp && Constants.KILL_CMD == cmd) { // kill
- twitter.notification("$name killed by $sender on $channel")
- sendRawLine("QUIT :Poof!")
- exitProcess(0)
- } else if (isOp && Constants.DIE_CMD == cmd) { // die
- send("$sender has just signed my death sentence.")
- timer.cancel()
- twitter.shutdown()
- twitter.notification("$name stopped by $sender on $channel")
- @Suppress("MagicNumber")
- sleep(3)
- quitServer("The Bot Is Out There!")
- exitProcess(0)
- } else if (!addons.exec(sender, login, cmd, args, isOp, true)) { // Execute command or module
- helpDefault(sender, isOp, true)
- }
+ override fun onNickChange(event: NickChangeEvent?) {
+ tell.send(event!!)
}
- override fun onAction(sender: String, login: String, hostname: String, target: String, action: String) {
- if (channel == target) {
- storeRecap(sender, action, true)
- }
- }
-
- override fun onJoin(channel: String, sender: String, login: String, hostname: String) {
- tell.send(sender)
- }
-
- override fun onNickChange(oldNick: String, login: String, hostname: String, newNick: String) {
- tell.send(newNick)
- }
-
- /**
- * Sends a private message or notice.
- */
- fun send(sender: String, message: String?, isPrivate: Boolean) {
- if (message != null && sender.isNotBlank()) {
- if (isPrivate) {
- if (logger.isDebugEnabled) logger.debug("Sending message to $sender : $message")
- sendMessage(sender, message)
- } else {
- if (logger.isDebugEnabled) logger.debug("Sending notice to $sender: $message")
- sendNotice(sender, message)
+ override fun onPart(event: PartEvent?) {
+ with(event!!.getBot()) {
+ if (event.user!!.nick == nick) {
+ LinksMgr.twitter.notification("$nick has left ${event.channel.name} on irc://$serverHostname")
}
}
}
- /**
- * Sends a notice to the channel.
- */
- fun send(notice: String?) {
- notice?.let { send(channel, it, false) }
- }
-
- /**
- * Sends a message.
- */
- fun send(who: String, message: Message) {
- send(if (message.isNotice) who else channel, message.msg, message.color, message.isPrivate)
- }
-
- /**
- * Sends a message.
- */
- fun send(who: String, message: String, color: String, isPrivate: Boolean) {
- send(who, colorize(message, color), isPrivate)
- }
-
- /**
- * Send a formatted commands/modules, etc. list.
- */
- @JvmOverloads
- fun sendList(
- nick: String,
- list: List,
- maxPerLine: Int,
- separator: String = " ",
- isPrivate: Boolean,
- isBold: Boolean = false,
- isIndent: Boolean = false
- ) {
- var i = 0
- while (i < list.size) {
- send(
- nick,
- helpFormat(
- list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""),
- isBold,
- isIndent
- ),
- isPrivate
- )
- i += maxPerLine
- }
- }
-
- /**
- * Sets the pinboard authentication.
- */
- private fun setPinboardAuth(apiToken: String) {
- if (apiToken.isNotBlank()) {
- pinboard.apiToken = apiToken
- isPinboardEnabled = true
- if (logger.isDebugEnabled) {
- val consoleHandler = ConsoleHandler()
- consoleHandler.level = java.util.logging.Level.FINE
- pinboard.logger.addHandler(consoleHandler)
- pinboard.logger.level = java.util.logging.Level.FINE
- }
- }
- }
-
- /**
- * Shutdown the bot.
- */
- fun shutdown(sender: String, now: Boolean = false) {
- if (now) { // kill
- twitter.notification("$name killed by $sender on $channel")
- sendRawLine("QUIT :Poof!")
- } else {
- timer.cancel()
- twitter.shutdown()
- twitter.notification("$name stopped by $sender on $channel")
- @Suppress("MagicNumber")
- sleep(3)
- quitServer("The Bot Is Out There!")
- }
- exitProcess(0)
- }
-
- /**
- * Sleeps for the specified number of seconds.
- */
- fun sleep(secs: Int) {
- try {
- @Suppress("MagicNumber")
- Thread.sleep(secs * 1000L)
- } catch (ignore: InterruptedException) {
- // Do nothing
- }
- }
-
- /**
- * Updates pin on pinboard.
- */
- fun updatePin(oldUrl: String, entry: EntryLink) {
- if (isPinboardEnabled) {
- PinboardUtils.updatePin(pinboard, ircServer, oldUrl, entry)
- }
- }
-
- /**
- * Returns the bot's version.
- */
- override fun onVersion(sourceNick: String, sourceLogin: String, sourceHostname: String, target: String) {
- sendRawLine("NOTICE $sourceNick :\u0001VERSION ${ReleaseInfo.PROJECT} ${ReleaseInfo.VERSION}\u0001")
- }
-
companion object {
- // Maximum number of times the bot will try to reconnect, if disconnected
- private const val MAX_RECONNECT = 10
-
- /**
- * The Truth is Out There!
- */
+ @Throws(Exception::class)
@JvmStatic
fun main(args: Array) {
// Set up the command line options
@@ -593,7 +307,7 @@ class Mobibot(nickname: String, channel: String, logsDirPath: String, p: Propert
val stdout = PrintStream(
BufferedOutputStream(
FileOutputStream(
- logsDir + channel.substring(1) + '.' + today() + ".log", true
+ logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true
)
), true
)
@@ -615,11 +329,8 @@ class Mobibot(nickname: String, channel: String, logsDirPath: String, p: Propert
}
}
- // Create the bot
- val bot = Mobibot(nickname, channel, logsDir, p)
-
- // Connect
- bot.connect()
+ // Start the bot
+ Mobibot(nickname, channel, logsDir, p).connect()
}
}
}
@@ -629,97 +340,93 @@ class Mobibot(nickname: String, channel: String, logsDirPath: String, p: Propert
* Initialize the bot.
*/
init {
- System.getProperties().setProperty("sun.net.client.defaultConnectTimeout", Constants.CONNECT_TIMEOUT.toString())
- System.getProperties().setProperty("sun.net.client.defaultReadTimeout", Constants.CONNECT_TIMEOUT.toString())
-
- name = nickname
- ircServer = p.getProperty("server", Constants.DEFAULT_SERVER)
- ircPort = p.getIntProperty("port", Constants.DEFAULT_PORT)
this.channel = channel
- logsDir = logsDirPath
+ val ircServer = p.getProperty("server", Constants.DEFAULT_SERVER)
+ config = Configuration.Builder().apply {
+ name = nickname
+ login = p.getProperty("login", nickname)
+ realName = p.getProperty("realname", nickname)
+ addServer(
+ ircServer,
+ p.getIntProperty("port", Constants.DEFAULT_PORT)
+ )
+ addAutoJoinChannel(channel)
+ addListener(this@Mobibot)
+ version = "${ReleaseInfo.PROJECT} ${ReleaseInfo.VERSION}"
+ isAutoNickChange = true
+ val identPwd = p.getProperty("ident")
+ if (!identPwd.isNullOrBlank()) {
+ nickservPassword = identPwd
+ }
+ val identNick = p.getProperty("ident-nick")
+ if (!identNick.isNullOrBlank()) {
+ nickservNick = identNick
+ }
+ val identMsg = p.getProperty("ident-msg")
+ if (!identMsg.isNullOrBlank()) {
+ nickservCustomMessage = identMsg
+ }
+ isAutoReconnect = true
+ //socketConnectTimeout = Constants.CONNECT_TIMEOUT
+ //socketTimeout = Constants.CONNECT_TIMEOUT
+ //messageDelay = StaticDelay(500)
+ }.buildConfiguration()
- // Store the default logger level
- loggerLevel = logger.level
+ // Load the current entries
+ with(LinksMgr) {
+ entries.channel = channel
+ entries.ircServer = ircServer
+ entries.logsDir = logsDirPath
+ entries.backlogs = p.getProperty("backlogs", "")
+ entries.load()
- setVerbose(true)
- setAutoNickChange(true)
- login = p.getProperty("login", name)
- // Set the real name
- version = ReleaseInfo.PROJECT
- // setMessageDelay(1000);
-
- // Set NICKSERV identification
- identPwd = p.getProperty("ident", "")
- identNick = p.getProperty("ident-nick", "")
- identMsg = p.getProperty("ident-msg", "")
-
- // Set the URLs
- weblogUrl = p.getProperty("weblog", "")
- backlogsUrl = p.getProperty("backlogs", weblogUrl).appendIfMissing('/')
-
- // Load the current entries and backlogs, if any
- try {
- LinksMgr.startup(logsDir + EntriesMgr.CURRENT_XML, logsDir + EntriesMgr.NAV_XML, this.channel)
- if (logger.isDebugEnabled) logger.debug("Last feed: ${LinksMgr.startDate}")
- } catch (e: Exception) {
- if (logger.isErrorEnabled) logger.error("An error occurred while loading the logs.", e)
+ // Set up pinboard
+ pinboard.setApiToken(p.getProperty("pinboard-api-token", ""))
}
- // Set the pinboard authentication
- setPinboardAuth(p.getProperty("pinboard-api-token", ""))
-
// Load the commands
- addons.add(AddLog(this), p)
- addons.add(ChannelFeed(this, channelName), p)
- addons.add(Cycle(this), p)
- addons.add(Die(this), p)
- addons.add(Debug(this), p)
- addons.add(Ignore(this), p)
- addons.add(Info(this), p)
- addons.add(Kill(this), p)
- addons.add(Me(this), p)
- addons.add(Modules(this), p)
- addons.add(Msg(this), p)
- addons.add(Nick(this), p)
- addons.add(Recap(this), p)
- addons.add(Say(this), p)
- addons.add(Users(this), p)
- addons.add(Versions(this), p)
+ addons.add(ChannelFeed(channel.removePrefix("#")), p)
+ addons.add(Comment(), p)
+ addons.add(Cycle(), p)
+ addons.add(Die(), p)
+ addons.add(Ignore(), p)
+ addons.add(LinksMgr(), p)
+ addons.add(Me(), p)
+ addons.add(Msg(), p)
+ addons.add(Nick(), p)
+ addons.add(Posting(), p)
+ addons.add(Recap(), p)
+ addons.add(Say(), p)
+ addons.add(Tags(), p)
// Tell command
- tell = Tell(this)
+ tell = Tell("${logsDirPath}${nickname}.ser")
addons.add(tell, p)
- // Load the links commands
- addons.add(Comment(this), p)
- addons.add(Posting(this), p)
- addons.add(Tags(this), p)
- addons.add(LinksMgr(this), p)
- addons.add(View(this), p)
+ addons.add(LinksMgr.twitter, p)
+ addons.add(Users(), p)
+ addons.add(Versions(), p)
+ addons.add(View(), p)
// Load the modules
- addons.add(Calc(this), p)
- addons.add(CryptoPrices(this), p)
- addons.add(CurrencyConverter(this), p)
- addons.add(Dice(this), p)
- addons.add(GoogleSearch(this), p)
- addons.add(Joke(this), p)
- addons.add(Lookup(this), p)
- addons.add(Ping(this), p)
- addons.add(RockPaperScissors(this), p)
- addons.add(StockQuote(this), p)
- addons.add(War(this), p)
- addons.add(Weather2(this), p)
- addons.add(WorldTime(this), p)
-
- // Twitter module
- twitter = Twitter(this)
- addons.add(twitter, p)
+ addons.add(Calc(), p)
+ addons.add(CryptoPrices(), p)
+ addons.add(CurrencyConverter(), p)
+ addons.add(Dice(), p)
+ addons.add(GoogleSearch(), p)
+ addons.add(Info(tell), p)
+ addons.add(Joke(), p)
+ addons.add(Lookup(), p)
+ addons.add(Modules(addons.modulesNames), p)
+ addons.add(Ping(), p)
+ addons.add(RockPaperScissors(), p)
+ addons.add(StockQuote(), p)
+ addons.add(Weather2(), p)
+ addons.add(WorldTime(), p)
+ addons.add(War(), p)
// Sort the addons
addons.sort()
-
- // Save the entries
- LinksMgr.saveEntries(this, true)
}
}
+
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/PinboardUtils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt
similarity index 63%
rename from src/main/kotlin/net/thauvin/erik/mobibot/PinboardUtils.kt
rename to src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt
index 2d91b64..8083c74 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/PinboardUtils.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt
@@ -1,5 +1,5 @@
/*
- * PinboardUtils.kt
+ * Pinboard.kt
*
* Copyright (c) 2004-2021, Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
@@ -45,33 +45,44 @@ import java.util.Date
/**
* Handles posts to pinboard.in.
*/
-object PinboardUtils {
+class Pinboard {
+ private val poster = PinboardPoster()
+
/**
* Adds a pin.
*/
- @JvmStatic
- fun addPin(poster: PinboardPoster, ircServer: String, entry: EntryLink) {
- runBlocking {
- launch {
- poster.addPin(
- entry.link,
- entry.title,
- entry.postedBy(ircServer),
- entry.pinboardTags,
- entry.date.toTimestamp()
- )
+ fun addPin(ircServer: String, entry: EntryLink) {
+ if (poster.apiToken.isNotBlank()) {
+ runBlocking {
+ launch {
+ poster.addPin(
+ entry.link,
+ entry.title,
+ entry.postedBy(ircServer),
+ entry.pinboardTags,
+ entry.date.toTimestamp()
+ )
+ }
}
}
}
+ /**
+ * Sets the pinboard API token.
+ */
+ fun setApiToken(apiToken: String) {
+ poster.apiToken = apiToken
+ }
+
/**
* Deletes a pin.
*/
- @JvmStatic
- fun deletePin(poster: PinboardPoster, entry: EntryLink) {
- runBlocking {
- launch {
- poster.deletePin(entry.link)
+ fun deletePin(entry: EntryLink) {
+ if (poster.apiToken.isNotBlank()) {
+ runBlocking {
+ launch {
+ poster.deletePin(entry.link)
+ }
}
}
}
@@ -79,30 +90,15 @@ object PinboardUtils {
/**
* Updates a pin.
*/
- @JvmStatic
- fun updatePin(poster: PinboardPoster, ircServer: String, oldUrl: String, entry: EntryLink) {
- runBlocking {
- launch {
- with(entry) {
- if (oldUrl != link) {
- poster.deletePin(oldUrl)
- poster.addPin(
- link,
- title,
- entry.postedBy(ircServer),
- pinboardTags,
- date.toTimestamp()
- )
- } else {
- poster.addPin(
- link,
- title,
- entry.postedBy(ircServer),
- pinboardTags,
- date.toTimestamp(),
- replace = true,
- shared = true
- )
+ fun updatePin(ircServer: String, oldUrl: String, entry: EntryLink) {
+ if (poster.apiToken.isNotBlank()) {
+ runBlocking {
+ launch {
+ with(entry) {
+ if (oldUrl != link) {
+ poster.deletePin(oldUrl)
+ }
+ poster.addPin(link, title, entry.postedBy(ircServer), pinboardTags, date.toTimestamp())
}
}
}
@@ -112,8 +108,7 @@ object PinboardUtils {
/**
* Format a date to a UTC timestamp.
*/
- @JvmStatic
- fun Date.toTimestamp(): String {
+ private fun Date.toTimestamp(): String {
return ZonedDateTime.ofInstant(
this.toInstant().truncatedTo(ChronoUnit.SECONDS),
ZoneId.systemDefault()
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt b/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt
index 31bde39..a96b491 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/TwitterOAuth.kt
@@ -95,7 +95,6 @@ object TwitterOAuth {
""".trimIndent()
)
} catch (te: TwitterException) {
- @Suppress("MagicNumber")
if (401 == te.statusCode) {
println("Unable to get the access token.")
} else {
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/TwitterTimer.kt b/src/main/kotlin/net/thauvin/erik/mobibot/TwitterTimer.kt
index 6b3a4b3..374f301 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/TwitterTimer.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/TwitterTimer.kt
@@ -32,10 +32,11 @@
package net.thauvin.erik.mobibot
+import net.thauvin.erik.mobibot.modules.Twitter
import java.util.TimerTask
-class TwitterTimer(var bot: Mobibot, private var index: Int) : TimerTask() {
+class TwitterTimer(private var twitter: Twitter, private var index: Int) : TimerTask() {
override fun run() {
- bot.twitter.postEntry(index)
+ twitter.postEntry(index)
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt
index a16c01b..6f75788 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt
@@ -31,9 +31,13 @@
*/
package net.thauvin.erik.mobibot
+import net.thauvin.erik.mobibot.msg.Message
import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR
-import org.jibble.pircbot.Colors
import org.jsoup.Jsoup
+import org.pircbotx.Colors
+import org.pircbotx.PircBotX
+import org.pircbotx.hooks.events.PrivateMessageEvent
+import org.pircbotx.hooks.types.GenericMessageEvent
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
@@ -85,6 +89,13 @@ object Utils {
@JvmStatic
fun bold(s: String?): String = colorize(s, Colors.BOLD)
+ /**
+ * Returns the [PircBotX] instance.
+ */
+ fun GenericMessageEvent.bot(): PircBotX {
+ return getBot() as PircBotX
+ }
+
/**
* Build a help command by replacing `%c` with the bot's pub/priv command, and `%n` with the bot's
* nick.
@@ -159,6 +170,14 @@ object Utils {
return if (isIndent) s.prependIndent() else s
}
+ /**
+ * Returns {@code true} if the specified user is an operator on the [channel].
+ */
+ @JvmStatic
+ fun isChannelOp(channel: String, event: GenericMessageEvent): Boolean {
+ return event.bot().userChannelDao.getChannel(channel).isOp(event.user)
+ }
+
/**
* Obfuscates the given string.
*/
@@ -203,6 +222,56 @@ object Utils {
@JvmStatic
fun reverseColor(s: String?): String = colorize(s, Colors.REVERSE)
+ /**
+ * Send a formatted commands/modules, etc. list.
+ */
+ @JvmStatic
+ fun GenericMessageEvent.sendList(
+ list: List,
+ maxPerLine: Int,
+ separator: String = " ",
+ isBold: Boolean = false,
+ isIndent: Boolean = false
+ ) {
+ var i = 0
+ while (i < list.size) {
+ sendMessage(
+ helpFormat(
+ list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""),
+ isBold,
+ isIndent
+ ),
+ )
+ i += maxPerLine
+ }
+ }
+
+ /**
+ * Sends a [message].
+ */
+ @JvmStatic
+ fun GenericMessageEvent.sendMessage(channel: String, message: Message) {
+ if (message.isNotice) {
+ bot().sendIRC().notice(user.nick, colorize(message.msg, message.color))
+ } else if (message.isPrivate || this is PrivateMessageEvent || channel.isBlank()) {
+ respondPrivateMessage(colorize(message.msg, message.color))
+ } else {
+ bot().sendIRC().message(channel, colorize(message.msg, message.color))
+ }
+ }
+
+ /**
+ * Sends a response as a private message or notice.
+ */
+ @JvmStatic
+ fun GenericMessageEvent.sendMessage(message: String) {
+ if (this is PrivateMessageEvent) {
+ respondPrivateMessage(message)
+ } else {
+ bot().sendIRC().notice(user.nick, message)
+ }
+ }
+
/**
* Returns today's date.
*/
@@ -258,7 +327,6 @@ object Utils {
/**
* Converts milliseconds to year month week day hour and minutes.
*/
- @Suppress("MagicNumber")
@JvmStatic
fun uptime(uptime: Long): String {
val info = StringBuilder()
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt
index 7675fe5..425f309 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt
@@ -32,31 +32,31 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.buildCmdSyntax
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import net.thauvin.erik.mobibot.Utils.sendMessage
+import org.pircbotx.hooks.events.PrivateMessageEvent
+import org.pircbotx.hooks.types.GenericMessageEvent
import java.util.concurrent.ConcurrentHashMap
-abstract class AbstractCommand(val bot: Mobibot) {
+abstract class AbstractCommand {
abstract val name: String
abstract val help: List
- abstract val isOp: Boolean
+ abstract val isOpOnly: Boolean
abstract val isPublic: Boolean
abstract val isVisible: Boolean
val properties: MutableMap = ConcurrentHashMap()
- abstract fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- )
+ abstract fun commandResponse(channel: String, args: String, event: GenericMessageEvent)
- open fun helpResponse(command: String, sender: String, isOp: Boolean, isPrivate: Boolean): Boolean {
- if (!this.isOp || this.isOp == isOp) {
+ open fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean {
+ if (!isOpOnly || isOpOnly == isChannelOp(channel, event)) {
for (h in help) {
- bot.send(sender, buildCmdSyntax(h, bot.nick, isPrivate), isPrivate)
+ event.sendMessage(
+ buildCmdSyntax(h, event.bot().nick, event is PrivateMessageEvent || !isPublic),
+ )
}
return true
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AddLog.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AddLog.kt
deleted file mode 100644
index f13aa4d..0000000
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AddLog.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * AddLog.kt
- *
- * Copyright (c) 2004-2021, Erik C. Thauvin (erik@thauvin.net)
- * All rights reserved.
- *
- * 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.commands
-
-import net.thauvin.erik.mobibot.Mobibot
-
-import net.thauvin.erik.mobibot.commands.links.LinksMgr.Companion.history
-import net.thauvin.erik.mobibot.entries.EntriesMgr
-import java.io.File
-
-class AddLog(bot: Mobibot) : AbstractCommand(bot) {
- override val name = "addlog"
- override val help = emptyList()
- override val isOp = true
- override val isPublic = false
- override val isVisible = false
-
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- if (isOp) {
- if (args.isNotBlank()) {
- // e.g: 2014-04-01
- val backlog = File("${bot.logsDir}$args${EntriesMgr.XML_EXT}")
- if (backlog.exists()) {
- history.add(0, args)
- } else {
- bot.send(sender, "The specified log could not be found.", isPrivate)
- return
- }
- }
- @Suppress("MagicNumber")
- bot.sendList(sender, history, 4, isPrivate = isPrivate, isIndent = true)
- }
- }
-}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt
index 8dbe942..5ac8d7f 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt
@@ -35,13 +35,14 @@ package net.thauvin.erik.mobibot.commands
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import net.thauvin.erik.mobibot.FeedReader
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendMessage
+import org.pircbotx.hooks.types.GenericMessageEvent
-class ChannelFeed(bot: Mobibot, channel: String) : AbstractCommand(bot) {
+class ChannelFeed(channel: String) : AbstractCommand() {
override val name = channel
override val help = listOf("To list the last 5 posts from the channel's weblog feed:", helpFormat("%c $channel"))
- override val isOp = false
+ override val isOpOnly = false
override val isPublic = true
override val isVisible = true
@@ -53,22 +54,16 @@ class ChannelFeed(bot: Mobibot, channel: String) : AbstractCommand(bot) {
initProperties(FEED_PROP)
}
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
with(properties[FEED_PROP]) {
if (!isNullOrBlank()) {
runBlocking {
launch {
- FeedReader(bot, sender, this@with).run()
+ FeedReader(this@with, event).run()
}
}
} else {
- bot.send(sender, "There is no feed setup for this channel.", false)
+ event.sendMessage("There is no feed setup for this channel.")
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt
index 88de89b..e5b019d 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt
@@ -32,35 +32,33 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Cycle(bot: Mobibot) : AbstractCommand(bot) {
- @Suppress("MagicNumber")
+class Cycle : AbstractCommand() {
private val wait = 10
override val name = "cycle"
override val help = listOf("To have the bot leave the channel and come back:", helpFormat("%c $name"))
- override val isOp = true
+ override val isOpOnly = true
override val isPublic = false
override val isVisible = true
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- with(bot) {
- if (isOp) {
- send("$sender has just asked me to leave. I'll be back!")
- sleep(wait)
- partChannel(channel)
- sleep(wait)
- joinChannel(channel)
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
+ with(event.bot()) {
+ if (isChannelOp(channel, event)) {
+ runBlocking {
+ sendIRC().message(channel, "${event.user.nick} asked me to leave. I'll be back!")
+ userChannelDao.getChannel(channel).send().part()
+ delay(wait * 1000L)
+ sendIRC().joinChannel(channel)
+ }
} else {
- helpDefault(sender, isOp, isPrivate)
+ helpResponse(channel, args, event)
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Debug.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Debug.kt
deleted file mode 100644
index 8c3c97b..0000000
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Debug.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Debug.kt
- *
- * Copyright (c) 2004-2021, Erik C. Thauvin (erik@thauvin.net)
- * All rights reserved.
- *
- * 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.commands
-
-import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Mobibot
-import org.apache.logging.log4j.Level
-import org.apache.logging.log4j.core.config.Configurator
-
-class Debug(bot: Mobibot) : AbstractCommand(bot) {
- override val name = Constants.DEBUG_CMD
- override val help = emptyList()
- override val isOp = true
- override val isPublic = false
- override val isVisible = false
-
- override fun commandResponse(sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean) {
- if (isOp) {
- with(bot) {
- if (logger.isDebugEnabled) {
- Configurator.setLevel(logger.name, loggerLevel)
- } else {
- Configurator.setLevel(logger.name, Level.DEBUG)
- }
- send(sender, "Debug logging is " + if (logger.isDebugEnabled) "enabled." else "disabled.", true)
- }
- }
- }
-}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt
index c9c6299..df715c4 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt
@@ -32,25 +32,35 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Die(bot: Mobibot) : AbstractCommand(bot) {
+class Die : AbstractCommand() {
override val name = "die"
override val help = emptyList()
- override val isOp = true
+ override val isOpOnly = true
override val isPublic = false
override val isVisible = false
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- if (isOp) {
- bot.send("$sender has just signed my death sentence.")
- bot.shutdown(sender)
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
+ with(event.bot()) {
+ if (isChannelOp(channel, event) && (properties[DIE_PROP].isNullOrBlank() || args == properties[DIE_PROP])) {
+ sendIRC().message(channel, "${event.user?.nick} has just signed my death sentence.")
+ stopBotReconnect()
+ sendIRC().quitServer("The Bot is Out There!")
+ }
}
}
+
+ companion object {
+ /**
+ * Max days property.
+ */
+ const val DIE_PROP = "die"
+ }
+
+ init {
+ initProperties(DIE_PROP)
+ }
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt
index 7ae45a2..d1e38ce 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt
@@ -32,13 +32,17 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.bold
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.buildCmdSyntax
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import net.thauvin.erik.mobibot.Utils.sendList
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.commands.links.LinksMgr
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Ignore(bot: Mobibot) : AbstractCommand(bot) {
+class Ignore : AbstractCommand() {
private val me = "me"
init {
@@ -58,7 +62,7 @@ class Ignore(bot: Mobibot) : AbstractCommand(bot) {
arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name [ ...]"))
)
- override val isOp = false
+ override val isOpOnly = false
override val isPublic = true
override val isVisible = true
@@ -73,56 +77,45 @@ class Ignore(bot: Mobibot) : AbstractCommand(bot) {
}
}
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
val isMe = args.trim().equals(me, true)
- if (isMe || !isOp) {
- val nick = sender.lowercase()
- ignoreNick(bot, nick, isMe, isPrivate)
+ if (isMe || !isChannelOp(channel, event)) {
+ val nick = event.user.nick.lowercase()
+ ignoreNick(nick, isMe, event)
} else {
- ignoreOp(bot, sender, args, isPrivate)
+ ignoreOp(args, event)
}
}
- override fun helpResponse(
- command: String,
- sender: String,
- isOp: Boolean,
- isPrivate: Boolean
- ): Boolean {
- return if (isOp) {
+ override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean {
+ return if (isChannelOp(channel, event)) {
for (h in helpOp) {
- bot.send(sender, buildCmdSyntax(h, bot.nick, isPrivate), isPrivate)
+ event.sendMessage(buildCmdSyntax(h, event.bot().nick, true))
}
true
} else {
- super.helpResponse(command, sender, isOp, isPrivate)
+ super.helpResponse(channel, topic, event)
}
}
- private fun ignoreNick(bot: Mobibot, sender: String, isMe: Boolean, isPrivate: Boolean) {
+ private fun ignoreNick(sender: String, isMe: Boolean, event: GenericMessageEvent) {
if (isMe) {
if (ignored.remove(sender)) {
- bot.send(sender, "You are no longer ignored.", isPrivate)
+ event.sendMessage("You are no longer ignored.")
} else {
ignored.add(sender)
- bot.send(sender, "You are now ignored.", isPrivate)
+ event.sendMessage("You are now ignored.")
}
} else {
if (ignored.contains(sender)) {
- bot.send(sender, "You are currently ignored.", isPrivate)
+ event.sendMessage("You are currently ignored.")
} else {
- bot.send(sender, "You are not currently ignored.", isPrivate)
+ event.sendMessage("You are not currently ignored.")
}
}
}
- private fun ignoreOp(bot: Mobibot, sender: String, args: String, isPrivate: Boolean) {
+ private fun ignoreOp(args: String, event: GenericMessageEvent) {
if (args.isNotEmpty()) {
val nicks = args.lowercase().split(" ")
for (nick in nicks) {
@@ -138,11 +131,10 @@ class Ignore(bot: Mobibot) : AbstractCommand(bot) {
}
if (ignored.size > 0) {
- bot.send(sender, "The following nicks are ignored:", isPrivate)
- @Suppress("MagicNumber")
- bot.sendList(sender, ignored.sorted(), 8, isPrivate = isPrivate, isIndent = true)
+ event.sendMessage("The following nicks are ignored:")
+ event.sendList(ignored.sorted(), 8, isIndent = true)
} else {
- bot.send(sender, "No one is currently ${bold("ignored")}.", isPrivate)
+ event.sendMessage("No one is currently ${bold("ignored")}.")
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt
index bffd1f2..a383756 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt
@@ -31,50 +31,46 @@
*/
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.ReleaseInfo
import net.thauvin.erik.mobibot.Utils.capitalise
import net.thauvin.erik.mobibot.Utils.green
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import net.thauvin.erik.mobibot.Utils.sendList
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.Utils.uptime
import net.thauvin.erik.mobibot.commands.links.LinksMgr
+import net.thauvin.erik.mobibot.commands.tell.Tell
+import org.pircbotx.hooks.types.GenericMessageEvent
import java.lang.management.ManagementFactory
-class Info(bot: Mobibot?) : AbstractCommand(bot!!) {
+class Info(private val tell: Tell) : AbstractCommand() {
private val allVersions = listOf(
"${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${green(ReleaseInfo.WEBSITE)})",
"Written by ${ReleaseInfo.AUTHOR} (${green(ReleaseInfo.AUTHOR_URL)})"
)
override val name = "info"
override val help = listOf("To view information about the bot:", helpFormat("%c $name"))
- override val isOp = false
+ override val isOpOnly = false
override val isPublic = true
override val isVisible = true
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- with(bot) {
- sendList(sender, allVersions, 1, isPrivate = isPrivate)
- val info = StringBuilder()
- info.append("Uptime: ")
- .append(uptime(ManagementFactory.getRuntimeMXBean().uptime))
- .append(" [Entries: ")
- .append(LinksMgr.entries.size)
- if (isOp) {
- if (tell.isEnabled()) {
- info.append(", Messages: ").append(tell.size())
- }
- if (twitter.isAutoPost) {
- info.append(", Twitter: ").append(twitter.entriesCount())
- }
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
+ event.sendList(allVersions, 1)
+ val info = StringBuilder()
+ info.append("Uptime: ")
+ .append(uptime(ManagementFactory.getRuntimeMXBean().uptime))
+ .append(" [Entries: ")
+ .append(LinksMgr.entries.links.size)
+ if (isChannelOp(channel, event)) {
+ if (tell.isEnabled()) {
+ info.append(", Messages: ").append(tell.size())
+ }
+ if (LinksMgr.twitter.isAutoPost) {
+ info.append(", Twitter: ").append(LinksMgr.twitter.entriesCount())
}
- info.append(", Recap: ").append(Recap.recaps.size).append(']')
- send(sender, info.toString(), isPrivate)
}
+ info.append(", Recap: ").append(Recap.recaps.size).append(']')
+ event.sendMessage(info.toString())
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt
index 4b996f1..7a85f4f 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt
@@ -32,27 +32,21 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Me(bot: Mobibot) : AbstractCommand(bot) {
+class Me : AbstractCommand() {
override val name = "me"
override val help = listOf("To have the bot perform an action:", helpFormat("%c $name "))
- override val isOp = true
+ override val isOpOnly = true
override val isPublic = false
override val isVisible = true
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- if (isOp) {
- bot.action(args)
- } else {
- bot.helpDefault(sender, isOp, isPrivate)
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
+ if (isChannelOp(channel, event)) {
+ event.bot().sendIRC().action(channel, args)
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt
index 3bd2db1..36a4baf 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt
@@ -32,35 +32,29 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import net.thauvin.erik.mobibot.Utils.sendList
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Modules(bot: Mobibot) : AbstractCommand(bot) {
+class Modules(private val modulesNames: List) : AbstractCommand() {
override val name = "modules"
override val help = listOf("To view a list of enabled modules:", helpFormat("%c $name"))
- override val isOp = true
+ override val isOpOnly = true
override val isPublic = false
override val isVisible = true
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- with(bot) {
- if (isOp) {
- if (modulesNames.isEmpty()) {
- send(sender, "There are no enabled modules.", isPrivate)
- } else {
- send(sender, "The enabled modules are: ", isPrivate)
- @Suppress("MagicNumber")
- sendList(sender, modulesNames, 7, isPrivate = isPrivate, isIndent = true)
- }
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
+ if (isChannelOp(channel, event)) {
+ if (modulesNames.isEmpty()) {
+ event.respondPrivateMessage("There are no enabled modules.")
} else {
- helpDefault(sender, isOp, isPrivate)
+ event.respondPrivateMessage("The enabled modules are: ")
+ event.sendList(modulesNames, 7, isIndent = true)
}
+ } else {
+ helpResponse(channel, args, event)
}
}
}
+
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt
index 5e9b5ae..edd9cc9 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt
@@ -32,35 +32,30 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Msg(bot: Mobibot) : AbstractCommand(bot) {
+class Msg : AbstractCommand() {
override val name = "msg"
override val help = listOf(
"To have the bot send a private message to someone:",
helpFormat("%c $name ")
)
- override val isOp = true
- override val isPublic = true
+ override val isOpOnly = true
+ override val isPublic = false
override val isVisible = true
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- if (isOp) {
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
+ if (isChannelOp(channel, event)) {
val msg = args.split(" ", limit = 2)
if (args.length > 2) {
- bot.send(msg[0], msg[1], isPrivate)
+ event.bot().sendIRC().message(msg[0], msg[1])
+ event.respondPrivateMessage("A message was sent to ${msg[0]}")
} else {
- helpResponse(name, sender, isOp, isPrivate)
+ helpResponse(channel, args, event)
}
- } else {
- bot.helpDefault(sender, isOp, isPrivate)
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt
index 2f956e2..c8275dd 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt
@@ -32,27 +32,21 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Nick(bot: Mobibot) : AbstractCommand(bot) {
+class Nick : AbstractCommand() {
override val name = "nick"
override val help = listOf("To change the bot's nickname:", helpFormat("%c $name "))
- override val isOp = true
+ override val isOpOnly = true
override val isPublic = true
override val isVisible = true
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- if (isOp) {
- bot.changeNick(args)
- } else {
- bot.helpDefault(sender, isOp, isPrivate)
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
+ if (isChannelOp(channel, event)) {
+ event.bot().sendIRC().changeNick(args)
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt
index 5912ff4..03b349c 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt
@@ -32,19 +32,20 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.Utils.toUtcDateTime
+import org.pircbotx.hooks.types.GenericMessageEvent
import java.time.Clock
import java.time.LocalDateTime
-class Recap(bot: Mobibot) : AbstractCommand(bot) {
+class Recap : AbstractCommand() {
override val name = "recap"
override val help = listOf(
"To list the last 10 public channel messages:",
helpFormat("%c $name")
)
- override val isOp = false
+ override val isOpOnly = false
override val isPublic = true
override val isVisible = true
@@ -61,26 +62,19 @@ class Recap(bot: Mobibot) : AbstractCommand(bot) {
LocalDateTime.now(Clock.systemUTC()).toUtcDateTime()
+ " - $sender" + (if (isAction) " " else ": ") + message
)
- @Suppress("MagicNumber")
if (recaps.size > 10) {
recaps.removeFirst()
}
}
}
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
if (recaps.isNotEmpty()) {
for (r in recaps) {
- bot.send(sender, r, isPrivate)
+ event.sendMessage(r)
}
} else {
- bot.send(sender, "Sorry, nothing to recap.", isPrivate)
+ event.sendMessage("Sorry, nothing to recap.")
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt
index 198ea8c..a89c64e 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt
@@ -32,28 +32,22 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Say(bot: Mobibot) : AbstractCommand(bot) {
+class Say : AbstractCommand() {
override val name = "say"
override val help = listOf("To have the bot say something on the channel:", helpFormat("%c $name "))
- override val isOp = true
+ override val isOpOnly = true
override val isPublic = false
override val isVisible = true
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- if (isOp) {
- bot.send(args)
- } else {
- bot.helpDefault(sender, isOp, isPrivate)
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
+ if (isChannelOp(channel, event)) {
+ event.bot().sendIRC().message(channel, args)
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt
index 82f5277..5133146 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt
@@ -32,36 +32,29 @@
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendList
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Users(bot: Mobibot) : AbstractCommand(bot) {
+class Users : AbstractCommand() {
override val name = "users"
override val help = listOf("To list the users present on the channel:", helpFormat("%c $name"))
- override val isOp = false
+ override val isOpOnly = false
override val isPublic = true
override val isVisible = true
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
val nicks = mutableListOf()
- with(bot) {
- getUsers(channel).forEach { user ->
- if (isOp(user.nick)) {
- nicks.add("@${user.nick}")
- } else {
- nicks.add(user.nick)
- }
+ val ch = event.bot().userChannelDao.getChannel(channel)
+ ch.users.forEach {
+ if (it.channelsOpIn.contains(ch)) {
+ nicks.add("@${it.nick}")
+ } else {
+ nicks.add(it.nick)
}
-
- @Suppress("MagicNumber")
- sendList(sender, nicks.sorted(), 8, isPrivate = isPrivate, isIndent = true)
}
+ event.sendList(nicks, 8)
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt
index 1712add..f7fa866 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt
@@ -31,12 +31,14 @@
*/
package net.thauvin.erik.mobibot.commands
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.ReleaseInfo
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import net.thauvin.erik.mobibot.Utils.sendList
import net.thauvin.erik.mobibot.Utils.toIsoLocalDate
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Versions(bot: Mobibot) : AbstractCommand(bot) {
+class Versions : AbstractCommand() {
private val allVersions = listOf(
"Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})",
"Platform: " + System.getProperty("os.name") + ' ' + System.getProperty("os.version")
@@ -45,21 +47,13 @@ class Versions(bot: Mobibot) : AbstractCommand(bot) {
)
override val name = "versions"
override val help = listOf("To view the versions data (bot, platform, java, etc.):", helpFormat("%c $name"))
- override val isOp = true
+ override val isOpOnly = true
override val isPublic = false
override val isVisible = true
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- if (isOp) {
- bot.sendList(sender, allVersions, 1, isPrivate = isPrivate)
- } else {
- bot.helpDefault(sender, false, isPrivate)
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
+ if (isChannelOp(channel, event)) {
+ event.sendList(allVersions, 1)
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt
index 2bfc57b..61143fb 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt
@@ -33,14 +33,16 @@
package net.thauvin.erik.mobibot.commands.links
import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.bold
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.entries.EntriesUtils
import net.thauvin.erik.mobibot.entries.EntryLink
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Comment(bot: Mobibot) : AbstractCommand(bot) {
+class Comment : AbstractCommand() {
override val name = COMMAND
override val help = listOf(
"To add a comment:",
@@ -51,7 +53,7 @@ class Comment(bot: Mobibot) : AbstractCommand(bot) {
"To delete a comment, use its label and a minus sign: ",
helpFormat("${Constants.LINK_CMD}1.1:-")
)
- override val isOp = false
+ override val isOpOnly = false
override val isPublic = true
override val isVisible = true
@@ -59,29 +61,22 @@ class Comment(bot: Mobibot) : AbstractCommand(bot) {
const val COMMAND = "comment"
}
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- @Suppress("MagicNumber")
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
val cmds = args.substring(1).split("[.:]".toRegex(), 3)
- val index = cmds[0].toInt() - 1
+ val entryIndex = cmds[0].toInt() - 1
- if (index < LinksMgr.entries.size) {
- val entry: EntryLink = LinksMgr.entries[index]
+ if (entryIndex < LinksMgr.entries.links.size && LinksMgr.isUpToDate(event)) {
+ val entry: EntryLink = LinksMgr.entries.links[entryIndex]
val commentIndex = cmds[1].toInt() - 1
if (commentIndex < entry.comments.size) {
when (val cmd = cmds[2].trim()) {
- "" -> showComment(bot, entry, index, commentIndex) // L1.1:
- "-" -> deleteComment(bot, sender, isOp, entry, index, commentIndex) // L11:-
+ "" -> showComment(entry, entryIndex, commentIndex, event) // L1.1:
+ "-" -> deleteComment(channel, entry, entryIndex, commentIndex, event) // L1.1:-
else -> {
if (cmd.startsWith('?')) { // L1.1:?
- changeAuthor(bot, cmd, sender, isOp, entry, index, commentIndex)
+ changeAuthor(channel, cmd, entry, entryIndex, commentIndex, event)
} else { // L1.1:
- setComment(bot, cmd, sender, entry, index, commentIndex)
+ setComment(cmd, entry, entryIndex, commentIndex, event)
}
}
}
@@ -89,20 +84,11 @@ class Comment(bot: Mobibot) : AbstractCommand(bot) {
}
}
- override fun helpResponse(
- command: String,
- sender: String,
- isOp: Boolean,
- isPrivate: Boolean
- ): Boolean {
- if (super.helpResponse(command, sender, isOp, isPrivate)) {
- if (isOp) {
- bot.send(sender, "To change a comment's author:", isPrivate)
- bot.send(
- sender,
- helpFormat("${Constants.LINK_CMD}1.1:?"),
- isPrivate
- )
+ override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean {
+ if (super.helpResponse(channel, topic, event)) {
+ if (isChannelOp(channel, event)) {
+ event.sendMessage("To change a comment's author:")
+ event.sendMessage(helpFormat("${Constants.LINK_CMD}1.1:?"))
}
return true
}
@@ -114,49 +100,52 @@ class Comment(bot: Mobibot) : AbstractCommand(bot) {
}
private fun changeAuthor(
- bot: Mobibot,
+ channel: String,
cmd: String,
- sender: String,
- isOp: Boolean,
entry: EntryLink,
- index: Int,
- commentIndex: Int
+ entryIndex: Int,
+ commentIndex: Int,
+ event: GenericMessageEvent
) {
- if (isOp && cmd.length > 1) {
+ if (isChannelOp(channel, event) && cmd.length > 1) {
val comment = entry.getComment(commentIndex)
comment.nick = cmd.substring(1)
- bot.send(EntriesUtils.buildComment(index, commentIndex, comment))
- LinksMgr.saveEntries(bot, false)
+ event.sendMessage(EntriesUtils.buildComment(entryIndex, commentIndex, comment))
+ LinksMgr.entries.save()
} else {
- bot.send(sender, "Please ask a channel op to change the author of this comment for you.", false)
+ event.sendMessage("Please ask a channel op to change the author of this comment for you.")
}
}
private fun deleteComment(
- bot: Mobibot,
- sender: String,
- isOp: Boolean,
+ channel: String,
entry: EntryLink,
- index: Int,
- commentIndex: Int
+ entryIndex: Int,
+ commentIndex: Int,
+ event: GenericMessageEvent
) {
- if (isOp || sender == entry.getComment(commentIndex).nick) {
+ if (isChannelOp(channel, event) || event.user.nick == entry.getComment(commentIndex).nick) {
entry.deleteComment(commentIndex)
- bot.send("Comment ${EntriesUtils.buildLinkCmd(index)}.${commentIndex + 1} removed.")
- LinksMgr.saveEntries(bot, false)
+ event.sendMessage("Comment ${EntriesUtils.buildLinkLabel(entryIndex)}.${commentIndex + 1} removed.")
+ LinksMgr.entries.save()
} else {
- bot.send(sender, "Please ask a channel op to delete this comment for you.", false)
+ event.sendMessage("Please ask a channel op to delete this comment for you.")
}
}
- private fun setComment(bot: Mobibot, cmd: String, sender: String, entry: EntryLink, index: Int, commentIndex: Int) {
- entry.setComment(commentIndex, cmd, sender)
- val comment = entry.getComment(commentIndex)
- bot.send(sender, EntriesUtils.buildComment(index, commentIndex, comment), false)
- LinksMgr.saveEntries(bot, false)
+ private fun setComment(
+ cmd: String,
+ entry: EntryLink,
+ entryIndex: Int,
+ commentIndex: Int,
+ event: GenericMessageEvent
+ ) {
+ entry.setComment(commentIndex, cmd, event.user.nick)
+ event.sendMessage(EntriesUtils.buildComment(entryIndex, commentIndex, entry.getComment(commentIndex)))
+ LinksMgr.entries.save()
}
- private fun showComment(bot: Mobibot, entry: EntryLink, index: Int, commentIndex: Int) {
- bot.send(EntriesUtils.buildComment(index, commentIndex, entry.getComment(commentIndex)))
+ private fun showComment(entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent) {
+ event.sendMessage(EntriesUtils.buildComment(entryIndex, commentIndex, entry.getComment(commentIndex)))
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksMgr.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksMgr.kt
index fd7eb27..7bd95b8 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksMgr.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksMgr.kt
@@ -33,25 +33,29 @@
package net.thauvin.erik.mobibot.commands.links
import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Pinboard
import net.thauvin.erik.mobibot.Utils.bold
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.Utils.today
import net.thauvin.erik.mobibot.commands.AbstractCommand
-import net.thauvin.erik.mobibot.commands.Ignore
-import net.thauvin.erik.mobibot.entries.EntriesMgr
+import net.thauvin.erik.mobibot.commands.Ignore.Companion.isNotIgnored
+import net.thauvin.erik.mobibot.entries.Entries
import net.thauvin.erik.mobibot.entries.EntriesUtils
import net.thauvin.erik.mobibot.entries.EntryLink
+import net.thauvin.erik.mobibot.modules.Twitter
import org.jsoup.Jsoup
+import org.pircbotx.hooks.types.GenericMessageEvent
import java.io.IOException
-class LinksMgr(bot: Mobibot) : AbstractCommand(bot) {
- private val keywords: MutableList = mutableListOf()
+class LinksMgr : AbstractCommand() {
private val defaultTags: MutableList = mutableListOf()
+ private val keywords: MutableList = mutableListOf()
override val name = Constants.LINK_CMD
override val help = emptyList()
- override val isOp = false
+ override val isOpOnly = false
override val isPublic = false
override val isVisible = false
@@ -65,52 +69,35 @@ class LinksMgr(bot: Mobibot) : AbstractCommand(bot) {
const val TAGS_PROP = "tags"
const val TAG_MATCH = ", *| +"
- // Entries array
- @JvmField
- val entries = mutableListOf()
+ /** Entries array **/
+ val entries = Entries()
- // History/backlogs array
- @JvmField
- val history = mutableListOf()
+ /** Pinboard handler. **/
+ val pinboard = Pinboard()
+ /** Twitter handler. **/
+ val twitter = Twitter()
+
+ /** Let the user know if the entries are too old to be modified. **/
@JvmStatic
- var startDate: String = today()
- private set
-
- /**
- * Saves the entries.
- *
- * @param isDayBackup Set the `true` if the daily backup file should also be created.
- */
- @JvmStatic
- fun saveEntries(bot: Mobibot, isDayBackup: Boolean) {
- EntriesMgr.saveEntries(bot, entries, history, isDayBackup)
- }
-
- @JvmStatic
- fun startup(current: String, backlogs: String, channel: String) {
- startDate = EntriesMgr.loadEntries(current, channel, entries)
- if (today() != startDate) {
- entries.clear()
- startDate = today()
+ fun isUpToDate(event: GenericMessageEvent): Boolean {
+ if (entries.lastPubDate != today()) {
+ event.sendMessage("The links are too old to be updated.")
+ return false
}
- EntriesMgr.loadBacklogs(backlogs, history)
+ return true
}
}
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
val cmds = args.split(" ".toRegex(), 2)
+ val sender = event.user.nick
+ val botNick = event.bot().nick
+ val login = event.user.login
- if (Ignore.isNotIgnored(sender) && (cmds.size == 1 || !cmds[1].contains(bot.nick))) {
+ if (isNotIgnored(sender) && (cmds.size == 1 || !cmds[1].contains(botNick))) {
val link = cmds[0].trim()
- if (!isDupEntry(bot, sender, link, isPrivate)) {
- val isBackup = saveDayBackup(bot)
+ if (!isDupEntry(link, event)) {
var title = ""
val tags = ArrayList(defaultTags)
if (cmds.size == 2) {
@@ -129,37 +116,32 @@ class LinksMgr(bot: Mobibot) : AbstractCommand(bot) {
matchTagKeywords(title, tags)
}
- entries.add(EntryLink(link, title, sender, login, bot.channel, tags))
- val index: Int = entries.size - 1
- val entry: EntryLink = entries[index]
- bot.send(EntriesUtils.buildLink(index, entry))
+ // Links are old, clear them
+ if (entries.lastPubDate != today()) {
+ entries.links.clear()
+ }
- // Add Entry to pinboard.
- bot.addPin(entry)
+ val entry = EntryLink(link, title, sender, login, channel, tags)
+ entries.links.add(entry)
+ val index = entries.links.lastIndexOf(entry)
+ event.sendMessage(EntriesUtils.buildLink(index, entry))
+
+ pinboard.addPin(event.bot().serverHostname, entry)
// Queue link for posting to Twitter.
- bot.twitter.queueEntry(index)
+ twitter.queueEntry(index)
- saveEntries(bot, isBackup)
+ entries.save()
if (Constants.NO_TITLE == entry.title) {
- bot.send(sender, "Please specify a title, by typing:", isPrivate)
- bot.send(
- sender,
- helpFormat("${EntriesUtils.buildLinkCmd(index)}:|This is the title"),
- isPrivate
- )
+ event.sendMessage("Please specify a title, by typing:")
+ event.sendMessage(helpFormat("${EntriesUtils.buildLinkLabel(index)}:|This is the title"))
}
}
}
}
- override fun helpResponse(
- command: String,
- sender: String,
- isOp: Boolean,
- isPrivate: Boolean
- ): Boolean = false
+ override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean = false
override fun matches(message: String): Boolean {
return message.matches(LINK_MATCH.toRegex())
@@ -180,12 +162,12 @@ class LinksMgr(bot: Mobibot) : AbstractCommand(bot) {
return Constants.NO_TITLE
}
- private fun isDupEntry(bot: Mobibot, sender: String, link: String, isPrivate: Boolean): Boolean {
+ private fun isDupEntry(link: String, event: GenericMessageEvent): Boolean {
synchronized(entries) {
- for (i in entries.indices) {
- if (link == entries[i].link) {
- val entry: EntryLink = entries[i]
- bot.send(sender, bold("Duplicate") + " >> " + EntriesUtils.buildLink(i, entry), isPrivate)
+ for (i in entries.links.indices) {
+ if (link == entries.links[i].link) {
+ val entry: EntryLink = entries.links[i]
+ event.sendMessage(bold("Duplicate") + " >> " + EntriesUtils.buildLink(i, entry))
return true
}
}
@@ -202,17 +184,6 @@ class LinksMgr(bot: Mobibot) : AbstractCommand(bot) {
}
}
- private fun saveDayBackup(bot: Mobibot): Boolean {
- if (today() != startDate) {
- saveEntries(bot, true)
- entries.clear()
- startDate = today()
- return true
- }
-
- return false
- }
-
override fun setProperty(key: String, value: String) {
super.setProperty(key, value)
if (KEYWORDS_PROP == key) {
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt
index 140f70c..2e7d9ec 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt
@@ -33,15 +33,18 @@
package net.thauvin.erik.mobibot.commands.links
import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.bold
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.commands.links.LinksMgr.Companion.entries
import net.thauvin.erik.mobibot.entries.EntriesUtils
import net.thauvin.erik.mobibot.entries.EntryLink
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Posting(bot: Mobibot) : AbstractCommand(bot) {
+class Posting : AbstractCommand() {
override val name = "posting"
override val help = listOf(
"Post a URL, by saying it on a line on its own:",
@@ -55,30 +58,27 @@ class Posting(bot: Mobibot) : AbstractCommand(bot) {
"To edit a comment, see: ",
helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}")
)
- override val isOp = false
+ override val isOpOnly = false
override val isPublic = true
override val isVisible = true
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
val cmds = args.substring(1).split(":", limit = 2)
- val index = cmds[0].toInt() - 1
+ val entryIndex = cmds[0].toInt() - 1
- if (index < entries.size) {
- when (val cmd = cmds[1].trim()) {
- "" -> showEntry(index)
- "-" -> removeEntry(sender, login, isOp, index) // L1:-
- else -> {
+ if (entryIndex < entries.links.size) {
+ val cmd = cmds[1].trim()
+ if (cmd.isBlank()) {
+ showEntry(entryIndex, event) // L1:
+ } else if (LinksMgr.isUpToDate(event)) {
+ if (cmd == "-") {
+ removeEntry(channel, entryIndex, event) // L1:-
+ } else {
when (cmd[0]) {
- '|' -> changeTitle(cmd, index) // L1:|
- '=' -> changeUrl(cmd, login, isOp, index) // L1:=
- '?' -> changeAuthor(cmd, sender, isOp, index) // L1:?
- else -> addComment(cmd, sender, index) // L1:
+ '|' -> changeTitle(cmd, entryIndex, event) // L1:|
+ '=' -> changeUrl(channel, cmd, entryIndex, event) // L1:=
+ '?' -> changeAuthor(channel, cmd, entryIndex, event) // L1:?
+ else -> addComment(cmd, entryIndex, event) // L1:
}
}
}
@@ -89,73 +89,75 @@ class Posting(bot: Mobibot) : AbstractCommand(bot) {
return message.matches("${Constants.LINK_CMD}[0-9]+:.*".toRegex())
}
- private fun addComment(cmd: String, sender: String, index: Int) {
- val entry: EntryLink = entries[index]
- val commentIndex = entry.addComment(cmd, sender)
+ private fun addComment(cmd: String, entryIndex: Int, event: GenericMessageEvent) {
+ val entry: EntryLink = entries.links[entryIndex]
+ val commentIndex = entry.addComment(cmd, event.user.nick)
val comment = entry.getComment(commentIndex)
- bot.send(sender, EntriesUtils.buildComment(index, commentIndex, comment), false)
- LinksMgr.saveEntries(bot, false)
+ event.sendMessage(EntriesUtils.buildComment(entryIndex, commentIndex, comment))
+ entries.save()
}
- private fun changeTitle(cmd: String, index: Int) {
+ private fun changeTitle(cmd: String, entryIndex: Int, event: GenericMessageEvent) {
if (cmd.length > 1) {
- val entry: EntryLink = entries[index]
+ val entry: EntryLink = entries.links[entryIndex]
entry.title = cmd.substring(1).trim()
- bot.updatePin(entry.link, entry)
- bot.send(EntriesUtils.buildLink(index, entry))
- LinksMgr.saveEntries(bot, false)
+ LinksMgr.pinboard.updatePin(event.bot().serverHostname, entry.link, entry)
+ event.sendMessage(EntriesUtils.buildLink(entryIndex, entry))
+ entries.save()
}
}
- private fun changeUrl(cmd: String, login: String, isOp: Boolean, index: Int) {
- val entry: EntryLink = entries[index]
- if (entry.login == login || isOp) {
+ private fun changeUrl(channel: String, cmd: String, entryIndex: Int, event: GenericMessageEvent) {
+ val entry: EntryLink = entries.links[entryIndex]
+ if (entry.login == event.user.login || isChannelOp(channel, event)) {
val link = cmd.substring(1)
if (link.matches(LinksMgr.LINK_MATCH.toRegex())) {
val oldLink = entry.link
entry.link = link
- bot.updatePin(oldLink, entry)
- bot.send(EntriesUtils.buildLink(index, entry))
- LinksMgr.saveEntries(bot, false)
+ LinksMgr.pinboard.updatePin(event.bot().serverHostname, oldLink, entry)
+ event.sendMessage(EntriesUtils.buildLink(entryIndex, entry))
+ entries.save()
}
}
}
- private fun changeAuthor(cmd: String, sender: String, isOp: Boolean, index: Int) {
- if (isOp) {
+ private fun changeAuthor(channel: String, cmd: String, index: Int, event: GenericMessageEvent) {
+ if (isChannelOp(channel, event)) {
if (cmd.length > 1) {
- val entry: EntryLink = entries[index]
+ val entry: EntryLink = entries.links[index]
entry.nick = cmd.substring(1)
- bot.send(EntriesUtils.buildLink(index, entry))
- LinksMgr.saveEntries(bot, false)
+ LinksMgr.pinboard.updatePin(event.bot().serverHostname, entry.link, entry)
+ event.sendMessage(EntriesUtils.buildLink(index, entry))
+ entries.save()
}
} else {
- bot.send(sender, "Please ask a channel op to change the author of this link for you.", false)
+ event.sendMessage("Please ask a channel op to change the author of this link for you.")
}
}
- private fun removeEntry(sender: String, login: String, isOp: Boolean, index: Int) {
- val entry: EntryLink = entries[index]
- if (entry.login == login || isOp) {
- bot.deletePin(index, entry)
- entries.removeAt(index)
- bot.send("Entry ${EntriesUtils.buildLinkCmd(index)} removed.")
- LinksMgr.saveEntries(bot, false)
+ private fun removeEntry(channel: String, index: Int, event: GenericMessageEvent) {
+ val entry: EntryLink = entries.links[index]
+ if (entry.login == event.user.login || isChannelOp(channel, event)) {
+ LinksMgr.pinboard.deletePin(entry)
+ LinksMgr.twitter.removeEntry(index)
+ entries.links.removeAt(index)
+ event.sendMessage("Entry ${EntriesUtils.buildLinkLabel(index)} removed.")
+ entries.save()
} else {
- bot.send(sender, "Please ask a channel op to remove this entry for you.", false)
+ event.sendMessage("Please ask a channel op to remove this entry for you.")
}
}
- private fun showEntry(index: Int) {
- val entry: EntryLink = entries[index]
- bot.send(EntriesUtils.buildLink(index, entry))
+ private fun showEntry(index: Int, event: GenericMessageEvent) {
+ val entry: EntryLink = entries.links[index]
+ event.sendMessage(EntriesUtils.buildLink(index, entry))
if (entry.tags.isNotEmpty()) {
- bot.send(EntriesUtils.buildTags(index, entry))
+ event.sendMessage(EntriesUtils.buildTags(index, entry))
}
if (entry.comments.isNotEmpty()) {
val comments = entry.comments
for (i in comments.indices) {
- bot.send(EntriesUtils.buildComment(index, i, comments[i]))
+ event.sendMessage(EntriesUtils.buildComment(index, i, comments[i]))
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt
index ab7a983..2970033 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt
@@ -33,19 +33,22 @@
package net.thauvin.erik.mobibot.commands.links
import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.entries.EntriesUtils
import net.thauvin.erik.mobibot.entries.EntryLink
+import org.pircbotx.hooks.types.GenericMessageEvent
-class Tags(bot: Mobibot) : AbstractCommand(bot) {
+class Tags : AbstractCommand() {
override val name = COMMAND
override val help = listOf(
"To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:",
helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]")
)
- override val isOp = false
+ override val isOpOnly = false
override val isPublic = true
override val isVisible = true
@@ -53,33 +56,27 @@ class Tags(bot: Mobibot) : AbstractCommand(bot) {
const val COMMAND = "tags"
}
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
val cmds = args.substring(1).split("${Constants.TAG_CMD}:", limit = 2)
val index = cmds[0].toInt() - 1
- if (index < LinksMgr.entries.size) {
+ if (index < LinksMgr.entries.links.size && LinksMgr.isUpToDate(event)) {
val cmd = cmds[1].trim()
- val entry: EntryLink = LinksMgr.entries[index]
+ val entry: EntryLink = LinksMgr.entries.links[index]
if (cmd.isNotEmpty()) {
- if (entry.login == login || isOp) {
+ if (entry.login == event.user.login || isChannelOp(channel, event)) {
entry.setTags(cmd)
- bot.updatePin(entry.link, entry)
- bot.send(EntriesUtils.buildTags(index, entry))
- LinksMgr.saveEntries(bot, false)
+ LinksMgr.pinboard.updatePin(event.bot().serverHostname, entry.link, entry)
+ event.sendMessage(EntriesUtils.buildTags(index, entry))
+ LinksMgr.entries.save()
} else {
- bot.send(sender, "Please ask a channel op to change the tags for you.", isPrivate)
+ event.sendMessage("Please ask a channel op to change the tags for you.")
}
} else {
if (entry.tags.isNotEmpty()) {
- bot.send(EntriesUtils.buildTags(index, entry))
+ event.sendMessage(EntriesUtils.buildTags(index, entry))
} else {
- bot.send(sender, "The entry has no tags. Why don't add some?", isPrivate)
+ event.sendMessage("The entry has no tags. Why don't add some?")
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt
index e845a66..5d446d2 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt
@@ -32,23 +32,25 @@
package net.thauvin.erik.mobibot.commands.links
-import net.thauvin.erik.mobibot.Mobibot
-import net.thauvin.erik.mobibot.Utils.bold
+import net.thauvin.erik.mobibot.Utils.bot
+import net.thauvin.erik.mobibot.Utils.buildCmdSyntax
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.commands.links.LinksMgr.Companion.entries
import net.thauvin.erik.mobibot.entries.EntriesUtils
import net.thauvin.erik.mobibot.entries.EntryLink
+import org.pircbotx.hooks.events.PrivateMessageEvent
+import org.pircbotx.hooks.types.GenericMessageEvent
-class View(bot: Mobibot) : AbstractCommand(bot) {
- @Suppress("MagicNumber")
- private val maxEntries = 8
+class View : AbstractCommand() {
+ private val maxEntries = 6
override val name = VIEW_CMD
override val help = listOf(
"To list or search the current URL posts:",
helpFormat("%c $name [] []")
)
- override val isOp = false
+ override val isOpOnly = false
override val isPublic = true
override val isVisible = true
@@ -56,22 +58,16 @@ class View(bot: Mobibot) : AbstractCommand(bot) {
const val VIEW_CMD = "view"
}
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- if (entries.size != 0) {
- showPosts(bot, args, sender)
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
+ if (entries.links.isNotEmpty()) {
+ showPosts(args, event)
} else {
- bot.send(sender, "There is currently nothing to view. Why don't you post something?", isPrivate)
+ event.sendMessage("There is currently nothing to view. Why don't you post something?")
}
}
- private fun showPosts(bot: Mobibot, args: String, sender: String) {
- val max = entries.size
+ private fun showPosts(args: String, event: GenericMessageEvent) {
+ val max = entries.links.size
var lcArgs = args.lowercase()
var i = 0
if (lcArgs.isEmpty() && max > maxEntries) {
@@ -97,25 +93,32 @@ class View(bot: Mobibot) : AbstractCommand(bot) {
var entry: EntryLink
var sent = 0
while (i < max && sent < maxEntries) {
- entry = entries[i]
+ entry = entries.links[i]
if (lcArgs.isNotBlank()) {
if (entry.matches(lcArgs)) {
- bot.send(sender, EntriesUtils.buildLink(i, entry, true), false)
+ event.sendMessage(EntriesUtils.buildLink(i, entry, true))
sent++
}
} else {
- bot.send(sender, EntriesUtils.buildLink(i, entry, true), false)
+ event.sendMessage(EntriesUtils.buildLink(i, entry, true))
sent++
}
i++
if (sent == maxEntries && i < max) {
- bot.send(
- sender, "To view more, try: " + bold("${bot.nick}: $name ${i + 1} $lcArgs"), false
+ event.sendMessage("To view more, try: ")
+ event.sendMessage(
+ helpFormat(
+ buildCmdSyntax(
+ "%c $name ${i + 1} $lcArgs",
+ event.bot().nick,
+ event is PrivateMessageEvent
+ )
+ )
)
}
}
if (sent == 0) {
- bot.send(sender, "No matches. Please try again.", false)
+ event.sendMessage("No matches. Please try again.")
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt
index ddacd50..b063549 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt
@@ -31,84 +31,88 @@
*/
package net.thauvin.erik.mobibot.commands.tell
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.bold
import net.thauvin.erik.mobibot.Utils.buildCmdSyntax
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.isChannelOp
import net.thauvin.erik.mobibot.Utils.plural
import net.thauvin.erik.mobibot.Utils.reverseColor
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.Utils.toIntOrDefault
import net.thauvin.erik.mobibot.Utils.toUtcDateTime
import net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.commands.links.View
+import org.pircbotx.PircBotX
+import org.pircbotx.hooks.events.MessageEvent
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.pircbotx.hooks.types.GenericUserEvent
/**
* The `Tell` command.
*/
-class Tell(bot: Mobibot) : AbstractCommand(bot) {
+class Tell(private val serialObject: String) : AbstractCommand() {
// Messages queue
private val messages: MutableList = mutableListOf()
- // Serialized object file
- private val serializedObject: String
-
// Maximum number of days to keep messages
- @Suppress("MagicNumber")
private var maxDays = 7
// Message maximum queue size
- @Suppress("MagicNumber")
private var maxSize = 50
/**
* Cleans the messages queue.
*/
private fun clean(): Boolean {
- if (bot.logger.isDebugEnabled) bot.logger.debug("Cleaning the messages.")
+ // if (bot.logger.isDebugEnabled) bot.logger.debug("Cleaning the messages.")
return TellMessagesMgr.clean(messages, maxDays.toLong())
}
// Delete message.
- private fun deleteMessage(sender: String, args: String, isOp: Boolean, isPrivate: Boolean) {
+ private fun deleteMessage(channel: String, args: String, event: GenericMessageEvent) {
val split = args.split(" ")
if (split.size == 2) {
val id = split[1]
var deleted = false
if (TELL_ALL_KEYWORD.equals(id, ignoreCase = true)) {
for (message in messages) {
- if (message.sender.equals(sender, ignoreCase = true) && message.isReceived) {
+ if (message.sender.equals(event.user.nick, ignoreCase = true) && message.isReceived) {
messages.remove(message)
deleted = true
}
}
if (deleted) {
save()
- bot.send(sender, "Delivered messages have been deleted.", isPrivate)
+ event.sendMessage("Delivered messages have been deleted.")
} else {
- bot.send(sender, "No delivered messages were found.", isPrivate)
+ event.sendMessage("No delivered messages were found.")
}
} else {
var found = false
for (message in messages) {
found = (message.id == id)
- if (found && (message.sender.equals(sender, ignoreCase = true) || bot.isOp(sender))) {
+ if (found && (message.sender.equals(event.user.nick, ignoreCase = true) || isChannelOp(
+ channel,
+ event
+ ))
+ ) {
messages.remove(message)
save()
- bot.send(sender, "Your message was deleted from the queue.", isPrivate)
+ event.sendMessage("Your message was deleted from the queue.")
deleted = true
break
}
}
if (!deleted) {
if (found) {
- bot.send(sender, "Only messages that you sent can be deleted.", isPrivate)
+ event.sendMessage("Only messages that you sent can be deleted.")
} else {
- bot.send(sender, "The specified message [ID $id] could not be found.", isPrivate)
+ event.sendMessage("The specified message [ID $id] could not be found.")
}
}
}
} else {
- helpResponse(args, sender, isOp, isPrivate)
+ helpResponse(channel, args, event)
}
}
@@ -124,30 +128,24 @@ class Tell(bot: Mobibot) : AbstractCommand(bot) {
helpFormat("%c $name ${View.VIEW_CMD}"),
"Messages are kept for ${bold(maxDays)}" + " day".plural(maxDays.toLong()) + '.'
)
- override val isOp: Boolean = false
+ override val isOpOnly: Boolean = false
override val isPublic: Boolean = isEnabled()
override val isVisible: Boolean = isEnabled()
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
+ override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) {
if (isEnabled()) {
if (args.isBlank()) {
- helpResponse(args, sender, isOp, isPrivate)
+ helpResponse(channel, args, event)
} else if (args.startsWith(View.VIEW_CMD)) {
- if (bot.isOp(sender) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) {
- viewAll(sender, isPrivate)
+ if (isChannelOp(channel, event) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) {
+ viewAll(event)
} else {
- viewMessages(sender, isPrivate)
+ viewMessages(event)
}
} else if (args.startsWith("$TELL_DEL_KEYWORD ")) {
- deleteMessage(sender, args, isOp, isPrivate)
+ deleteMessage(channel, args, event)
} else {
- newMessage(sender, args, isOp, isPrivate)
+ newMessage(channel, args, event)
}
if (clean()) {
save()
@@ -169,21 +167,19 @@ class Tell(bot: Mobibot) : AbstractCommand(bot) {
}
// New message.
- private fun newMessage(sender: String, args: String, isOp: Boolean, isPrivate: Boolean) {
+ private fun newMessage(channel: String, args: String, event: GenericMessageEvent) {
val split = args.split(" ".toRegex(), 2)
if (split.size == 2 && split[1].isNotBlank() && split[1].contains(" ")) {
if (messages.size < maxSize) {
- val message = TellMessage(sender, split[0], split[1].trim())
+ val message = TellMessage(event.user.nick, split[0], split[1].trim())
messages.add(message)
save()
- bot.send(
- sender, "Message [ID ${message.id}] was queued for ${bold(message.recipient)}", isPrivate
- )
+ event.sendMessage("Message [ID ${message.id}] was queued for ${bold(message.recipient)}")
} else {
- bot.send(sender, "Sorry, the messages queue is currently full.", isPrivate)
+ event.sendMessage("Sorry, the messages queue is currently full.")
}
} else {
- helpResponse(args, sender, isOp, isPrivate)
+ helpResponse(channel, args, event)
}
}
@@ -191,34 +187,30 @@ class Tell(bot: Mobibot) : AbstractCommand(bot) {
* Saves the messages queue.
*/
private fun save() {
- TellMessagesMgr.save(serializedObject, messages, bot.logger)
+ TellMessagesMgr.save(serialObject, messages)
}
/**
* Checks and sends messages.
*/
- @JvmOverloads
- fun send(nickname: String, isMessage: Boolean = false) {
- if (isEnabled() && nickname != bot.nick) {
+ fun send(event: GenericUserEvent) {
+ val nickname = event.user.nick
+ if (isEnabled() && nickname != event.getBot().nick) {
messages.stream().filter { message: TellMessage -> message.isMatch(nickname) }
.forEach { message: TellMessage ->
if (message.recipient.equals(nickname, ignoreCase = true) && !message.isReceived) {
if (message.sender == nickname) {
- if (!isMessage) {
- bot.send(
- nickname,
- "${bold("You")} wanted me to remind you: ${reverseColor(message.message)}",
- true
+ if (event !is MessageEvent) {
+ event.user.send().message(
+ "${bold("You")} wanted me to remind you: ${reverseColor(message.message)}"
)
message.isReceived = true
message.isNotified = true
save()
}
} else {
- bot.send(
- nickname,
- "${message.sender} wanted me to tell you: ${reverseColor(message.message)}",
- true
+ event.user.send().message(
+ "${message.sender} wanted me to tell you: ${reverseColor(message.message)}"
)
message.isReceived = true
save()
@@ -226,11 +218,9 @@ class Tell(bot: Mobibot) : AbstractCommand(bot) {
} else if (message.sender.equals(nickname, ignoreCase = true) && message.isReceived
&& !message.isNotified
) {
- bot.send(
- nickname,
- "Your message ${reverseColor("[ID " + message.id + ']')} was sent to "
- + "${bold(message.recipient)} on ${message.receptionDate.toUtcDateTime()}",
- true
+ event.user.send().message(
+ "Your message ${reverseColor("[ID ${message.id}]")} was sent to "
+ + "${bold(message.recipient)} on ${message.receptionDate}"
)
message.isNotified = true
save()
@@ -247,66 +237,55 @@ class Tell(bot: Mobibot) : AbstractCommand(bot) {
fun size(): Int = messages.size
// View all messages.
- private fun viewAll(sender: String, isPrivate: Boolean) {
+ private fun viewAll(event: GenericMessageEvent) {
if (messages.isNotEmpty()) {
for (message in messages) {
- bot.send(
- sender, bold(message.sender) + ARROW + bold(message.recipient)
- + " [ID: " + message.id + ", "
- + (if (message.isReceived) "DELIVERED" else "QUEUED") + ']',
- isPrivate
+ event.sendMessage(
+ "${bold(message.sender)}$ARROW${bold(message.recipient)} [ID: ${message.id}, " +
+ (if (message.isReceived) "DELIVERED]" else "QUEUED]")
)
}
} else {
- bot.send(sender, "There are no messages in the queue.", isPrivate)
+ event.sendMessage("There are no messages in the queue.")
}
}
// View messages.
- private fun viewMessages(sender: String, isPrivate: Boolean) {
+ private fun viewMessages(event: GenericMessageEvent) {
var hasMessage = false
for (message in messages) {
- if (message.isMatch(sender)) {
+ if (message.isMatch(event.user.nick)) {
if (!hasMessage) {
- hasMessage = true
- bot.send(sender, "Here are your messages: ", isPrivate)
+ hasMessage = true; event.sendMessage("Here are your messages: ")
}
if (message.isReceived) {
- bot.send(
- sender,
- bold(message.sender) + ARROW + bold(message.recipient)
- + " [${message.receptionDate.toUtcDateTime()}, ID: "
- + bold(message.id) + ", DELIVERED]",
- isPrivate
+ event.sendMessage(
+ bold(message.sender) + ARROW + bold(message.recipient) +
+ " [${message.receptionDate.toUtcDateTime()}, ID: ${bold(message.id)}, DELIVERED]"
)
} else {
- bot.send(
- sender,
- bold(message.sender) + ARROW + bold(message.recipient)
- + " [${message.queued.toUtcDateTime()}, ID: "
- + bold(message.id) + ", QUEUED]",
- isPrivate
+ event.sendMessage(
+ bold(message.sender) + ARROW + bold(message.recipient) +
+ " [${message.queued.toUtcDateTime()}, ID: ${bold(message.id)}, QUEUED]"
)
}
- bot.send(sender, helpFormat(message.message), isPrivate)
+ event.sendMessage(helpFormat(message.message))
}
}
if (!hasMessage) {
- bot.send(sender, "You have no messages in the queue.", isPrivate)
+ event.sendMessage("You have no messages in the queue.")
} else {
- bot.send(sender, "To delete one or all delivered messages:", isPrivate)
- bot.send(
- sender,
+ event.sendMessage("To delete one or all delivered messages:")
+ event.sendMessage(
helpFormat(
buildCmdSyntax(
"%c $name $TELL_DEL_KEYWORD ",
- bot.nick,
- isPrivate
+ event.user.nick,
+ true
)
- ),
- isPrivate
+ )
)
- bot.send(sender, help.last(), isPrivate)
+ event.sendMessage(help.last())
}
}
@@ -324,9 +303,6 @@ class Tell(bot: Mobibot) : AbstractCommand(bot) {
// Arrow
private const val ARROW = " --> "
- // Serialized object file extension
- private const val SER_EXT = ".ser"
-
// All keyword
private const val TELL_ALL_KEYWORD = "all"
@@ -341,8 +317,7 @@ class Tell(bot: Mobibot) : AbstractCommand(bot) {
initProperties(MAX_DAYS_PROP, MAX_SIZE_PROP)
// Load the message queue
- serializedObject = bot.logsDir + bot.name + SER_EXT
- messages.addAll(TellMessagesMgr.load(serializedObject, bot.logger))
+ messages.addAll(TellMessagesMgr.load(serialObject))
if (clean()) {
save()
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt
index 47521d4..eb058b7 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt
@@ -66,12 +66,12 @@ class TellMessage internal constructor(
var id: String = queued.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
/**
- * Returns {@code true) if a notification was sent.
+ * Returns {@code true} if a notification was sent.
*/
var isNotified = false
/**
- * Returns {@code true) if the message was received.
+ * Returns {@code true} if the message was received.
*/
var isReceived = false
set(value) {
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgr.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgr.kt
index c11e23e..5960b63 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgr.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgr.kt
@@ -31,10 +31,10 @@
*/
package net.thauvin.erik.mobibot.commands.tell
-import org.apache.logging.log4j.Logger
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
-import java.io.FileNotFoundException
import java.io.IOException
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
@@ -42,11 +42,14 @@ import java.nio.file.Files
import java.nio.file.Paths
import java.time.Clock
import java.time.LocalDateTime
+import kotlin.io.path.exists
/**
* The Tell Messages Manager.
*/
object TellMessagesMgr {
+ val logger: Logger = LoggerFactory.getLogger(TellMessagesMgr::class.java)
+
/**
* Cleans the messages queue.
*/
@@ -58,22 +61,22 @@ object TellMessagesMgr {
/**
* Loads the messages.
*/
-
- fun load(file: String, logger: Logger): List {
- try {
- ObjectInputStream(
- BufferedInputStream(Files.newInputStream(Paths.get(file)))
- ).use { input ->
- if (logger.isDebugEnabled) logger.debug("Loading the messages.")
- @Suppress("UNCHECKED_CAST")
- return input.readObject() as List
+ fun load(file: String): List {
+ val serialFile = Paths.get(file)
+ if (serialFile.exists()) {
+ try {
+ ObjectInputStream(
+ BufferedInputStream(Files.newInputStream(serialFile))
+ ).use { input ->
+ if (logger.isDebugEnabled) logger.debug("Loading the messages.")
+ @Suppress("UNCHECKED_CAST")
+ return input.readObject() as List
+ }
+ } catch (e: IOException) {
+ logger.error("An IO error occurred loading the messages queue.", e)
+ } catch (e: ClassNotFoundException) {
+ logger.error("An error occurred loading the messages queue.", e)
}
- } catch (ignore: FileNotFoundException) {
- // Do nothing
- } catch (e: IOException) {
- logger.error("An IO error occurred loading the messages queue.", e)
- } catch (e: ClassNotFoundException) {
- logger.error("An error occurred loading the messages queue.", e)
}
return listOf()
}
@@ -81,7 +84,7 @@ object TellMessagesMgr {
/**
* Saves the messages.
*/
- fun save(file: String, messages: List?, logger: Logger) {
+ fun save(file: String, messages: List?) {
try {
BufferedOutputStream(Files.newOutputStream(Paths.get(file))).use { bos ->
ObjectOutputStream(bos).use { output ->
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Kill.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt
similarity index 74%
rename from src/main/kotlin/net/thauvin/erik/mobibot/commands/Kill.kt
rename to src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt
index 803ab58..78602f6 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Kill.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt
@@ -1,5 +1,5 @@
/*
- * Kill.kt
+ * Entries.kt
*
* Copyright (c) 2004-2021, Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
@@ -30,26 +30,26 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package net.thauvin.erik.mobibot.commands
+package net.thauvin.erik.mobibot.entries
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.today
-class Kill(bot: Mobibot) : AbstractCommand(bot) {
- override val name = "kill"
- override val help = emptyList()
- override val isOp = true
- override val isPublic = false
- override val isVisible = false
+class Entries(
+ var channel: String = "",
+ var ircServer: String = "",
+ var logsDir: String = "",
+ var backlogs: String = ""
+) {
+ val links = mutableListOf()
- override fun commandResponse(
- sender: String,
- login: String,
- args: String,
- isOp: Boolean,
- isPrivate: Boolean
- ) {
- if (isOp) {
- bot.shutdown(sender, true)
- }
+ var lastPubDate = today()
+
+ fun load() {
+ lastPubDate = FeedsMgr.loadFeed(this)
+ }
+
+ fun save() {
+ lastPubDate = today()
+ FeedsMgr.saveFeed(this)
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesMgr.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesMgr.kt
deleted file mode 100644
index 6fe809b..0000000
--- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesMgr.kt
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * EntriesMgr.kt
- *
- * Copyright (c) 2004-2021, Erik C. Thauvin (erik@thauvin.net)
- * All rights reserved.
- *
- * 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.entries
-
-import com.rometools.rome.feed.synd.SyndContentImpl
-import com.rometools.rome.feed.synd.SyndEntry
-import com.rometools.rome.feed.synd.SyndEntryImpl
-import com.rometools.rome.feed.synd.SyndFeed
-import com.rometools.rome.feed.synd.SyndFeedImpl
-import com.rometools.rome.io.FeedException
-import com.rometools.rome.io.SyndFeedInput
-import com.rometools.rome.io.SyndFeedOutput
-import net.thauvin.erik.mobibot.Mobibot
-import net.thauvin.erik.mobibot.Utils.toIsoLocalDate
-import java.io.IOException
-import java.io.InputStreamReader
-import java.io.OutputStreamWriter
-import java.nio.charset.StandardCharsets
-import java.nio.file.Files
-import java.nio.file.Paths
-import java.util.Calendar
-
-/**
- * Manages the feed entries.
- */
-object EntriesMgr {
- /**
- * The name of the file containing the current entries.
- */
- const val CURRENT_XML = "current.xml"
-
- /**
- * The name of the file containing the backlog entries.
- */
- const val NAV_XML = "nav.xml"
-
- /**
- * The .xml extension
- */
- const val XML_EXT = ".xml"
-
- // Maximum number of backlogs to keep
- private const val maxBacklogs = 10
-
- // Daily backup
- private fun dailyBackup(
- bot: Mobibot,
- history: MutableList
- ) {
- if (bot.backlogsUrl.isNotBlank()) {
- if (!history.contains(bot.today)) {
- history.add(bot.today)
- while (history.size > maxBacklogs) {
- history.removeFirst()
- }
- }
- OutputStreamWriter(
- Files.newOutputStream(Paths.get(bot.logsDir + NAV_XML)), StandardCharsets.UTF_8
- ).use { fw ->
- val output = SyndFeedOutput()
- val rss: SyndFeed = SyndFeedImpl()
- val items: MutableList = mutableListOf()
- var item: SyndEntry
- with(rss) {
- feedType = "rss_2.0"
- title = "${bot.channel} IRC Links Backlogs"
- description = "Backlogs of Links from ${bot.ircServer} on ${bot.channel}"
- link = bot.backlogsUrl
- publishedDate = Calendar.getInstance().time
- }
- var date: String
- items.clear()
- for (i in history.size - 1 downTo 0) {
- date = history[i]
- item = SyndEntryImpl()
- with(item) {
- link = bot.backlogsUrl + date + ".xml"
- title = date
- description = SyndContentImpl().apply { value = "Links for $date" }
- }
- items.add(item)
- }
- rss.entries = items
- if (bot.logger.isDebugEnabled) bot.logger.debug("Writing the backlog feed.")
- output.output(rss, fw)
- }
- } else {
- if (bot.logger.isErrorEnabled) {
- bot.logger.warn("Unable to generate the backlogs feed. No property configured.")
- }
- }
- }
-
- /**
- * Loads the backlogs.
- */
- @Throws(IOException::class, FeedException::class)
- fun loadBacklogs(file: String, history: MutableList) {
- history.clear()
- val input = SyndFeedInput()
- InputStreamReader(Files.newInputStream(Paths.get(file)), StandardCharsets.UTF_8).use { reader ->
- val feed = input.build(reader)
- val items = feed.entries
- for (i in items.indices.reversed()) {
- history.add(items[i].title)
- }
- }
- }
-
- /**
- * Loads the current entries.
- */
- @Throws(IOException::class, FeedException::class)
- fun loadEntries(file: String, channel: String, entries: MutableList): String {
- entries.clear()
- val input = SyndFeedInput()
- var today: String
- InputStreamReader(
- Files.newInputStream(Paths.get(file)), StandardCharsets.UTF_8
- ).use { reader ->
- val feed = input.build(reader)
- today = feed.publishedDate.toIsoLocalDate()
- val items = feed.entries
- var entry: EntryLink
- for (i in items.indices.reversed()) {
- with(items[i]) {
- entry = EntryLink(
- link,
- title,
- author.substring(author.lastIndexOf('(') + 1, author.length - 1),
- channel,
- publishedDate,
- categories
- )
- var split: List
- for (comment in description.value.split("
")) {
- split = comment.split(": ".toRegex(), 2)
- if (split.size == 2) {
- entry.addComment(comment = split[1].trim(), nick = split[0].trim())
- }
- }
- }
- entries.add(entry)
- }
- }
- return today
- }
-
- /**
- * Saves the entries.
- */
- fun saveEntries(
- bot: Mobibot,
- entries: List,
- history: MutableList,
- isDayBackup: Boolean
- ) {
- if (bot.logger.isDebugEnabled) bot.logger.debug("Saving the feeds...")
- if (bot.logsDir.isNotBlank() && bot.weblogUrl.isNotBlank()) {
- try {
- val output = SyndFeedOutput()
- val rss: SyndFeed = SyndFeedImpl()
- val items: MutableList = mutableListOf()
- var item: SyndEntry
- OutputStreamWriter(
- Files.newOutputStream(Paths.get(bot.logsDir + CURRENT_XML)), StandardCharsets.UTF_8
- ).use { fw ->
- with(rss) {
- feedType = "rss_2.0"
- title = bot.channel + " IRC Links"
- description = "Links from ${bot.ircServer} on ${bot.channel}"
- link = bot.weblogUrl
- publishedDate = Calendar.getInstance().time
- language = "en"
- }
- val buff: StringBuilder = StringBuilder()
- for (i in entries.size - 1 downTo 0) {
- with(entries[i]) {
- buff.setLength(0)
- buff.append("Posted by ")
- .append(nick)
- .append(" on ")
- .append(channel)
- .append("")
- if (comments.size > 0) {
- buff.append("
")
- for (j in comments.indices) {
- if (j > 0) {
- buff.append("
")
- }
- buff.append(comments[j].nick).append(": ").append(comments[j].comment)
- }
- }
- item = SyndEntryImpl()
- item.link = link
- item.description = SyndContentImpl().apply { value = buff.toString() }
- item.title = title
- item.publishedDate = date
- item.author = "${bot.channel.substring(1)}@${bot.ircServer} ($nick)"
- item.categories = tags
- items.add(item)
- }
- }
- rss.entries = items
- if (bot.logger.isDebugEnabled) bot.logger.debug("Writing the entries feed.")
- output.output(rss, fw)
- }
- OutputStreamWriter(
- Files.newOutputStream(
- Paths.get(
- bot.logsDir + bot.today + XML_EXT
- )
- ), StandardCharsets.UTF_8
- ).use { fw -> output.output(rss, fw) }
- if (isDayBackup) {
- dailyBackup(bot, history)
- }
- } catch (e: FeedException) {
- if (bot.logger.isWarnEnabled) bot.logger.warn("Unable to generate the entries feed.", e)
- } catch (e: IOException) {
- if (bot.logger.isWarnEnabled)
- bot.logger.warn("An IO error occurred while generating the entries feed.", e)
- }
- } else {
- if (bot.logger.isWarnEnabled) {
- bot.logger.warn("Unable to generate the entries feed. A required property is missing.")
- }
- }
- }
-}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt
index cf0bf35..b577895 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt
@@ -40,22 +40,22 @@ import net.thauvin.erik.mobibot.Utils.green
*/
object EntriesUtils {
/**
- * Build link cmd based on its index. e.g: L1
+ * Build link label based on its index. e.g: L1
*/
- fun buildLinkCmd(index: Int): String = Constants.LINK_CMD + (index + 1)
+ fun buildLinkLabel(index: Int): String = Constants.LINK_CMD + (index + 1)
/**
* Builds an entry's comment for display on the channel.
*/
fun buildComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String =
- ("${buildLinkCmd(entryIndex)}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}")
+ ("${buildLinkLabel(entryIndex)}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}")
/**
* Builds an entry's link for display on the channel.
*/
@JvmOverloads
fun buildLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String {
- val buff = StringBuilder().append(buildLinkCmd(entryIndex)).append(": ")
+ val buff = StringBuilder().append(buildLinkLabel(entryIndex)).append(": ")
.append('[').append(entry.nick).append(']')
if (isView && entry.comments.isNotEmpty()) {
buff.append("[+").append(entry.comments.size).append(']')
@@ -76,5 +76,5 @@ object EntriesUtils {
* Build an entry's tags/categories for display on the channel.
*/
fun buildTags(entryIndex: Int, entry: EntryLink): String =
- buildLinkCmd(entryIndex) + "${Constants.TAG_CMD}: " + entry.pinboardTags.replace(",", ", ")
+ buildLinkLabel(entryIndex) + "${Constants.TAG_CMD}: " + entry.pinboardTags.replace(",", ", ")
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt
index 1a8468f..d7730a5 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt
@@ -109,16 +109,25 @@ class EntryLink : Serializable {
*/
fun addComment(comment: String, nick: String): Int {
comments.add(EntryComment(comment, nick))
- return comments.size - 1
+ return comments.lastIndex
}
/**
* Deletes a specific comment.
*/
- fun deleteComment(index: Int) {
+ fun deleteComment(index: Int): Boolean {
if (index < comments.size) {
comments.removeAt(index)
+ return true
}
+ return false
+ }
+
+ /**
+ * Deletes a comment.
+ */
+ fun deleteComment(entryComment: EntryComment): Boolean {
+ return comments.remove(entryComment)
}
/**
@@ -154,7 +163,7 @@ class EntryLink : Serializable {
* Sets a comment.
*/
fun setComment(index: Int, comment: String?, nick: String?) {
- if (index < comments.size && (comment != null) && !nick.isNullOrBlank()) {
+ if (index < comments.size && !comment.isNullOrBlank() && !nick.isNullOrBlank()) {
comments[index] = EntryComment(comment, nick)
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsMgr.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsMgr.kt
new file mode 100644
index 0000000..ccbcd46
--- /dev/null
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsMgr.kt
@@ -0,0 +1,190 @@
+/*
+ * FeedsMgr.kt
+ *
+ * Copyright (c) 2004-2021, Erik C. Thauvin (erik@thauvin.net)
+ * All rights reserved.
+ *
+ * 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.entries
+
+import com.rometools.rome.feed.synd.SyndContentImpl
+import com.rometools.rome.feed.synd.SyndEntry
+import com.rometools.rome.feed.synd.SyndEntryImpl
+import com.rometools.rome.feed.synd.SyndFeed
+import com.rometools.rome.feed.synd.SyndFeedImpl
+import com.rometools.rome.io.FeedException
+import com.rometools.rome.io.SyndFeedInput
+import com.rometools.rome.io.SyndFeedOutput
+import net.thauvin.erik.mobibot.Utils.toIsoLocalDate
+import net.thauvin.erik.mobibot.Utils.today
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import java.io.IOException
+import java.io.InputStreamReader
+import java.io.OutputStreamWriter
+import java.nio.charset.StandardCharsets
+import java.nio.file.Files
+import java.nio.file.Paths
+import java.util.Calendar
+import kotlin.io.path.exists
+
+/**
+ * Manages the RSS feeds.
+ */
+class FeedsMgr private constructor() {
+ companion object {
+ private val logger: Logger = LoggerFactory.getLogger(FeedsMgr::class.java)
+
+ // The file containing the current entries.
+ private const val currentXml = "current.xml"
+
+ // The .xml extension.
+ private const val dotXml = ".xml"
+
+ /**
+ * Loads the current feed.
+ */
+ @Throws(IOException::class, FeedException::class)
+ fun loadFeed(entries: Entries, currentFile: String = currentXml): String {
+ entries.links.clear()
+ val xml = Paths.get("${entries.logsDir}${currentFile}")
+ var pubDate = today()
+ if (xml.exists()) {
+ val input = SyndFeedInput()
+ InputStreamReader(
+ Files.newInputStream(xml), StandardCharsets.UTF_8
+ ).use { reader ->
+ val feed = input.build(reader)
+ pubDate = feed.publishedDate.toIsoLocalDate()
+ val items = feed.entries
+ var entry: EntryLink
+ for (i in items.indices.reversed()) {
+ with(items[i]) {
+ entry = EntryLink(
+ link,
+ title,
+ author.substring(author.lastIndexOf('(') + 1, author.length - 1),
+ entries.channel,
+ publishedDate,
+ categories
+ )
+ var split: List
+ for (comment in description.value.split("
")) {
+ split = comment.split(": ".toRegex(), 2)
+ if (split.size == 2) {
+ entry.addComment(comment = split[1].trim(), nick = split[0].trim())
+ }
+ }
+ }
+ entries.links.add(entry)
+ }
+ }
+ } else {
+ // Create an empty feed.
+ saveFeed(entries)
+ }
+ return pubDate
+ }
+
+ /**
+ * Saves the feeds.
+ */
+ fun saveFeed(entries: Entries, currentFile: String = currentXml) {
+ if (logger.isDebugEnabled) logger.debug("Saving the feeds...")
+ if (entries.logsDir.isNotBlank()) {
+ try {
+ val output = SyndFeedOutput()
+ val rss: SyndFeed = SyndFeedImpl()
+ val items: MutableList = mutableListOf()
+ var item: SyndEntry
+ OutputStreamWriter(
+ Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8
+ ).use { fw ->
+ with(rss) {
+ feedType = "rss_2.0"
+ title = "${entries.channel} IRC Links"
+ description = "Links from ${entries.ircServer} on ${entries.channel}"
+ if (entries.backlogs.isNotBlank()) link = entries.backlogs
+ publishedDate = Calendar.getInstance().time
+ language = "en"
+ }
+ val buff: StringBuilder = StringBuilder()
+ for (i in entries.links.indices.reversed()) {
+ with(entries.links[i]) {
+ buff.setLength(0)
+ buff.append("Posted by ")
+ .append(nick)
+ .append(" on ")
+ .append(channel)
+ .append("")
+ if (comments.size > 0) {
+ buff.append("
")
+ for (j in comments.indices) {
+ if (j > 0) {
+ buff.append("
")
+ }
+ buff.append(comments[j].nick).append(": ").append(comments[j].comment)
+ }
+ }
+ item = SyndEntryImpl()
+ item.link = link
+ item.description = SyndContentImpl().apply { value = buff.toString() }
+ item.title = title
+ item.publishedDate = date
+ item.author = "${channel.substring(1)}@${entries.ircServer} ($nick)"
+ item.categories = tags
+ items.add(item)
+ }
+ }
+ rss.entries = items
+ if (logger.isDebugEnabled) logger.debug("Writing the entries feed.")
+ output.output(rss, fw)
+ }
+ OutputStreamWriter(
+ Files.newOutputStream(
+ Paths.get(
+ entries.logsDir + today() + dotXml
+ )
+ ), StandardCharsets.UTF_8
+ ).use { fw -> output.output(rss, fw) }
+ } catch (e: FeedException) {
+ if (logger.isWarnEnabled) logger.warn("Unable to generate the entries feed.", e)
+ } catch (e: IOException) {
+ if (logger.isWarnEnabled)
+ logger.warn("An IO error occurred while generating the entries feed.", e)
+ }
+ } else {
+ if (logger.isWarnEnabled) {
+ logger.warn("Unable to generate the entries feed. A required property is missing.")
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt
index 3c46fb4..372ef2d 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt
@@ -31,13 +31,16 @@
*/
package net.thauvin.erik.mobibot.modules
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.buildCmdSyntax
+import net.thauvin.erik.mobibot.Utils.sendMessage
+import org.pircbotx.hooks.events.PrivateMessageEvent
+import org.pircbotx.hooks.types.GenericMessageEvent
/**
* The `Module` abstract class.
*/
-abstract class AbstractModule(val bot: Mobibot) {
+abstract class AbstractModule {
/**
* The module's commands, if any.
*/
@@ -51,12 +54,7 @@ abstract class AbstractModule(val bot: Mobibot) {
/**
* Responds to a command.
*/
- abstract fun commandResponse(
- sender: String,
- cmd: String,
- args: String,
- isPrivate: Boolean
- )
+ abstract fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)
/**
* Returns the module's property keys.
@@ -74,9 +72,9 @@ abstract class AbstractModule(val bot: Mobibot) {
/**
* Responds with the module's help.
*/
- open fun helpResponse(sender: String, isPrivate: Boolean): Boolean {
+ open fun helpResponse(event: GenericMessageEvent): Boolean {
for (h in help) {
- bot.send(sender, buildCmdSyntax(h, bot.nick, isPrivateMsgEnabled && isPrivate), isPrivate)
+ event.sendMessage(buildCmdSyntax(h, event.bot().nick, isPrivateMsgEnabled && event is PrivateMessageEvent))
}
return true
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt
index 5ff5c73..efe87e5 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt
@@ -33,35 +33,32 @@ package net.thauvin.erik.mobibot.modules
import net.objecthunter.exp4j.ExpressionBuilder
import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.bold
import net.thauvin.erik.mobibot.Utils.helpFormat
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import java.text.DecimalFormat
/**
* The Calc module.
*/
-class Calc(bot: Mobibot) : AbstractModule(bot) {
- override fun commandResponse(
- sender: String,
- cmd: String,
- args: String,
- isPrivate: Boolean
- ) {
+class Calc : AbstractModule() {
+ private val logger: Logger = LoggerFactory.getLogger(Calc::class.java)
+
+ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
if (args.isNotBlank()) {
- with(bot) {
- try {
- send(calculate(args))
- } catch (e: IllegalArgumentException) {
- if (logger.isWarnEnabled) logger.warn("Failed to calculate: $args", e)
- send("No idea. This is the kind of math I don't get.")
- } catch (e: UnknownFunctionOrVariableException) {
- if (logger.isWarnEnabled) logger.warn("Unable to calculate: $args", e)
- send("No idea. I must've some form of Dyscalculia.")
- }
+ try {
+ event.respond(calculate(args))
+ } catch (e: IllegalArgumentException) {
+ if (logger.isWarnEnabled) logger.warn("Failed to calculate: $args", e)
+ event.respond("No idea. This is the kind of math I don't get.")
+ } catch (e: UnknownFunctionOrVariableException) {
+ if (logger.isWarnEnabled) logger.warn("Unable to calculate: $args", e)
+ event.respond("No idea. I must've some form of Dyscalculia.")
}
} else {
- helpResponse(sender, isPrivate)
+ helpResponse(event)
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt
index db28550..6cd8906 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt
@@ -34,40 +34,44 @@ package net.thauvin.erik.mobibot.modules
import net.thauvin.erik.crypto.CryptoException
import net.thauvin.erik.crypto.CryptoPrice
import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.msg.PublicMessage
+import net.thauvin.erik.mobibot.Utils.sendMessage
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import java.io.IOException
/**
* The Cryptocurrency Prices module.
*/
-class CryptoPrices(bot: Mobibot) : ThreadedModule(bot) {
+class CryptoPrices : ThreadedModule() {
+ private val logger: Logger = LoggerFactory.getLogger(CryptoPrices::class.java)
+
/**
* Returns the cryptocurrency market price from [Coinbase](https://developers.coinbase.com/api/v2#get-spot-price).
*/
- override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
+ override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
val debugMessage = "crypto($cmd $args)"
- with(bot) {
- if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) {
- try {
- val price = currentPrice(args.split(' '))
- val amount = try {
- price.toCurrency()
- } catch (ignore: IllegalArgumentException) {
- price.amount
- }
- send(sender, PublicMessage("${price.base}: $amount [${price.currency}]"))
- } catch (e: CryptoException) {
- if (logger.isWarnEnabled) logger.warn("$debugMessage => ${e.statusCode}", e)
- send(e.message)
- } catch (e: Exception) {
- if (logger.isErrorEnabled) logger.error(debugMessage, e)
- send("An error has occurred while retrieving the cryptocurrency market price.")
+ if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) {
+ try {
+ val price = currentPrice(args.split(' '))
+ val amount = try {
+ price.toCurrency()
+ } catch (ignore: IllegalArgumentException) {
+ price.amount
}
- } else {
- helpResponse(sender, isPrivate)
+ event.respond("${price.base} current price is $amount [${price.currency}]")
+ } catch (e: CryptoException) {
+ if (logger.isWarnEnabled) logger.warn("$debugMessage => ${e.statusCode}", e)
+ event.sendMessage(e.message!!)
+ } catch (e: IOException) {
+ if (logger.isErrorEnabled) logger.error(debugMessage, e)
+ event.sendMessage("An IO error has occurred while retrieving the cryptocurrency market price.")
}
+ } else {
+ helpResponse(event)
}
+
}
companion object {
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt
index e0b7088..cd4bb67 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt
@@ -31,16 +31,21 @@
*/
package net.thauvin.erik.mobibot.modules
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.bold
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.buildCmdSyntax
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendList
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.Utils.today
import net.thauvin.erik.mobibot.msg.ErrorMessage
import net.thauvin.erik.mobibot.msg.Message
import net.thauvin.erik.mobibot.msg.PublicMessage
import org.jdom2.JDOMException
import org.jdom2.input.SAXBuilder
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import java.io.IOException
import java.net.URL
import java.text.NumberFormat
@@ -51,84 +56,68 @@ import javax.xml.XMLConstants
/**
* The CurrencyConverter module.
*/
-class CurrencyConverter(bot: Mobibot) : ThreadedModule(bot) {
- override fun commandResponse(
- sender: String,
- cmd: String,
- args: String,
- isPrivate: Boolean
- ) {
+class CurrencyConverter : ThreadedModule() {
+ private val logger: Logger = LoggerFactory.getLogger(CurrencyConverter::class.java)
+
+ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
synchronized(this) {
if (pubDate != today()) {
EXCHANGE_RATES.clear()
}
}
- super.commandResponse(sender, cmd, args, isPrivate)
+ super.commandResponse(channel, cmd, args, event)
}
/**
* Converts the specified currencies.
*/
- override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
- bot.apply {
- if (EXCHANGE_RATES.isEmpty()) {
- try {
- loadRates()
- } catch (e: ModuleException) {
- if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
- }
+ override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
+ if (EXCHANGE_RATES.isEmpty()) {
+ try {
+ loadRates()
+ } catch (e: ModuleException) {
+ if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
}
+ }
- if (EXCHANGE_RATES.isEmpty()) {
- send(sender, EMPTY_RATE_TABLE, true)
- } else if (args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+".toRegex())) {
- val msg = convertCurrency(args)
- send(sender, msg)
- if (msg.isError) {
- helpResponse(sender, isPrivate)
- }
- } else if (args.contains(CURRENCY_RATES_KEYWORD)) {
- send(sender, "The reference rates for ${bold(pubDate)} are:", isPrivate)
- @Suppress("MagicNumber")
- sendList(sender, currencyRates(), 3, " ", isPrivate, isIndent = true)
- } else {
- helpResponse(sender, isPrivate)
+ if (EXCHANGE_RATES.isEmpty()) {
+ event.respond(EMPTY_RATE_TABLE)
+ } else if (args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+".toRegex())) {
+ val msg = convertCurrency(args)
+ event.respond(msg.msg)
+ if (msg.isError) {
+ helpResponse(event)
}
+ } else if (args.contains(CURRENCY_RATES_KEYWORD)) {
+ event.sendMessage("The reference rates for ${bold(pubDate)} are:")
+ event.sendList(currencyRates(), 3, " ", isIndent = true)
+ } else {
+ helpResponse(event)
}
}
- override fun helpResponse(sender: String, isPrivate: Boolean): Boolean {
- with(bot) {
- if (EXCHANGE_RATES.isEmpty()) {
- try {
- loadRates()
- } catch (e: ModuleException) {
- if (logger.isDebugEnabled) logger.debug(e.debugMessage, e)
- }
+ override fun helpResponse(event: GenericMessageEvent): Boolean {
+ if (EXCHANGE_RATES.isEmpty()) {
+ try {
+ loadRates()
+ } catch (e: ModuleException) {
+ if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
}
- if (EXCHANGE_RATES.isEmpty()) {
- send(sender, EMPTY_RATE_TABLE, isPrivate)
- } else {
- send(sender, "To convert from one currency to another:", isPrivate)
- send(
- sender,
- helpFormat(
- buildCmdSyntax("%c $CURRENCY_CMD 100 USD to EUR", nick, isPrivateMsgEnabled)
- ),
- isPrivate
+ }
+ if (EXCHANGE_RATES.isEmpty()) {
+ event.sendMessage(EMPTY_RATE_TABLE)
+ } else {
+ val nick = event.bot().nick
+ event.sendMessage("To convert from one currency to another:")
+ event.sendMessage(helpFormat(buildCmdSyntax("%c $CURRENCY_CMD 100 USD to EUR", nick, isPrivateMsgEnabled)))
+ event.sendMessage("For a listing of current reference rates:")
+ event.sendMessage(
+ helpFormat(
+ buildCmdSyntax("%c $CURRENCY_CMD $CURRENCY_RATES_KEYWORD", nick, isPrivateMsgEnabled)
)
- send(sender, "For a listing of current reference rates:", isPrivate)
- send(
- sender,
- helpFormat(
- buildCmdSyntax("%c $CURRENCY_CMD $CURRENCY_RATES_KEYWORD", nick, isPrivateMsgEnabled)
- ),
- isPrivate
- )
- send(sender, "The supported currencies are: ", isPrivate)
- @Suppress("MagicNumber")
- sendList(sender, ArrayList(EXCHANGE_RATES.keys), 11, isPrivate = isPrivate, isIndent = true)
- }
+ )
+ event.sendMessage("The supported currencies are: ")
+ event.sendList(ArrayList(EXCHANGE_RATES.keys), 11, isIndent = true)
}
return true
}
@@ -161,7 +150,6 @@ class CurrencyConverter(bot: Mobibot) : ThreadedModule(bot) {
/**
* Converts from a currency to another.
*/
- @Suppress("MagicNumber")
@JvmStatic
fun convertCurrency(query: String): Message {
val cmds = query.split(" ")
@@ -194,7 +182,6 @@ class CurrencyConverter(bot: Mobibot) : ThreadedModule(bot) {
fun currencyRates(): List {
val rates = mutableListOf()
for ((key, value) in EXCHANGE_RATES.toSortedMap()) {
- @Suppress("MagicNumber")
rates.add("$key: ${value.padStart(8)}")
}
return rates
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt
index 57e78ca..4b7257e 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt
@@ -31,37 +31,33 @@
*/
package net.thauvin.erik.mobibot.modules
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bold
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import org.pircbotx.hooks.types.GenericMessageEvent
import kotlin.random.Random
/**
* The Dice module.
*/
-class Dice(bot: Mobibot) : AbstractModule(bot) {
- override fun commandResponse(
- sender: String,
- cmd: String,
- args: String,
- isPrivate: Boolean
- ) {
+class Dice : AbstractModule() {
+ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
val botRoll = roll()
val roll = roll()
val botTotal = botRoll.first + botRoll.second
val total = roll.first + roll.second
- with(bot) {
- send(
- channel,
- "$sender rolled ${total}: ${DICE_FACES[roll.first]} ${DICE_FACES[roll.second]}",
- isPrivate
+ with(event.bot()) {
+ event.respond(
+ "you rolled ${DICE_FACES[roll.first]} ${DICE_FACES[roll.second]} for a total of ${bold(total)}"
)
- action(
- "rolled ${botTotal}: ${DICE_FACES[botRoll.first]} ${DICE_FACES[botRoll.second]}"
+ sendIRC().action(
+ channel,
+ "rolled ${DICE_FACES[botRoll.first]} ${DICE_FACES[botRoll.second]} for a total of ${bold(botTotal)}"
)
when (winLoseOrTie(botTotal, total)) {
- Result.WIN -> action("wins.")
- Result.LOSE -> action("lost.")
- else -> action("tied.")
+ Result.WIN -> sendIRC().action(channel, "wins.")
+ Result.LOSE -> sendIRC().action(channel, "lost.")
+ else -> sendIRC().action(channel, "tied.")
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt
index 5c1a268..9571556 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt
@@ -31,45 +31,49 @@
*/
package net.thauvin.erik.mobibot.modules
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.capitalise
import net.thauvin.erik.mobibot.Utils.encodeUrl
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.Utils.unescapeXml
import net.thauvin.erik.mobibot.Utils.urlReader
+import net.thauvin.erik.mobibot.msg.ErrorMessage
import net.thauvin.erik.mobibot.msg.Message
import net.thauvin.erik.mobibot.msg.NoticeMessage
-import org.jibble.pircbot.Colors
import org.json.JSONException
import org.json.JSONObject
+import org.pircbotx.Colors
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import java.io.IOException
import java.net.URL
/**
* The GoogleSearch module.
*/
-class GoogleSearch(bot: Mobibot) : ThreadedModule(bot) {
+class GoogleSearch : ThreadedModule() {
+ private val logger: Logger = LoggerFactory.getLogger(GoogleSearch::class.java)
+
/**
* Searches Google.
*/
- override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
- with(bot) {
- if (args.isNotBlank()) {
- try {
- val results = searchGoogle(
- args, properties[GOOGLE_API_KEY_PROP],
- properties[GOOGLE_CSE_KEY_PROP]
- )
- for (msg in results) {
- send(sender, msg)
- }
- } catch (e: ModuleException) {
- if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
- send(sender, e.message, isPrivate)
+ override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
+ if (args.isNotBlank()) {
+ try {
+ val results = searchGoogle(
+ args, properties[GOOGLE_API_KEY_PROP],
+ properties[GOOGLE_CSE_KEY_PROP]
+ )
+ for (msg in results) {
+ event.sendMessage(channel, msg)
}
- } else {
- helpResponse(sender, isPrivate)
+ } catch (e: ModuleException) {
+ if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
+ event.sendMessage(e.message!!)
}
+ } else {
+ helpResponse(event)
}
}
@@ -92,29 +96,33 @@ class GoogleSearch(bot: Mobibot) : ThreadedModule(bot) {
if (apiKey.isNullOrBlank() || cseKey.isNullOrBlank()) {
throw ModuleException("${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing.")
}
- return if (query.isNotBlank()) {
- val results = mutableListOf()
+ val results = mutableListOf()
+ if (query.isNotBlank()) {
try {
val url = URL(
"https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" +
"&q=${encodeUrl(query)}&filter=1&num=5&alt=json"
)
val json = JSONObject(urlReader(url))
- val ja = json.getJSONArray("items")
- for (i in 0 until ja.length()) {
- val j = ja.getJSONObject(i)
- results.add(NoticeMessage(unescapeXml(j.getString("title"))))
- results.add(NoticeMessage(helpFormat(j.getString("link"), false), Colors.DARK_GREEN))
+ if (json.has("items")) {
+ val ja = json.getJSONArray("items")
+ for (i in 0 until ja.length()) {
+ val j = ja.getJSONObject(i)
+ results.add(NoticeMessage(unescapeXml(j.getString("title"))))
+ results.add(NoticeMessage(helpFormat(j.getString("link"), false), Colors.DARK_GREEN))
+ }
+ } else {
+ results.add(ErrorMessage("No results found.", Colors.RED))
}
} catch (e: IOException) {
throw ModuleException("searchGoogle($query)", "An IO error has occurred searching Google.", e)
} catch (e: JSONException) {
throw ModuleException("searchGoogle($query)", "A JSON error has occurred searching Google.", e)
}
- results
} else {
- throw ModuleException("Invalid query. Please try again.")
+ results.add(ErrorMessage("Invalid query. Please try again."))
}
+ return results
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt
index d3e0ca8..2d5af61 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt
@@ -33,42 +33,43 @@ package net.thauvin.erik.mobibot.modules
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.cyan
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.Utils.urlReader
import net.thauvin.erik.mobibot.msg.Message
import net.thauvin.erik.mobibot.msg.PublicMessage
import org.json.JSONException
import org.json.JSONObject
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import java.io.IOException
import java.net.URL
/**
* The Joke module.
*/
-class Joke(bot: Mobibot) : ThreadedModule(bot) {
- override fun commandResponse(
- sender: String,
- cmd: String,
- args: String,
- isPrivate: Boolean
- ) {
+class Joke : ThreadedModule() {
+ private val logger: Logger = LoggerFactory.getLogger(Joke::class.java)
+
+ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
runBlocking {
- launch { run(sender, cmd, args, isPrivate) }
+ launch { run(channel, cmd, args, event) }
}
}
/**
* Returns a random joke from [The Internet Chuck Norris Database](http://www.icndb.com/).
*/
- override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
- with(bot) {
+ override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
+ with(event.bot()) {
try {
- send(cyan(randomJoke().msg))
+ sendIRC().notice(channel, cyan(randomJoke().msg))
} catch (e: ModuleException) {
if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
- send(sender, e.message, isPrivate)
+ event.sendMessage(e.message!!)
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt
index e1557d9..703f138 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt
@@ -32,9 +32,12 @@
package net.thauvin.erik.mobibot.modules
import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
import org.apache.commons.net.whois.WhoisClient
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import java.io.IOException
import java.net.InetAddress
import java.net.UnknownHostException
@@ -42,52 +45,51 @@ import java.net.UnknownHostException
/**
* The Lookup module.
*/
-class Lookup(bot: Mobibot) : AbstractModule(bot) {
- override fun commandResponse(
- sender: String,
- cmd: String,
- args: String,
- isPrivate: Boolean
- ) {
+class Lookup : AbstractModule() {
+ private val logger: Logger = LoggerFactory.getLogger(Lookup::class.java)
+
+ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
if (args.matches("(\\S.)+(\\S)+".toRegex())) {
- with(bot) {
- try {
- nslookup(args).split(',').forEach {
- send(it.trim())
- }
- } catch (ignore: UnknownHostException) {
- if (args.matches(
- ("(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
- "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
- "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)").toRegex()
- )
- ) {
- try {
- val lines = whois(args)
- if (lines.isNotEmpty()) {
- var line: String
- for (rawLine in lines) {
- line = rawLine.trim()
- if (line.isNotEmpty() && line[0] != '#') {
- send(line)
+ try {
+ event.respondWith(nslookup(args).prependIndent())
+ } catch (ignore: UnknownHostException) {
+ if (args.matches(
+ ("(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
+ "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
+ "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)").toRegex()
+ )
+ ) {
+ try {
+ val lines = whois(args)
+ if (lines.isNotEmpty()) {
+ var line: String
+ var hasData = false
+ for (rawLine in lines) {
+ line = rawLine.trim()
+ if (line.matches("^\\b(?!\\b[Cc]omment\\b)\\w+\\b: .*$".toRegex())) {
+ if (!hasData) {
+ event.respondWith(line)
+ hasData = true
+ } else {
+ event.bot().sendIRC().notice(event.user.nick, line)
}
}
- } else {
- send("Unknown host.")
}
- } catch (ioe: IOException) {
- if (logger.isDebugEnabled) {
- logger.debug("Unable to perform whois IP lookup: $args", ioe)
- }
- send("Unable to perform whois IP lookup: ${ioe.message}")
+ } else {
+ event.respond("Unknown host.")
}
- } else {
- send("Unknown host.")
+ } catch (ioe: IOException) {
+ if (logger.isWarnEnabled) {
+ logger.warn("Unable to perform whois IP lookup: $args", ioe)
+ }
+ event.respond("Unable to perform whois IP lookup: ${ioe.message}")
}
+ } else {
+ event.respond("Unknown host.")
}
}
} else {
- helpResponse(sender, true)
+ helpResponse(event)
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt
index 0a97d7b..9d49118 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt
@@ -31,24 +31,20 @@
*/
package net.thauvin.erik.mobibot.modules
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.helpFormat
+import org.pircbotx.hooks.types.GenericMessageEvent
import kotlin.random.Random
/**
* The Ping module.
*/
-class Ping(bot: Mobibot) : AbstractModule(bot) {
+class Ping : AbstractModule() {
/**
* {@inheritDoc}
*/
- override fun commandResponse(
- sender: String,
- cmd: String,
- args: String,
- isPrivate: Boolean
- ) {
- bot.action(randomPing())
+ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
+ event.bot().sendIRC().action(channel, randomPing())
}
companion object {
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt
index 33b1fce..20c5c29 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt
@@ -32,16 +32,17 @@
package net.thauvin.erik.mobibot.modules
-import net.thauvin.erik.mobibot.Mobibot
+import net.thauvin.erik.mobibot.Utils.bot
import net.thauvin.erik.mobibot.Utils.capitalise
import net.thauvin.erik.mobibot.Utils.helpFormat
+import org.pircbotx.hooks.types.GenericMessageEvent
import kotlin.random.Random
/**
* Simple module example in Kotlin.
*/
-class RockPaperScissors(bot: Mobibot) : AbstractModule(bot) {
+class RockPaperScissors : AbstractModule() {
init {
with(commands) {
add(Hands.ROCK.name.lowercase())
@@ -101,20 +102,26 @@ class RockPaperScissors(bot: Mobibot) : AbstractModule(bot) {
}
}
- override fun commandResponse(sender: String, cmd: String, args: String, isPrivate: Boolean) {
+ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
val hand = Hands.valueOf(cmd.uppercase())
val botHand = Hands.values()[Random.nextInt(0, Hands.values().size)]
- with(bot) {
- send("${hand.emoji} vs. ${botHand.emoji}")
+ with(event.bot()) {
+ sendIRC().message(channel, "${hand.emoji} vs. ${botHand.emoji}")
when {
hand == botHand -> {
- action("tied.")
+ sendIRC().action(channel, "tied.")
}
hand.beats(botHand) -> {
- action("lost. ${hand.name.capitalise()} ${hand.action} ${botHand.name.lowercase()}.")
+ sendIRC().action(
+ channel,
+ "lost. ${hand.name.capitalise()} ${hand.action} ${botHand.name.lowercase()}."
+ )
}
else -> {
- action("wins. ${botHand.name.capitalise()} ${botHand.action} ${hand.name.lowercase()}.")
+ sendIRC().action(
+ channel,
+ "wins. ${botHand.name.capitalise()} ${botHand.action} ${hand.name.lowercase()}."
+ )
}
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt
index f418185..230e2af 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt
@@ -31,10 +31,10 @@
*/
package net.thauvin.erik.mobibot.modules
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.capitalise
import net.thauvin.erik.mobibot.Utils.encodeUrl
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.Utils.unescapeXml
import net.thauvin.erik.mobibot.Utils.urlReader
import net.thauvin.erik.mobibot.msg.ErrorMessage
@@ -43,31 +43,34 @@ import net.thauvin.erik.mobibot.msg.NoticeMessage
import net.thauvin.erik.mobibot.msg.PublicMessage
import org.json.JSONException
import org.json.JSONObject
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import java.io.IOException
import java.net.URL
/**
* The StockQuote module.
*/
-class StockQuote(bot: Mobibot) : ThreadedModule(bot) {
+class StockQuote : ThreadedModule() {
+ private val logger: Logger = LoggerFactory.getLogger(StockQuote::class.java)
+
/**
* Returns the specified stock quote from Alpha Vantage.
*/
- override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
- with(bot) {
- if (args.isNotBlank()) {
- try {
- val messages = getQuote(args, properties[ALPHAVANTAGE_API_KEY_PROP])
- for (msg in messages) {
- send(sender, msg)
- }
- } catch (e: ModuleException) {
- if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
- send(e.message)
+ override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
+ if (args.isNotBlank()) {
+ try {
+ val messages = getQuote(args, properties[ALPHAVANTAGE_API_KEY_PROP])
+ for (msg in messages) {
+ event.sendMessage(channel, msg)
}
- } else {
- helpResponse(sender, isPrivate)
+ } catch (e: ModuleException) {
+ if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
+ event.sendMessage(e.message!!)
}
+ } else {
+ helpResponse(event)
}
}
@@ -129,9 +132,9 @@ class StockQuote(bot: Mobibot) : ThreadedModule(bot) {
"${STOCK_CMD.capitalise()} is disabled. The API key is missing."
)
}
- return if (symbol.isNotBlank()) {
+ val messages = mutableListOf()
+ if (symbol.isNotBlank()) {
val debugMessage = "getQuote($symbol)"
- val messages = mutableListOf()
var response: String
try {
with(messages) {
@@ -161,56 +164,55 @@ class StockQuote(bot: Mobibot) : ThreadedModule(bot) {
val quote = json.getJSONObject("Global Quote")
if (quote.isEmpty) {
add(ErrorMessage(INVALID_SYMBOL))
- return messages
- }
+ } else {
- add(
- PublicMessage(
- "Symbol: " + unescapeXml(quote.getString("01. symbol"))
- + " [" + unescapeXml(symbolInfo.getString("2. name")) + ']'
+ add(
+ PublicMessage(
+ "Symbol: " + unescapeXml(quote.getString("01. symbol"))
+ + " [" + unescapeXml(symbolInfo.getString("2. name")) + ']'
+ )
)
- )
- @Suppress("MagicNumber")
- val pad = 10
+ val pad = 10
- add(
- PublicMessage(
- "Price:".padEnd(pad).prependIndent()
- + unescapeXml(quote.getString("05. price"))
+ add(
+ PublicMessage(
+ "Price:".padEnd(pad).prependIndent()
+ + unescapeXml(quote.getString("05. price"))
+ )
)
- )
- add(
- PublicMessage(
- "Previous:".padEnd(pad).prependIndent()
- + unescapeXml(quote.getString("08. previous close"))
+ add(
+ PublicMessage(
+ "Previous:".padEnd(pad).prependIndent()
+ + unescapeXml(quote.getString("08. previous close"))
+ )
)
- )
- val data = arrayOf(
- "Open" to "02. open",
- "High" to "03. high",
- "Low" to "04. low",
- "Volume" to "06. volume",
- "Latest" to "07. latest trading day"
- )
+ val data = arrayOf(
+ "Open" to "02. open",
+ "High" to "03. high",
+ "Low" to "04. low",
+ "Volume" to "06. volume",
+ "Latest" to "07. latest trading day"
+ )
+
+ data.forEach {
+ add(
+ NoticeMessage(
+ "${it.first}:".padEnd(pad).prependIndent()
+ + unescapeXml(quote.getString(it.second))
+ )
+ )
+ }
- data.forEach {
add(
NoticeMessage(
- "${it.first}:".padEnd(pad).prependIndent()
- + unescapeXml(quote.getString(it.second))
+ "Change:".padEnd(pad).prependIndent()
+ + unescapeXml(quote.getString("09. change"))
+ + " [" + unescapeXml(quote.getString("10. change percent")) + ']'
)
)
}
-
- add(
- NoticeMessage(
- "Change:".padEnd(pad).prependIndent()
- + unescapeXml(quote.getString("09. change"))
- + " [" + unescapeXml(quote.getString("10. change percent")) + ']'
- )
- )
}
}
} catch (e: IOException) {
@@ -218,10 +220,10 @@ class StockQuote(bot: Mobibot) : ThreadedModule(bot) {
} catch (e: NullPointerException) {
throw ModuleException(debugMessage, "An error has occurred retrieving a stock quote.", e)
}
- messages
} else {
- throw ModuleException(INVALID_SYMBOL)
+ messages.add(ErrorMessage(INVALID_SYMBOL))
}
+ return messages
}
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ThreadedModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ThreadedModule.kt
index d1d58d0..b44aab1 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ThreadedModule.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ThreadedModule.kt
@@ -33,36 +33,26 @@ package net.thauvin.erik.mobibot.modules
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
-import net.thauvin.erik.mobibot.Mobibot
+import org.pircbotx.hooks.types.GenericMessageEvent
/**
* The `ThreadedModule` class.
*/
-abstract class ThreadedModule(bot: Mobibot) : AbstractModule(bot) {
- override fun commandResponse(
- sender: String,
- cmd: String,
- args: String,
- isPrivate: Boolean
- ) {
- if (isEnabled && args.isNotEmpty()) {
+abstract class ThreadedModule : AbstractModule() {
+ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
+ if (isEnabled && event.message.isNotEmpty()) {
runBlocking {
launch {
- run(sender, cmd, args, isPrivate)
+ run(channel, cmd, args, event)
}
}
} else {
- helpResponse(sender, isPrivate)
+ helpResponse(event)
}
}
/**
* Runs the thread.
*/
- abstract fun run(
- sender: String,
- cmd: String,
- args: String,
- isPrivate: Boolean
- )
+ abstract fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent)
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt
index 17f2557..f6020e3 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt
@@ -34,21 +34,26 @@ package net.thauvin.erik.mobibot.modules
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import net.thauvin.erik.mobibot.Constants
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.TwitterTimer
import net.thauvin.erik.mobibot.Utils.helpFormat
import net.thauvin.erik.mobibot.commands.links.LinksMgr
import net.thauvin.erik.mobibot.entries.EntriesUtils
-import net.thauvin.erik.mobibot.msg.Message
-import net.thauvin.erik.mobibot.msg.NoticeMessage
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import twitter4j.TwitterException
import twitter4j.TwitterFactory
import twitter4j.conf.ConfigurationBuilder
+import java.util.Timer
/**
* The Twitter module.
*/
-class Twitter(bot: Mobibot) : ThreadedModule(bot) {
+class Twitter : ThreadedModule() {
+ private val logger: Logger = LoggerFactory.getLogger(Twitter::class.java)
+
+ private val timer = Timer(true)
+
// Twitter auto-posts.
private val entries: MutableSet = HashSet()
@@ -87,16 +92,14 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) {
* Send a notification to the registered Twitter handle.
*/
fun notification(msg: String) {
- with(bot) {
- if (isEnabled && !handle.isNullOrBlank()) {
- runBlocking {
- launch {
- try {
- post(message = msg, isDm = true)
- if (logger.isDebugEnabled) logger.debug("Notified @$handle: $msg")
- } catch (e: ModuleException) {
- if (logger.isWarnEnabled) logger.warn("Failed to notify @$handle: $msg", e)
- }
+ if (isEnabled && !handle.isNullOrBlank()) {
+ runBlocking {
+ launch {
+ try {
+ post(message = msg, isDm = true)
+ if (logger.isDebugEnabled) logger.debug("Notified @$handle: $msg")
+ } catch (e: ModuleException) {
+ if (logger.isWarnEnabled) logger.warn("Failed to notify @$handle: $msg", e)
}
}
}
@@ -107,7 +110,7 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) {
* Posts on Twitter.
*/
@Throws(ModuleException::class)
- fun post(handle: String = "${properties[HANDLE_PROP]}", message: String, isDm: Boolean): Message {
+ fun post(handle: String = "${properties[HANDLE_PROP]}", message: String, isDm: Boolean): String {
return twitterPost(
properties[CONSUMER_KEY_PROP],
properties[CONSUMER_SECRET_PROP],
@@ -123,35 +126,32 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) {
* Post an entry to twitter.
*/
fun postEntry(index: Int) {
- with(bot) {
- if (isAutoPost && hasEntry(index) && LinksMgr.entries.size >= index) {
- val entry = LinksMgr.entries[index]
- val msg = "${entry.title} ${entry.link} via ${entry.nick} on $channel"
- runBlocking {
- launch {
- try {
- if (logger.isDebugEnabled) {
- logger.debug("Posting {} to Twitter.", EntriesUtils.buildLinkCmd(index))
- }
- post(message = msg, isDm = false)
- } catch (e: ModuleException) {
- if (logger.isWarnEnabled) logger.warn("Failed to post entry on Twitter.", e)
+ if (isAutoPost && hasEntry(index) && LinksMgr.entries.links.size >= index) {
+ val entry = LinksMgr.entries.links[index]
+ val msg = "${entry.title} ${entry.link} via ${entry.nick} on ${entry.channel}"
+ runBlocking {
+ launch {
+ try {
+ if (logger.isDebugEnabled) {
+ logger.debug("Posting {} to Twitter.", EntriesUtils.buildLinkLabel(index))
}
+ post(message = msg, isDm = false)
+ } catch (e: ModuleException) {
+ if (logger.isWarnEnabled) logger.warn("Failed to post entry on Twitter.", e)
}
}
- removeEntry(index)
}
+ removeEntry(index)
}
}
fun queueEntry(index: Int) {
if (isAutoPost) {
addEntry(index)
- if (bot.logger.isDebugEnabled) {
- bot.logger.debug("Scheduling {} for posting on Twitter.", EntriesUtils.buildLinkCmd(index))
+ if (logger.isDebugEnabled) {
+ logger.debug("Scheduling {} for posting on Twitter.", EntriesUtils.buildLinkLabel(index))
}
- @Suppress("MagicNumber")
- bot.timer.schedule(TwitterTimer(bot, index), Constants.TIMER_DELAY * 60L * 1000L)
+ timer.schedule(TwitterTimer(this, index), Constants.TIMER_DELAY * 60L * 1000L)
}
}
@@ -162,18 +162,12 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) {
/**
* Posts to twitter.
*/
- override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
- with(bot) {
- try {
- send(
- sender,
- post(sender, "$args (by $sender on $channel)", false).msg,
- isPrivate
- )
- } catch (e: ModuleException) {
- if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
- send(sender, e.message, isPrivate)
- }
+ override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
+ try {
+ event.respond(post(event.user.nick, "$args (by ${event.user.nick} on $channel)", false))
+ } catch (e: ModuleException) {
+ if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
+ event.respond(e.message)
}
}
@@ -181,6 +175,7 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) {
* Post all the entries to Twitter on shutdown.
*/
fun shutdown() {
+ timer.cancel()
if (isAutoPost) {
for (index in entries) {
postEntry(index)
@@ -213,23 +208,23 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) {
handle: String?,
message: String,
isDm: Boolean
- ): Message {
+ ): String {
return try {
- val cb = ConfigurationBuilder()
- cb.setDebugEnabled(true)
- .setOAuthConsumerKey(consumerKey)
- .setOAuthConsumerSecret(consumerSecret)
- .setOAuthAccessToken(token).setOAuthAccessTokenSecret(tokenSecret)
+ val cb = ConfigurationBuilder().apply {
+ setDebugEnabled(true)
+ setOAuthConsumerKey(consumerKey)
+ setOAuthConsumerSecret(consumerSecret)
+ setOAuthAccessToken(token)
+ setOAuthAccessTokenSecret(tokenSecret)
+ }
val tf = TwitterFactory(cb.build())
val twitter = tf.instance
if (!isDm) {
val status = twitter.updateStatus(message)
- NoticeMessage(
- "You message was posted to https://twitter.com/${twitter.screenName}/statuses/${status.id}"
- )
+ "Your message was posted to https://twitter.com/${twitter.screenName}/statuses/${status.id}"
} else {
val dm = twitter.sendDirectMessage(handle, message)
- NoticeMessage(dm.text)
+ dm.text
}
} catch (e: TwitterException) {
throw ModuleException("twitterPost($message)", "An error has occurred: ${e.message}", e)
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt
index ef6cb1f..1b2c525 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt
@@ -35,45 +35,48 @@ import net.aksingh.owmjapis.api.APIException
import net.aksingh.owmjapis.core.OWM
import net.aksingh.owmjapis.core.OWM.Country
import net.aksingh.owmjapis.model.CurrentWeather
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.bold
import net.thauvin.erik.mobibot.Utils.capitalise
import net.thauvin.erik.mobibot.Utils.capitalizeWords
import net.thauvin.erik.mobibot.Utils.encodeUrl
import net.thauvin.erik.mobibot.Utils.helpFormat
+import net.thauvin.erik.mobibot.Utils.sendMessage
import net.thauvin.erik.mobibot.msg.ErrorMessage
import net.thauvin.erik.mobibot.msg.Message
import net.thauvin.erik.mobibot.msg.NoticeMessage
import net.thauvin.erik.mobibot.msg.PublicMessage
-import org.jibble.pircbot.Colors
+import org.pircbotx.Colors
+import org.pircbotx.hooks.types.GenericMessageEvent
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import kotlin.math.roundToInt
/**
* The `Weather2` module.
*/
-class Weather2(bot: Mobibot) : ThreadedModule(bot) {
+class Weather2 : ThreadedModule() {
+ private val logger: Logger = LoggerFactory.getLogger(Weather2::class.java)
+
/**
* Fetches the weather data from a specific city.
*/
- override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) {
+ override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
if (args.isNotBlank()) {
- with(bot) {
- try {
- val messages = getWeather(args, properties[OWM_API_KEY_PROP])
- if (messages[0].isError) {
- helpResponse(sender, isPrivate)
- } else {
- for (msg in messages) {
- send(sender, msg)
- }
+ try {
+ val messages = getWeather(args, properties[OWM_API_KEY_PROP])
+ if (messages[0].isError) {
+ helpResponse(event)
+ } else {
+ for (msg in messages) {
+ event.sendMessage(channel, msg)
}
- } catch (e: ModuleException) {
- if (logger.isDebugEnabled) logger.debug(e.debugMessage, e)
- send(e.message)
}
+ } catch (e: ModuleException) {
+ if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
+ event.respond(e.message)
}
} else {
- helpResponse(sender, isPrivate)
+ helpResponse(event)
}
}
@@ -90,7 +93,6 @@ class Weather2(bot: Mobibot) : ThreadedModule(bot) {
* Converts and rounds temperature from °F to °C.
*/
fun ftoC(d: Double?): Pair {
- @Suppress("MagicNumber")
val c = (d!! - 32) * 5 / 9
return d.roundToInt() to c.roundToInt()
}
@@ -208,7 +210,6 @@ class Weather2(bot: Mobibot) : ThreadedModule(bot) {
* Converts and rounds temperature from mph to km/h.
*/
fun mphToKmh(w: Double): Pair {
- @Suppress("MagicNumber")
val kmh = w * 1.60934
return w.roundToInt() to kmh.roundToInt()
}
diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt
index e4deddb..3105d97 100644
--- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt
+++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt
@@ -31,12 +31,11 @@
*/
package net.thauvin.erik.mobibot.modules
-import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils.bold
import net.thauvin.erik.mobibot.Utils.helpFormat
-import net.thauvin.erik.mobibot.msg.ErrorMessage
-import net.thauvin.erik.mobibot.msg.Message
-import net.thauvin.erik.mobibot.msg.PublicMessage
+import net.thauvin.erik.mobibot.Utils.sendList
+import net.thauvin.erik.mobibot.Utils.sendMessage
+import org.pircbotx.hooks.types.GenericMessageEvent
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
@@ -46,7 +45,7 @@ import java.util.Collections
/**
* The WorldTime module.
*/
-class WorldTime(bot: Mobibot) : AbstractModule(bot) {
+class WorldTime : AbstractModule() {
companion object {
// Beats (Internet Time) keyword
const val BEATS_KEYWORD = ".beats"
@@ -57,6 +56,12 @@ class WorldTime(bot: Mobibot) : AbstractModule(bot) {
// The Time command
private const val TIME_CMD = "time"
+ // The zones arguments
+ private const val ZONES_ARGS = "zones"
+
+ // The default zone
+ private const val DEFAULT_ZONE = "PST"
+
// Date/Time Format
private var dtf =
DateTimeFormatter.ofPattern("'The time is ${bold("'HH:mm'")} on ${bold("'EEEE, d MMMM yyyy'")} in '")
@@ -64,342 +69,316 @@ class WorldTime(bot: Mobibot) : AbstractModule(bot) {
/**
* Returns the current Internet (beat) Time.
*/
- @Suppress("MagicNumber", "ImplicitDefaultLocale")
private fun internetTime(): String {
val zdt = ZonedDateTime.now(ZoneId.of("UTC+01:00"))
val beats = ((zdt[ChronoField.SECOND_OF_MINUTE] + zdt[ChronoField.MINUTE_OF_HOUR] * 60
+ zdt[ChronoField.HOUR_OF_DAY] * 3600) / 86.4).toInt()
- return String.format("%c%03d", '@', beats)
+ return "%c%03d".format('@', beats)
}
/**
* Returns the time for the given timezone/city.
*/
@JvmStatic
- fun time(query: String): Message {
- val tz = COUNTRIES_MAP[(query.substring(query.indexOf(' ') + 1).trim()).uppercase()]
- val response: String = if (tz != null) {
+ fun time(query: String = DEFAULT_ZONE): String {
+ val tz = COUNTRIES_MAP[(if (query.isNotBlank()) query.trim().uppercase() else DEFAULT_ZONE)]
+ return if (tz != null) {
if (BEATS_KEYWORD == tz) {
- "The current Internet Time is: ${bold(internetTime())} $BEATS_KEYWORD"
+ "The current Internet Time is ${bold(internetTime())} $BEATS_KEYWORD"
} else {
(ZonedDateTime.now().withZoneSameInstant(ZoneId.of(tz)).format(dtf)
+ bold(tz.substring(tz.lastIndexOf('/') + 1).replace('_', ' ')))
}
} else {
- return ErrorMessage("Unsupported country/zone. Please try again.")
+ "Unsupported country/zone. Please try again."
}
- return PublicMessage(response)
}
init {
- // Initialize the countries map
- val countries = mutableMapOf()
- countries["AD"] = "Europe/Andorra"
- countries["AE"] = "Asia/Dubai"
- countries["AF"] = "Asia/Kabul"
- countries["AG"] = "America/Antigua"
- countries["AI"] = "America/Anguilla"
- countries["AKDT"] = "America/Anchorage"
- countries["AKST"] = "America/Anchorage"
- countries["AL"] = "Europe/Tirane"
- countries["AM"] = "Asia/Yerevan"
- countries["AO"] = "Africa/Luanda"
- countries["AQ"] = "Antarctica/South_Pole"
- countries["AR"] = "America/Argentina/Buenos_Aires"
- countries["AS"] = "Pacific/Pago_Pago"
- countries["AT"] = "Europe/Vienna"
- countries["AU"] = "Australia/Sydney"
- countries["AW"] = "America/Aruba"
- countries["AX"] = "Europe/Mariehamn"
- countries["AZ"] = "Asia/Baku"
- countries["BA"] = "Europe/Sarajevo"
- countries["BB"] = "America/Barbados"
- countries["BD"] = "Asia/Dhaka"
- countries["BE"] = "Europe/Brussels"
- countries["BEAT"] = BEATS_KEYWORD
- countries["BF"] = "Africa/Ouagadougou"
- countries["BG"] = "Europe/Sofia"
- countries["BH"] = "Asia/Bahrain"
- countries["BI"] = "Africa/Bujumbura"
- countries["BJ"] = "Africa/Porto-Novo"
- countries["BL"] = "America/St_Barthelemy"
- countries["BM"] = "Atlantic/Bermuda"
- countries["BMT"] = BEATS_KEYWORD
- countries["BN"] = "Asia/Brunei"
- countries["BO"] = "America/La_Paz"
- countries["BQ"] = "America/Kralendijk"
- countries["BR"] = "America/Sao_Paulo"
- countries["BS"] = "America/Nassau"
- countries["BT"] = "Asia/Thimphu"
- countries["BW"] = "Africa/Gaborone"
- countries["BY"] = "Europe/Minsk"
- countries["BZ"] = "America/Belize"
- countries["CA"] = "America/Montreal"
- countries["CC"] = "Indian/Cocos"
- countries["CD"] = "Africa/Kinshasa"
- countries["CDT"] = "America/Chicago"
- countries["CET"] = "CET"
- countries["CF"] = "Africa/Bangui"
- countries["CG"] = "Africa/Brazzaville"
- countries["CH"] = "Europe/Zurich"
- countries["CI"] = "Africa/Abidjan"
- countries["CK"] = "Pacific/Rarotonga"
- countries["CL"] = "America/Santiago"
- countries["CM"] = "Africa/Douala"
- countries["CN"] = "Asia/Shanghai"
- countries["CO"] = "America/Bogota"
- countries["CR"] = "America/Costa_Rica"
- countries["CST"] = "America/Chicago"
- countries["CU"] = "Cuba"
- countries["CV"] = "Atlantic/Cape_Verde"
- countries["CW"] = "America/Curacao"
- countries["CX"] = "Indian/Christmas"
- countries["CY"] = "Asia/Nicosia"
- countries["CZ"] = "Europe/Prague"
- countries["DE"] = "Europe/Berlin"
- countries["DJ"] = "Africa/Djibouti"
- countries["DK"] = "Europe/Copenhagen"
- countries["DM"] = "America/Dominica"
- countries["DO"] = "America/Santo_Domingo"
- countries["DZ"] = "Africa/Algiers"
- countries["EC"] = "Pacific/Galapagos"
- countries["EDT"] = "America/New_York"
- countries["EE"] = "Europe/Tallinn"
- countries["EG"] = "Africa/Cairo"
- countries["EH"] = "Africa/El_Aaiun"
- countries["ER"] = "Africa/Asmara"
- countries["ES"] = "Europe/Madrid"
- countries["EST"] = "America/New_York"
- countries["ET"] = "Africa/Addis_Ababa"
- countries["FI"] = "Europe/Helsinki"
- countries["FJ"] = "Pacific/Fiji"
- countries["FK"] = "Atlantic/Stanley"
- countries["FM"] = "Pacific/Yap"
- countries["FO"] = "Atlantic/Faroe"
- countries["FR"] = "Europe/Paris"
- countries["GA"] = "Africa/Libreville"
- countries["GB"] = "Europe/London"
- countries["GD"] = "America/Grenada"
- countries["GE"] = "Asia/Tbilisi"
- countries["GF"] = "America/Cayenne"
- countries["GG"] = "Europe/Guernsey"
- countries["GH"] = "Africa/Accra"
- countries["GI"] = "Europe/Gibraltar"
- countries["GL"] = "America/Thule"
- countries["GM"] = "Africa/Banjul"
- countries["GMT"] = "GMT"
- countries["GN"] = "Africa/Conakry"
- countries["GP"] = "America/Guadeloupe"
- countries["GQ"] = "Africa/Malabo"
- countries["GR"] = "Europe/Athens"
- countries["GS"] = "Atlantic/South_Georgia"
- countries["GT"] = "America/Guatemala"
- countries["GU"] = "Pacific/Guam"
- countries["GW"] = "Africa/Bissau"
- countries["GY"] = "America/Guyana"
- countries["HK"] = "Asia/Hong_Kong"
- countries["HN"] = "America/Tegucigalpa"
- countries["HR"] = "Europe/Zagreb"
- countries["HST"] = "Pacific/Honolulu"
- countries["HT"] = "America/Port-au-Prince"
- countries["HU"] = "Europe/Budapest"
- countries["ID"] = "Asia/Jakarta"
- countries["IE"] = "Europe/Dublin"
- countries["IL"] = "Asia/Tel_Aviv"
- countries["IM"] = "Europe/Isle_of_Man"
- countries["IN"] = "Asia/Kolkata"
- countries["IO"] = "Indian/Chagos"
- countries["IQ"] = "Asia/Baghdad"
- countries["IR"] = "Asia/Tehran"
- countries["IS"] = "Atlantic/Reykjavik"
- countries["IT"] = "Europe/Rome"
- countries["JE"] = "Europe/Jersey"
- countries["JM"] = "Jamaica"
- countries["JO"] = "Asia/Amman"
- countries["JP"] = "Asia/Tokyo"
- countries["KE"] = "Africa/Nairobi"
- countries["KG"] = "Asia/Bishkek"
- countries["KH"] = "Asia/Phnom_Penh"
- countries["KI"] = "Pacific/Tarawa"
- countries["KM"] = "Indian/Comoro"
- countries["KN"] = "America/St_Kitts"
- countries["KP"] = "Asia/Pyongyang"
- countries["KR"] = "Asia/Seoul"
- countries["KW"] = "Asia/Riyadh"
- countries["KY"] = "America/Cayman"
- countries["KZ"] = "Asia/Oral"
- countries["LA"] = "Asia/Vientiane"
- countries["LB"] = "Asia/Beirut"
- countries["LC"] = "America/St_Lucia"
- countries["LI"] = "Europe/Vaduz"
- countries["LK"] = "Asia/Colombo"
- countries["LR"] = "Africa/Monrovia"
- countries["LS"] = "Africa/Maseru"
- countries["LT"] = "Europe/Vilnius"
- countries["LU"] = "Europe/Luxembourg"
- countries["LV"] = "Europe/Riga"
- countries["LY"] = "Africa/Tripoli"
- countries["MA"] = "Africa/Casablanca"
- countries["MC"] = "Europe/Monaco"
- countries["MD"] = "Europe/Chisinau"
- countries["MDT"] = "America/Denver"
- countries["ME"] = "Europe/Podgorica"
- countries["MF"] = "America/Marigot"
- countries["MG"] = "Indian/Antananarivo"
- countries["MH"] = "Pacific/Majuro"
- countries["MK"] = "Europe/Skopje"
- countries["ML"] = "Africa/Timbuktu"
- countries["MM"] = "Asia/Yangon"
- countries["MN"] = "Asia/Ulaanbaatar"
- countries["MO"] = "Asia/Macau"
- countries["MP"] = "Pacific/Saipan"
- countries["MQ"] = "America/Martinique"
- countries["MR"] = "Africa/Nouakchott"
- countries["MS"] = "America/Montserrat"
- countries["MST"] = "America/Denver"
- countries["MT"] = "Europe/Malta"
- countries["MU"] = "Indian/Mauritius"
- countries["MV"] = "Indian/Maldives"
- countries["MW"] = "Africa/Blantyre"
- countries["MX"] = "America/Mexico_City"
- countries["MY"] = "Asia/Kuala_Lumpur"
- countries["MZ"] = "Africa/Maputo"
- countries["NA"] = "Africa/Windhoek"
- countries["NC"] = "Pacific/Noumea"
- countries["NE"] = "Africa/Niamey"
- countries["NF"] = "Pacific/Norfolk"
- countries["NG"] = "Africa/Lagos"
- countries["NI"] = "America/Managua"
- countries["NL"] = "Europe/Amsterdam"
- countries["NO"] = "Europe/Oslo"
- countries["NP"] = "Asia/Kathmandu"
- countries["NR"] = "Pacific/Nauru"
- countries["NU"] = "Pacific/Niue"
- countries["NZ"] = "Pacific/Auckland"
- countries["OM"] = "Asia/Muscat"
- countries["PA"] = "America/Panama"
- countries["PDT"] = "America/Los_Angeles"
- countries["PE"] = "America/Lima"
- countries["PF"] = "Pacific/Tahiti"
- countries["PG"] = "Pacific/Port_Moresby"
- countries["PH"] = "Asia/Manila"
- countries["PK"] = "Asia/Karachi"
- countries["PL"] = "Europe/Warsaw"
- countries["PM"] = "America/Miquelon"
- countries["PN"] = "Pacific/Pitcairn"
- countries["PR"] = "America/Puerto_Rico"
- countries["PS"] = "Asia/Gaza"
- countries["PST"] = "America/Los_Angeles"
- countries["PT"] = "Europe/Lisbon"
- countries["PW"] = "Pacific/Palau"
- countries["PY"] = "America/Asuncion"
- countries["QA"] = "Asia/Qatar"
- countries["RE"] = "Indian/Reunion"
- countries["RO"] = "Europe/Bucharest"
- countries["RS"] = "Europe/Belgrade"
- countries["RU"] = "Europe/Moscow"
- countries["RW"] = "Africa/Kigali"
- countries["SA"] = "Asia/Riyadh"
- countries["SB"] = "Pacific/Guadalcanal"
- countries["SC"] = "Indian/Mahe"
- countries["SD"] = "Africa/Khartoum"
- countries["SE"] = "Europe/Stockholm"
- countries["SG"] = "Asia/Singapore"
- countries["SH"] = "Atlantic/St_Helena"
- countries["SI"] = "Europe/Ljubljana"
- countries["SJ"] = "Atlantic/Jan_Mayen"
- countries["SK"] = "Europe/Bratislava"
- countries["SL"] = "Africa/Freetown"
- countries["SM"] = "Europe/San_Marino"
- countries["SN"] = "Africa/Dakar"
- countries["SO"] = "Africa/Mogadishu"
- countries["SR"] = "America/Paramaribo"
- countries["SS"] = "Africa/Juba"
- countries["ST"] = "Africa/Sao_Tome"
- countries["SV"] = "America/El_Salvador"
- countries["SX"] = "America/Lower_Princes"
- countries["SY"] = "Asia/Damascus"
- countries["SZ"] = "Africa/Mbabane"
- countries["TC"] = "America/Grand_Turk"
- countries["TD"] = "Africa/Ndjamena"
- countries["TF"] = "Indian/Kerguelen"
- countries["TG"] = "Africa/Lome"
- countries["TH"] = "Asia/Bangkok"
- countries["TJ"] = "Asia/Dushanbe"
- countries["TK"] = "Pacific/Fakaofo"
- countries["TL"] = "Asia/Dili"
- countries["TM"] = "Asia/Ashgabat"
- countries["TN"] = "Africa/Tunis"
- countries["TO"] = "Pacific/Tongatapu"
- countries["TR"] = "Europe/Istanbul"
- countries["TT"] = "America/Port_of_Spain"
- countries["TV"] = "Pacific/Funafuti"
- countries["TW"] = "Asia/Taipei"
- countries["TZ"] = "Africa/Dar_es_Salaam"
- countries["UA"] = "Europe/Kiev"
- countries["UG"] = "Africa/Kampala"
- countries["UK"] = "Europe/London"
- countries["UM"] = "Pacific/Wake"
- countries["US"] = "America/New_York"
- countries["UTC"] = "UTC"
- countries["UY"] = "America/Montevideo"
- countries["UZ"] = "Asia/Tashkent"
- countries["VA"] = "Europe/Vatican"
- countries["VC"] = "America/St_Vincent"
- countries["VE"] = "America/Caracas"
- countries["VG"] = "America/Tortola"
- countries["VI"] = "America/St_Thomas"
- countries["VN"] = "Asia/Ho_Chi_Minh"
- countries["VU"] = "Pacific/Efate"
- countries["WF"] = "Pacific/Wallis"
- countries["WS"] = "Pacific/Apia"
- countries["YE"] = "Asia/Aden"
- countries["YT"] = "Indian/Mayotte"
- countries["ZA"] = "Africa/Johannesburg"
- countries["ZM"] = "Africa/Lusaka"
- countries["ZULU"] = "Zulu"
- countries["ZW"] = "Africa/Harare"
- @Suppress("MagicNumber")
+ // Initialize the zones map
+ val zones = mutableMapOf()
+ zones["AD"] = "Europe/Andorra"
+ zones["AE"] = "Asia/Dubai"
+ zones["AF"] = "Asia/Kabul"
+ zones["AG"] = "America/Antigua"
+ zones["AI"] = "America/Anguilla"
+ zones["AKDT"] = "America/Anchorage"
+ zones["AKST"] = "America/Anchorage"
+ zones["AL"] = "Europe/Tirane"
+ zones["AM"] = "Asia/Yerevan"
+ zones["AO"] = "Africa/Luanda"
+ zones["AQ"] = "Antarctica/South_Pole"
+ zones["AR"] = "America/Argentina/Buenos_Aires"
+ zones["AS"] = "Pacific/Pago_Pago"
+ zones["AT"] = "Europe/Vienna"
+ zones["AU"] = "Australia/Sydney"
+ zones["AW"] = "America/Aruba"
+ zones["AX"] = "Europe/Mariehamn"
+ zones["AZ"] = "Asia/Baku"
+ zones["BA"] = "Europe/Sarajevo"
+ zones["BB"] = "America/Barbados"
+ zones["BD"] = "Asia/Dhaka"
+ zones["BE"] = "Europe/Brussels"
+ zones["BEAT"] = BEATS_KEYWORD
+ zones["BF"] = "Africa/Ouagadougou"
+ zones["BG"] = "Europe/Sofia"
+ zones["BH"] = "Asia/Bahrain"
+ zones["BI"] = "Africa/Bujumbura"
+ zones["BJ"] = "Africa/Porto-Novo"
+ zones["BL"] = "America/St_Barthelemy"
+ zones["BM"] = "Atlantic/Bermuda"
+ zones["BMT"] = BEATS_KEYWORD
+ zones["BN"] = "Asia/Brunei"
+ zones["BO"] = "America/La_Paz"
+ zones["BQ"] = "America/Kralendijk"
+ zones["BR"] = "America/Sao_Paulo"
+ zones["BS"] = "America/Nassau"
+ zones["BT"] = "Asia/Thimphu"
+ zones["BW"] = "Africa/Gaborone"
+ zones["BY"] = "Europe/Minsk"
+ zones["BZ"] = "America/Belize"
+ zones["CA"] = "America/Montreal"
+ zones["CC"] = "Indian/Cocos"
+ zones["CD"] = "Africa/Kinshasa"
+ zones["CDT"] = "America/Chicago"
+ zones["CET"] = "CET"
+ zones["CF"] = "Africa/Bangui"
+ zones["CG"] = "Africa/Brazzaville"
+ zones["CH"] = "Europe/Zurich"
+ zones["CI"] = "Africa/Abidjan"
+ zones["CK"] = "Pacific/Rarotonga"
+ zones["CL"] = "America/Santiago"
+ zones["CM"] = "Africa/Douala"
+ zones["CN"] = "Asia/Shanghai"
+ zones["CO"] = "America/Bogota"
+ zones["CR"] = "America/Costa_Rica"
+ zones["CST"] = "America/Chicago"
+ zones["CU"] = "Cuba"
+ zones["CV"] = "Atlantic/Cape_Verde"
+ zones["CW"] = "America/Curacao"
+ zones["CX"] = "Indian/Christmas"
+ zones["CY"] = "Asia/Nicosia"
+ zones["CZ"] = "Europe/Prague"
+ zones["DE"] = "Europe/Berlin"
+ zones["DJ"] = "Africa/Djibouti"
+ zones["DK"] = "Europe/Copenhagen"
+ zones["DM"] = "America/Dominica"
+ zones["DO"] = "America/Santo_Domingo"
+ zones["DZ"] = "Africa/Algiers"
+ zones["EC"] = "Pacific/Galapagos"
+ zones["EDT"] = "America/New_York"
+ zones["EE"] = "Europe/Tallinn"
+ zones["EG"] = "Africa/Cairo"
+ zones["EH"] = "Africa/El_Aaiun"
+ zones["ER"] = "Africa/Asmara"
+ zones["ES"] = "Europe/Madrid"
+ zones["EST"] = "America/New_York"
+ zones["ET"] = "Africa/Addis_Ababa"
+ zones["FI"] = "Europe/Helsinki"
+ zones["FJ"] = "Pacific/Fiji"
+ zones["FK"] = "Atlantic/Stanley"
+ zones["FM"] = "Pacific/Yap"
+ zones["FO"] = "Atlantic/Faroe"
+ zones["FR"] = "Europe/Paris"
+ zones["GA"] = "Africa/Libreville"
+ zones["GB"] = "Europe/London"
+ zones["GD"] = "America/Grenada"
+ zones["GE"] = "Asia/Tbilisi"
+ zones["GF"] = "America/Cayenne"
+ zones["GG"] = "Europe/Guernsey"
+ zones["GH"] = "Africa/Accra"
+ zones["GI"] = "Europe/Gibraltar"
+ zones["GL"] = "America/Thule"
+ zones["GM"] = "Africa/Banjul"
+ zones["GMT"] = "GMT"
+ zones["GN"] = "Africa/Conakry"
+ zones["GP"] = "America/Guadeloupe"
+ zones["GQ"] = "Africa/Malabo"
+ zones["GR"] = "Europe/Athens"
+ zones["GS"] = "Atlantic/South_Georgia"
+ zones["GT"] = "America/Guatemala"
+ zones["GU"] = "Pacific/Guam"
+ zones["GW"] = "Africa/Bissau"
+ zones["GY"] = "America/Guyana"
+ zones["HK"] = "Asia/Hong_Kong"
+ zones["HN"] = "America/Tegucigalpa"
+ zones["HR"] = "Europe/Zagreb"
+ zones["HST"] = "Pacific/Honolulu"
+ zones["HT"] = "America/Port-au-Prince"
+ zones["HU"] = "Europe/Budapest"
+ zones["ID"] = "Asia/Jakarta"
+ zones["IE"] = "Europe/Dublin"
+ zones["IL"] = "Asia/Tel_Aviv"
+ zones["IM"] = "Europe/Isle_of_Man"
+ zones["IN"] = "Asia/Kolkata"
+ zones["IO"] = "Indian/Chagos"
+ zones["IQ"] = "Asia/Baghdad"
+ zones["IR"] = "Asia/Tehran"
+ zones["IS"] = "Atlantic/Reykjavik"
+ zones["IT"] = "Europe/Rome"
+ zones["JE"] = "Europe/Jersey"
+ zones["JM"] = "Jamaica"
+ zones["JO"] = "Asia/Amman"
+ zones["JP"] = "Asia/Tokyo"
+ zones["KE"] = "Africa/Nairobi"
+ zones["KG"] = "Asia/Bishkek"
+ zones["KH"] = "Asia/Phnom_Penh"
+ zones["KI"] = "Pacific/Tarawa"
+ zones["KM"] = "Indian/Comoro"
+ zones["KN"] = "America/St_Kitts"
+ zones["KP"] = "Asia/Pyongyang"
+ zones["KR"] = "Asia/Seoul"
+ zones["KW"] = "Asia/Riyadh"
+ zones["KY"] = "America/Cayman"
+ zones["KZ"] = "Asia/Oral"
+ zones["LA"] = "Asia/Vientiane"
+ zones["LB"] = "Asia/Beirut"
+ zones["LC"] = "America/St_Lucia"
+ zones["LI"] = "Europe/Vaduz"
+ zones["LK"] = "Asia/Colombo"
+ zones["LR"] = "Africa/Monrovia"
+ zones["LS"] = "Africa/Maseru"
+ zones["LT"] = "Europe/Vilnius"
+ zones["LU"] = "Europe/Luxembourg"
+ zones["LV"] = "Europe/Riga"
+ zones["LY"] = "Africa/Tripoli"
+ zones["MA"] = "Africa/Casablanca"
+ zones["MC"] = "Europe/Monaco"
+ zones["MD"] = "Europe/Chisinau"
+ zones["MDT"] = "America/Denver"
+ zones["ME"] = "Europe/Podgorica"
+ zones["MF"] = "America/Marigot"
+ zones["MG"] = "Indian/Antananarivo"
+ zones["MH"] = "Pacific/Majuro"
+ zones["MK"] = "Europe/Skopje"
+ zones["ML"] = "Africa/Timbuktu"
+ zones["MM"] = "Asia/Yangon"
+ zones["MN"] = "Asia/Ulaanbaatar"
+ zones["MO"] = "Asia/Macau"
+ zones["MP"] = "Pacific/Saipan"
+ zones["MQ"] = "America/Martinique"
+ zones["MR"] = "Africa/Nouakchott"
+ zones["MS"] = "America/Montserrat"
+ zones["MST"] = "America/Denver"
+ zones["MT"] = "Europe/Malta"
+ zones["MU"] = "Indian/Mauritius"
+ zones["MV"] = "Indian/Maldives"
+ zones["MW"] = "Africa/Blantyre"
+ zones["MX"] = "America/Mexico_City"
+ zones["MY"] = "Asia/Kuala_Lumpur"
+ zones["MZ"] = "Africa/Maputo"
+ zones["NA"] = "Africa/Windhoek"
+ zones["NC"] = "Pacific/Noumea"
+ zones["NE"] = "Africa/Niamey"
+ zones["NF"] = "Pacific/Norfolk"
+ zones["NG"] = "Africa/Lagos"
+ zones["NI"] = "America/Managua"
+ zones["NL"] = "Europe/Amsterdam"
+ zones["NO"] = "Europe/Oslo"
+ zones["NP"] = "Asia/Kathmandu"
+ zones["NR"] = "Pacific/Nauru"
+ zones["NU"] = "Pacific/Niue"
+ zones["NZ"] = "Pacific/Auckland"
+ zones["OM"] = "Asia/Muscat"
+ zones["PA"] = "America/Panama"
+ zones["PDT"] = "America/Los_Angeles"
+ zones["PE"] = "America/Lima"
+ zones["PF"] = "Pacific/Tahiti"
+ zones["PG"] = "Pacific/Port_Moresby"
+ zones["PH"] = "Asia/Manila"
+ zones["PK"] = "Asia/Karachi"
+ zones["PL"] = "Europe/Warsaw"
+ zones["PM"] = "America/Miquelon"
+ zones["PN"] = "Pacific/Pitcairn"
+ zones["PR"] = "America/Puerto_Rico"
+ zones["PS"] = "Asia/Gaza"
+ zones["PST"] = "America/Los_Angeles"
+ zones["PT"] = "Europe/Lisbon"
+ zones["PW"] = "Pacific/Palau"
+ zones["PY"] = "America/Asuncion"
+ zones["QA"] = "Asia/Qatar"
+ zones["RE"] = "Indian/Reunion"
+ zones["RO"] = "Europe/Bucharest"
+ zones["RS"] = "Europe/Belgrade"
+ zones["RU"] = "Europe/Moscow"
+ zones["RW"] = "Africa/Kigali"
+ zones["SA"] = "Asia/Riyadh"
+ zones["SB"] = "Pacific/Guadalcanal"
+ zones["SC"] = "Indian/Mahe"
+ zones["SD"] = "Africa/Khartoum"
+ zones["SE"] = "Europe/Stockholm"
+ zones["SG"] = "Asia/Singapore"
+ zones["SH"] = "Atlantic/St_Helena"
+ zones["SI"] = "Europe/Ljubljana"
+ zones["SJ"] = "Atlantic/Jan_Mayen"
+ zones["SK"] = "Europe/Bratislava"
+ zones["SL"] = "Africa/Freetown"
+ zones["SM"] = "Europe/San_Marino"
+ zones["SN"] = "Africa/Dakar"
+ zones["SO"] = "Africa/Mogadishu"
+ zones["SR"] = "America/Paramaribo"
+ zones["SS"] = "Africa/Juba"
+ zones["ST"] = "Africa/Sao_Tome"
+ zones["SV"] = "America/El_Salvador"
+ zones["SX"] = "America/Lower_Princes"
+ zones["SY"] = "Asia/Damascus"
+ zones["SZ"] = "Africa/Mbabane"
+ zones["TC"] = "America/Grand_Turk"
+ zones["TD"] = "Africa/Ndjamena"
+ zones["TF"] = "Indian/Kerguelen"
+ zones["TG"] = "Africa/Lome"
+ zones["TH"] = "Asia/Bangkok"
+ zones["TJ"] = "Asia/Dushanbe"
+ zones["TK"] = "Pacific/Fakaofo"
+ zones["TL"] = "Asia/Dili"
+ zones["TM"] = "Asia/Ashgabat"
+ zones["TN"] = "Africa/Tunis"
+ zones["TO"] = "Pacific/Tongatapu"
+ zones["TR"] = "Europe/Istanbul"
+ zones["TT"] = "America/Port_of_Spain"
+ zones["TV"] = "Pacific/Funafuti"
+ zones["TW"] = "Asia/Taipei"
+ zones["TZ"] = "Africa/Dar_es_Salaam"
+ zones["UA"] = "Europe/Kiev"
+ zones["UG"] = "Africa/Kampala"
+ zones["UK"] = "Europe/London"
+ zones["UM"] = "Pacific/Wake"
+ zones["US"] = "America/New_York"
+ zones["UTC"] = "UTC"
+ zones["UY"] = "America/Montevideo"
+ zones["UZ"] = "Asia/Tashkent"
+ zones["VA"] = "Europe/Vatican"
+ zones["VC"] = "America/St_Vincent"
+ zones["VE"] = "America/Caracas"
+ zones["VG"] = "America/Tortola"
+ zones["VI"] = "America/St_Thomas"
+ zones["VN"] = "Asia/Ho_Chi_Minh"
+ zones["VU"] = "Pacific/Efate"
+ zones["WF"] = "Pacific/Wallis"
+ zones["WS"] = "Pacific/Apia"
+ zones["YE"] = "Asia/Aden"
+ zones["YT"] = "Indian/Mayotte"
+ zones["ZA"] = "Africa/Johannesburg"
+ zones["ZM"] = "Africa/Lusaka"
+ zones["ZULU"] = "Zulu"
+ zones["ZW"] = "Africa/Harare"
ZoneId.getAvailableZoneIds().stream()
.filter { tz: String ->
- tz.length <= 3 && !countries.containsKey(tz)
+ tz.length <= 3 && !zones.containsKey(tz)
}
.forEach { tz: String ->
- countries[tz] = tz
+ zones[tz] = tz
}
- COUNTRIES_MAP = Collections.unmodifiableMap(countries)
+ COUNTRIES_MAP = Collections.unmodifiableMap(zones)
}
}
- override fun commandResponse(
- sender: String,
- cmd: String,
- args: String,
- isPrivate: Boolean
- ) {
- with(bot) {
- if (args.isEmpty()) {
- send(sender, "The supported countries/zones are: ", isPrivate)
- @Suppress("MagicNumber")
- sendList(
- sender,
- COUNTRIES_MAP.keys.sorted().map { it.padEnd(4) },
- 14,
- isPrivate = false,
- isIndent = true
- )
- } else {
- val msg = time(args)
- if (isPrivate) {
- send(sender, msg.msg, true)
- } else {
- if (msg.isError) {
- send(sender, msg.msg, false)
- } else {
- send(msg.msg)
- }
- }
- }
+ override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
+ if (args.equals(ZONES_ARGS, true)) {
+ event.sendMessage("The supported countries/zones are: ")
+ event.sendList(COUNTRIES_MAP.keys.sorted().map { it.padEnd(4) }, 14, isIndent = true)
+ } else {
+ event.respond(time(args))
}
}
@@ -408,9 +387,9 @@ class WorldTime(bot: Mobibot) : AbstractModule(bot) {
init {
with(help) {
add("To display a country's current date/time:")
- add(helpFormat("%c $TIME_CMD "))
- add("For a listing of the supported countries:")
- add(helpFormat("%c $TIME_CMD"))
+ add(helpFormat("%c $TIME_CMD []"))
+ add("For a listing of the supported countries/zones:")
+ add(helpFormat("%c $TIME_CMD $ZONES_ARGS"))
}
commands.add(TIME_CMD)
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/Sanitize.kt b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt
similarity index 82%
rename from src/test/kotlin/net/thauvin/erik/mobibot/Sanitize.kt
rename to src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt
index e8cc448..1660df7 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/Sanitize.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt
@@ -1,5 +1,5 @@
/*
- * Sanitize.kt
+ * ExceptionSanitizer.kt
*
* Copyright (c) 2004-2021, Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
@@ -36,27 +36,26 @@ import net.thauvin.erik.mobibot.Utils.obfuscate
import net.thauvin.erik.mobibot.Utils.replaceEach
import net.thauvin.erik.mobibot.modules.ModuleException
-object Sanitize {
+object ExceptionSanitizer {
/**
* Returns a sanitized exception to avoid displaying api keys, etc. in CI logs.
*/
- fun sanitizeException(e: ModuleException, vararg sanitize: String): ModuleException {
- var sanitizedException = e
+ fun ModuleException.sanitize(vararg sanitize: String): ModuleException {
val search = sanitize.filter { it.isNotBlank() }.toTypedArray()
if (search.isNotEmpty()) {
val obfuscate = search.map { it.obfuscate() }.toTypedArray()
- with(e) {
- if (cause?.message != null) {
- sanitizedException = ModuleException(
+ with(this) {
+ if (!cause?.message.isNullOrBlank()) {
+ return ModuleException(
debugMessage,
cause!!.javaClass.name + ": " + cause!!.message!!.replaceEach(search, obfuscate),
this
)
- } else if (message != null) {
- sanitizedException = ModuleException(debugMessage, message!!.replaceEach(search, obfuscate), this)
+ } else if (!message.isNullOrBlank()) {
+ return ModuleException(debugMessage, message!!.replaceEach(search, obfuscate), this)
}
}
}
- return sanitizedException
+ return this
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt
index 234f84b..dadf542 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt
@@ -31,12 +31,14 @@
*/
package net.thauvin.erik.mobibot
+import assertk.assertThat
+import assertk.assertions.contains
+import assertk.assertions.isEqualTo
+import assertk.assertions.isFailure
+import assertk.assertions.isInstanceOf
import com.rometools.rome.io.FeedException
import net.thauvin.erik.mobibot.FeedReader.Companion.readFeed
-import org.assertj.core.api.Assertions.assertThat
-import org.assertj.core.api.Assertions.assertThatThrownBy
import org.testng.annotations.Test
-
import java.io.FileNotFoundException
import java.net.MalformedURLException
import java.net.UnknownHostException
@@ -48,26 +50,24 @@ class FeedReaderTest {
@Test
fun readFeedTest() {
var messages = readFeed("https://feeds.thauvin.net/ethauvin")
- assertThat(messages.size).describedAs("messages = 10").isEqualTo(10)
- assertThat(messages[1].msg).describedAs("feed entry url").contains("ethauvin")
+ assertThat(messages.size, "size = 10").isEqualTo(10)
+ assertThat(messages[1].msg, "feed entry url").contains("ethauvin")
messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=0")
- assertThat(messages[0].msg).describedAs("nothing to view").contains("nothing")
+ assertThat(messages[0].msg, "nothing to view").contains("nothing")
messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=42", 42)
- assertThat(messages.size).describedAs("messages = 84").isEqualTo(84)
- assertThat(messages.last().msg).describedAs("example entry url").contains("http://example.com/test/")
+ assertThat(messages.size, "messages = 84").isEqualTo(84)
+ assertThat(messages.last().msg, "example entry url").contains("http://example.com/test/")
- assertThatThrownBy { readFeed("blah") }.describedAs("invalid URL")
- .isInstanceOf(MalformedURLException::class.java)
+ assertThat { readFeed("blah") }.isFailure().isInstanceOf(MalformedURLException::class.java)
- assertThatThrownBy { readFeed("https://www.example.com") }.describedAs("not a feed")
- .isInstanceOf(FeedException::class.java)
+ assertThat { readFeed("https://www.example.com") }.isFailure().isInstanceOf(FeedException::class.java)
- assertThatThrownBy { readFeed("https://www.examples.com/foo") }.describedAs("404 not found")
+ assertThat { readFeed("https://www.examples.com/foo") }.isFailure()
.isInstanceOf(FileNotFoundException::class.java)
- assertThatThrownBy { readFeed("https://www.doesnotexists.com") }.describedAs("unknown host")
+ assertThat { readFeed("https://www.doesnotexists.com") }.isFailure()
.isInstanceOf(UnknownHostException::class.java)
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardUtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt
similarity index 81%
rename from src/test/kotlin/net/thauvin/erik/mobibot/PinboardUtilsTest.kt
rename to src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt
index 93ff940..76b5b95 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardUtilsTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt
@@ -1,5 +1,5 @@
/*
- * PinboardUtilsTest.kt
+ * PinboardTest.kt
*
* Copyright (c) 2004-2021, Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
@@ -32,45 +32,39 @@
package net.thauvin.erik.mobibot
-import net.thauvin.erik.mobibot.PinboardUtils.toTimestamp
import net.thauvin.erik.mobibot.entries.EntryLink
-import net.thauvin.erik.pinboard.PinboardPoster
import org.testng.Assert.assertFalse
import org.testng.Assert.assertTrue
import org.testng.annotations.Test
import java.net.URL
-import java.util.Date
-class PinboardUtilsTest : LocalProperties() {
+class PinboardTest : LocalProperties() {
+ private val pinboard = Pinboard()
+
@Test
- fun pinboardTest() {
+ fun testPinboard() {
val apiToken = getProperty("pinboard-api-token")
- val pinboard = PinboardPoster(apiToken)
val url = "https://www.example.com/"
val ircServer = "irc.test.com"
val entry = EntryLink(url, "Test Example", "ErikT", "", "#mobitopia", listOf("test"))
- PinboardUtils.addPin(pinboard, ircServer, entry)
+ pinboard.setApiToken(apiToken)
+
+ pinboard.addPin(ircServer, entry)
assertTrue(validatePin(apiToken, url = entry.link, entry.title, entry.nick, entry.channel), "validate add")
entry.link = "https://www.foo.com/"
- PinboardUtils.updatePin(pinboard, ircServer, url, entry)
+ pinboard.updatePin(ircServer, url, entry)
assertTrue(validatePin(apiToken, url = entry.link, ircServer), "validate update")
entry.title = "Foo Title"
- PinboardUtils.updatePin(pinboard, ircServer, entry.link, entry)
+ pinboard.updatePin(ircServer, entry.link, entry)
assertTrue(validatePin(apiToken, url = entry.link, entry.title), "validate title")
- PinboardUtils.deletePin(pinboard, entry)
+ pinboard.deletePin(entry)
assertFalse(validatePin(apiToken, url = entry.link), "validate delete")
}
- @Test
- fun toTimestampTest() {
- val d = Date()
- assertTrue(d.toTimestamp().matches("[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z".toRegex()))
- }
-
private fun validatePin(apiToken: String, url: String, vararg matches: String): Boolean {
val response = Utils.urlReader(
URL(
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt
index 2dc0ef8..fc8f117 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt
@@ -31,6 +31,8 @@
*/
package net.thauvin.erik.mobibot
+import assertk.assertThat
+import assertk.assertions.isEqualTo
import net.thauvin.erik.mobibot.Utils.appendIfMissing
import net.thauvin.erik.mobibot.Utils.bold
import net.thauvin.erik.mobibot.Utils.buildCmdSyntax
@@ -55,8 +57,7 @@ import net.thauvin.erik.mobibot.Utils.unescapeXml
import net.thauvin.erik.mobibot.Utils.uptime
import net.thauvin.erik.mobibot.Utils.urlReader
import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR
-import org.assertj.core.api.Assertions.assertThat
-import org.jibble.pircbot.Colors
+import org.pircbotx.Colors
import org.testng.annotations.BeforeClass
import org.testng.annotations.Test
import java.io.File
@@ -86,59 +87,59 @@ class UtilsTest {
val dir = "dir"
val sep = '/'
val url = "https://erik.thauvin.net"
- assertThat(dir.appendIfMissing(File.separatorChar)).describedAs("appendIfMissing(dir)")
+ assertThat(dir.appendIfMissing(File.separatorChar), "appendIfMissing(dir)")
.isEqualTo(dir + File.separatorChar)
- assertThat(url.appendIfMissing(sep)).describedAs("appendIfMissing(url)").isEqualTo("$url$sep")
- assertThat("$url$sep".appendIfMissing(sep)).describedAs("appendIfMissing($url$sep)").isEqualTo("$url$sep")
+ assertThat(url.appendIfMissing(sep), "appendIfMissing(url)").isEqualTo("$url$sep")
+ assertThat("$url$sep".appendIfMissing(sep), "appendIfMissing($url$sep)").isEqualTo("$url$sep")
}
@Test
fun testBold() {
- assertThat(bold(1)).describedAs("bold(1)").isEqualTo(Colors.BOLD + "1" + Colors.BOLD)
- assertThat(bold(2L)).describedAs("bold(1)").isEqualTo(Colors.BOLD + "2" + Colors.BOLD)
- assertThat(bold(ascii)).describedAs("bold(ascii)").isEqualTo(Colors.BOLD + ascii + Colors.BOLD)
- assertThat(bold("test")).describedAs("bold(test)").isEqualTo(Colors.BOLD + "test" + Colors.BOLD)
+ assertThat(bold(1), "bold(1)").isEqualTo(Colors.BOLD + "1" + Colors.BOLD)
+ assertThat(bold(2L), "bold(1)").isEqualTo(Colors.BOLD + "2" + Colors.BOLD)
+ assertThat(bold(ascii), "bold(ascii)").isEqualTo(Colors.BOLD + ascii + Colors.BOLD)
+ assertThat(bold("test"), "bold(test)").isEqualTo(Colors.BOLD + "test" + Colors.BOLD)
}
@Test
fun testBuildCmdSyntax() {
val bot = "mobibot"
- assertThat(buildCmdSyntax("%c $test %n $test", bot, false)).describedAs("public")
+ assertThat(buildCmdSyntax("%c $test %n $test", bot, false), "public")
.isEqualTo("$bot: $test $bot $test")
- assertThat(buildCmdSyntax("%c %n $test %c $test %n", bot, true)).describedAs("public")
+ assertThat(buildCmdSyntax("%c %n $test %c $test %n", bot, true), "public")
.isEqualTo("/msg $bot $bot $test /msg $bot $test $bot")
}
@Test
fun testCapitalise() {
- assertThat("test".capitalise()).describedAs("capitalize(test)").isEqualTo("Test")
- assertThat("Test".capitalise()).describedAs("capitalize(Test)").isEqualTo("Test")
- assertThat(test.capitalise()).describedAs("capitalize($test)").isEqualTo(test)
- assertThat("".capitalise()).describedAs("capitalize()").isEqualTo("")
+ assertThat("test".capitalise(), "capitalize(test)").isEqualTo("Test")
+ assertThat("Test".capitalise(), "capitalize(Test)").isEqualTo("Test")
+ assertThat(test.capitalise(), "capitalize($test)").isEqualTo(test)
+ assertThat("".capitalise(), "capitalize()").isEqualTo("")
}
@Test
fun textCapitaliseWords() {
- assertThat(test.capitalizeWords()).describedAs("captiatlizeWords(test)").isEqualTo("This Is A Test.")
- assertThat("Already Capitalized".capitalizeWords()).describedAs("already capitalized")
+ assertThat(test.capitalizeWords(), "captiatlizeWords(test)").isEqualTo("This Is A Test.")
+ assertThat("Already Capitalized".capitalizeWords(), "already capitalized")
.isEqualTo("Already Capitalized")
- assertThat(" a test ".capitalizeWords()).describedAs("with spaces").isEqualTo(" A Test ")
+ assertThat(" a test ".capitalizeWords(), "with spaces").isEqualTo(" A Test ")
}
@Test
fun testColorize() {
- assertThat(colorize(ascii, Colors.REVERSE)).describedAs("colorize(reverse)").isEqualTo(
+ assertThat(colorize(ascii, Colors.REVERSE), "colorize(reverse)").isEqualTo(
Colors.REVERSE + ascii + Colors.REVERSE
)
- assertThat(colorize(ascii, Colors.RED)).describedAs("colorize(red)")
+ assertThat(colorize(ascii, Colors.RED), "colorize(red)")
.isEqualTo(Colors.RED + ascii + Colors.NORMAL)
- assertThat(colorize(ascii, Colors.BOLD)).describedAs("colorized(bold)")
+ assertThat(colorize(ascii, Colors.BOLD), "colorized(bold)")
.isEqualTo(Colors.BOLD + ascii + Colors.BOLD)
- assertThat(colorize(null, Colors.RED)).describedAs("colorize(null)").isEqualTo("")
- assertThat(colorize("", Colors.RED)).describedAs("colorize()").isEqualTo("")
- assertThat(colorize(ascii, DEFAULT_COLOR)).describedAs("colorize(none)").isEqualTo(ascii)
- assertThat(colorize(" ", Colors.NORMAL)).describedAs("colorize(blank)")
+ assertThat(colorize(null, Colors.RED), "colorize(null)").isEqualTo("")
+ assertThat(colorize("", Colors.RED), "colorize()").isEqualTo("")
+ assertThat(colorize(ascii, DEFAULT_COLOR), "colorize(none)").isEqualTo(ascii)
+ assertThat(colorize(" ", Colors.NORMAL), "colorize(blank)")
.isEqualTo(Colors.NORMAL + " " + Colors.NORMAL)
}
@@ -157,9 +158,9 @@ class UtilsTest {
val p = Properties()
p["one"] = "1"
p["two"] = "two"
- assertThat(p.getIntProperty("one", 9)).describedAs("getIntProperty(one)").isEqualTo(1)
- assertThat(p.getIntProperty("two", 2)).describedAs("getIntProperty(two)").isEqualTo(2)
- assertThat(p.getIntProperty("foo", 3)).describedAs("getIntProperty(foo)").isEqualTo(3)
+ assertThat(p.getIntProperty("one", 9), "getIntProperty(one)").isEqualTo(1)
+ assertThat(p.getIntProperty("two", 2), "getIntProperty(two)").isEqualTo(2)
+ assertThat(p.getIntProperty("foo", 3), "getIntProperty(foo)").isEqualTo(3)
}
@Test
@@ -169,26 +170,26 @@ class UtilsTest {
@Test
fun testHelpFormat() {
- assertThat(helpFormat(test, isBold = true, isIndent = false)).describedAs("bold")
+ assertThat(helpFormat(test, isBold = true, isIndent = false), "bold")
.isEqualTo("${Colors.BOLD}$test${Colors.BOLD}")
- assertThat(helpFormat(test, isBold = false, isIndent = true)).describedAs("indent")
+ assertThat(helpFormat(test, isBold = false, isIndent = true), "indent")
.isEqualTo(test.prependIndent())
- assertThat(helpFormat(test, isBold = true, isIndent = true)).describedAs("bold-indent")
+ assertThat(helpFormat(test, isBold = true, isIndent = true), "bold-indent")
.isEqualTo(colorize(test, Colors.BOLD).prependIndent())
}
@Test
fun testIsoLocalDate() {
- assertThat(cal.time.toIsoLocalDate()).describedAs("isoLocalDate(date)").isEqualTo("1952-02-17")
- assertThat(localDateTime.toIsoLocalDate()).describedAs("isoLocalDate(localDate)").isEqualTo("1952-02-17")
+ assertThat(cal.time.toIsoLocalDate(), "isoLocalDate(date)").isEqualTo("1952-02-17")
+ assertThat(localDateTime.toIsoLocalDate(), "isoLocalDate(localDate)").isEqualTo("1952-02-17")
}
@Test
fun testObfuscate() {
- assertThat(ascii.obfuscate().length).describedAs("obfuscate is right length").isEqualTo(ascii.length)
- assertThat(ascii.obfuscate()).describedAs("obfuscate()").isEqualTo("x".repeat(ascii.length))
- assertThat(" ".obfuscate()).describedAs("obfuscate(blank)").isEqualTo(" ")
+ assertThat(ascii.obfuscate().length, "obfuscate is right length").isEqualTo(ascii.length)
+ assertThat(ascii.obfuscate(), "obfuscate()").isEqualTo("x".repeat(ascii.length))
+ assertThat(" ".obfuscate(), "obfuscate(blank)").isEqualTo(" ")
}
@Test
@@ -197,7 +198,7 @@ class UtilsTest {
val weeks = "weeks"
for (i in -1..3) {
- assertThat(week.plural(i.toLong())).describedAs("plural($i)").isEqualTo(if (i > 1) weeks else week)
+ assertThat(week.plural(i.toLong()), "plural($i)").isEqualTo(if (i > 1) weeks else week)
}
}
@@ -205,15 +206,15 @@ class UtilsTest {
fun testReplaceEach() {
val search = arrayOf("one", "two", "three")
val replace = arrayOf("1", "2", "3")
- assertThat(search.joinToString(",").replaceEach(search, replace)).describedAs("replaceEach(1,2,3")
+ assertThat(search.joinToString(",").replaceEach(search, replace), "replaceEach(1,2,3")
.isEqualTo(replace.joinToString(","))
- assertThat(test.replaceEach(search, replace)).describedAs("replaceEach(nothing)").isEqualTo(test)
+ assertThat(test.replaceEach(search, replace), "replaceEach(nothing)").isEqualTo(test)
- assertThat(test.replaceEach(arrayOf("t", "e"), arrayOf("", "E"))).describedAs("replaceEach($test)")
+ assertThat(test.replaceEach(arrayOf("t", "e"), arrayOf("", "E")), "replaceEach($test)")
.isEqualTo(test.replace("t", "").replace("e", "E"))
- assertThat(test.replaceEach(search, emptyArray())).describedAs("replaceEach(search, empty)")
+ assertThat(test.replaceEach(search, emptyArray()), "replaceEach(search, empty)")
.isEqualTo(test)
}
@@ -234,8 +235,8 @@ class UtilsTest {
@Test
fun testToIntOrDefault() {
- assertThat("10".toIntOrDefault(1)).describedAs("toIntOrDefault(10, 1)").isEqualTo(10)
- assertThat("a".toIntOrDefault(2)).describedAs("toIntOrDefault(a, 2)").isEqualTo(2)
+ assertThat("10".toIntOrDefault(1), "toIntOrDefault(10, 1)").isEqualTo(10)
+ assertThat("a".toIntOrDefault(2), "toIntOrDefault(a, 2)").isEqualTo(2)
}
@Test
@@ -247,26 +248,26 @@ class UtilsTest {
@Test
fun testUptime() {
- assertThat(uptime(547800300076L)).describedAs("full")
+ assertThat(uptime(547800300076L), "full")
.isEqualTo("17 years 2 months 2 weeks 1 day 6 hours 45 minutes")
- assertThat(uptime(2700000L)).describedAs("minutes").isEqualTo("45 minutes")
- assertThat(uptime(24300000L)).describedAs("hours minutes").isEqualTo("6 hours 45 minutes")
- assertThat(uptime(110700000L)).describedAs("days hours minutes").isEqualTo("1 day 6 hours 45 minutes")
- assertThat(uptime(1320300000L)).describedAs("weeks days hours minutes")
+ assertThat(uptime(2700000L), "minutes").isEqualTo("45 minutes")
+ assertThat(uptime(24300000L), "hours minutes").isEqualTo("6 hours 45 minutes")
+ assertThat(uptime(110700000L), "days hours minutes").isEqualTo("1 day 6 hours 45 minutes")
+ assertThat(uptime(1320300000L), "weeks days hours minutes")
.isEqualTo("2 weeks 1 day 6 hours 45 minutes")
- assertThat(uptime(0L)).describedAs("0 minutes").isEqualTo("0 minute")
+ assertThat(uptime(0L), "0 minutes").isEqualTo("0 minute")
}
@Test
@Throws(IOException::class)
fun testUrlReader() {
- assertThat(urlReader(URL("https://postman-echo.com/status/200"))).describedAs("urlReader()")
+ assertThat(urlReader(URL("https://postman-echo.com/status/200")), "urlReader()")
.isEqualTo("{\"status\":200}")
}
@Test
fun testUtcDateTime() {
- assertThat(cal.time.toUtcDateTime()).describedAs("utcDateTime(date)").isEqualTo("1952-02-17 12:30")
- assertThat(localDateTime.toUtcDateTime()).describedAs("utcDateTime(localDate)").isEqualTo("1952-02-17 12:30")
+ assertThat(cal.time.toUtcDateTime(), "utcDateTime(date)").isEqualTo("1952-02-17 12:30")
+ assertThat(localDateTime.toUtcDateTime(), "utcDateTime(localDate)").isEqualTo("1952-02-17 12:30")
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt
index 86422ca..808ea97 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt
@@ -31,7 +31,12 @@
*/
package net.thauvin.erik.mobibot.commands.tell
-import org.assertj.core.api.Assertions.assertThat
+import assertk.all
+import assertk.assertThat
+import assertk.assertions.isEqualTo
+import assertk.assertions.isFalse
+import assertk.assertions.isTrue
+import assertk.assertions.prop
import org.testng.annotations.Test
import java.time.Duration
import java.time.LocalDateTime
@@ -51,18 +56,21 @@ class TellMessageTest {
val recipient = "recipient"
val sender = "sender"
val tellMessage = TellMessage(sender, recipient, message)
- assertThat(tellMessage).extracting("sender", "recipient", "message")
- .containsExactly(sender, recipient, message)
- assertThat(isValidDate(tellMessage.queued)).describedAs("queued is valid date/time").isTrue
- assertThat(tellMessage.isMatch(sender)).describedAs("match sender").isTrue
- assertThat(tellMessage.isMatch(recipient)).describedAs("match recipient").isTrue
- assertThat(tellMessage.isMatch("foo")).describedAs("foo is no match").isFalse
+ assertThat(tellMessage).all {
+ prop(TellMessage::sender).isEqualTo(sender)
+ prop(TellMessage::recipient).isEqualTo(recipient)
+ prop(TellMessage::message).isEqualTo(message)
+ }
+ assertThat(isValidDate(tellMessage.queued), "queued is valid date/time").isTrue()
+ assertThat(tellMessage.isMatch(sender), "match sender").isTrue()
+ assertThat(tellMessage.isMatch(recipient), "match recipient").isTrue()
+ assertThat(tellMessage.isMatch("foo"), "foo is no match").isFalse()
tellMessage.isReceived = false
- assertThat(tellMessage.receptionDate).describedAs("reception date not set").isEqualTo(LocalDateTime.MIN)
+ assertThat(tellMessage.receptionDate, "reception date not set").isEqualTo(LocalDateTime.MIN)
tellMessage.isReceived = true
- assertThat(tellMessage.isReceived).describedAs("is received").isTrue
- assertThat(isValidDate(tellMessage.receptionDate)).describedAs("received is valid date/time").isTrue
+ assertThat(tellMessage.isReceived, "is received").isTrue()
+ assertThat(isValidDate(tellMessage.receptionDate), "received is valid date/time").isTrue()
tellMessage.isNotified = true
- assertThat(tellMessage.isNotified).describedAs("is notified").isTrue
+ assertThat(tellMessage.isNotified, "is notified").isTrue()
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt
index 347b508..94a6b7e 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt
@@ -31,9 +31,16 @@
*/
package net.thauvin.erik.mobibot.entries
+import assertk.all
+import assertk.assertThat
+import assertk.assertions.isEmpty
+import assertk.assertions.isEqualTo
+import assertk.assertions.isFalse
+import assertk.assertions.isTrue
+import assertk.assertions.prop
+import assertk.assertions.size
import com.rometools.rome.feed.synd.SyndCategory
import com.rometools.rome.feed.synd.SyndCategoryImpl
-import org.assertj.core.api.Assertions.assertThat
import org.testng.annotations.Test
import java.security.SecureRandom
import java.util.Date
@@ -58,21 +65,30 @@ class EntryLinkTest {
entryLink.addComment("c$i", "u$i")
i++
}
- assertThat(entryLink.comments.size).describedAs("getComments().size() == 5").isEqualTo(i)
+ assertThat(entryLink.comments.size, "getComments().size() == 5").isEqualTo(i)
i = 0
for (comment in entryLink.comments) {
- assertThat(comment).extracting("comment", "nick").containsExactly("c$i", "u$i")
+ assertThat(comment).all {
+ prop(EntryComment::comment).isEqualTo("c$i")
+ prop(EntryComment::nick).isEqualTo("u$i")
+ }
i++
}
+
val r = SecureRandom()
while (entryLink.comments.size > 0) {
entryLink.deleteComment(r.nextInt(entryLink.comments.size))
}
- assertThat(entryLink.comments).describedAs("hasComments()").isEmpty()
+ assertThat(entryLink.comments, "hasComments()").isEmpty()
entryLink.addComment("nothing", "nobody")
entryLink.setComment(0, "something", "somebody")
- assertThat(entryLink.getComment(0)).describedAs("get first comment").extracting("nick", "comment")
- .containsExactly("somebody", "something")
+ val comment = entryLink.getComment(0)
+ assertThat(comment, "get first comment").all {
+ prop(EntryComment::nick).isEqualTo("somebody")
+ prop(EntryComment::comment).isEqualTo("something")
+ }
+ assertThat(entryLink.deleteComment(comment), "delete comment").isTrue()
+ assertThat(entryLink.deleteComment(comment), "comment is already deleted").isFalse()
}
@Test
@@ -80,19 +96,19 @@ class EntryLinkTest {
val tag = "test"
val tags = listOf(SyndCategoryImpl().apply { name = tag })
val link = EntryLink("link", "title", "nick", "channel", Date(), tags)
- assertThat(link.tags.size).describedAs("check tag size").isEqualTo(tags.size)
- assertThat(link.tags[0].name).describedAs("check tag name").isEqualTo(tag)
- assertThat(link.pinboardTags).describedAs("check pinboard tags").isEqualTo("nick,$tag")
+ assertThat(link.tags.size, "check tag size").isEqualTo(tags.size)
+ assertThat(link.tags[0].name, "check tag name").isEqualTo(tag)
+ assertThat(link.pinboardTags, "check pinboard tags").isEqualTo("nick,$tag")
}
@Test
fun testMatches() {
- assertThat(entryLink.matches("mobitopia")).describedAs("match mobitopia").isTrue
- assertThat(entryLink.matches("skynx")).describedAs("match nick").isTrue
- assertThat(entryLink.matches("www.mobitopia.org")).describedAs("match url").isTrue
- assertThat(entryLink.matches("foo")).describedAs("match foo").isFalse
- assertThat(entryLink.matches("")).describedAs("match empty").isFalse
- assertThat(entryLink.matches(null)).describedAs("match null").isFalse
+ assertThat(entryLink.matches("mobitopia"), "match mobitopia").isTrue()
+ assertThat(entryLink.matches("skynx"), "match nick").isTrue()
+ assertThat(entryLink.matches("www.mobitopia.org"), "match url").isTrue()
+ assertThat(entryLink.matches("foo"), "match foo").isFalse()
+ assertThat(entryLink.matches(""), "match empty").isFalse()
+ assertThat(entryLink.matches(null), "match null").isFalse()
}
@@ -100,20 +116,19 @@ class EntryLinkTest {
fun testTags() {
val tags: List = entryLink.tags
for ((i, tag) in tags.withIndex()) {
- assertThat(tag.name).describedAs("tag.getName($i)").isEqualTo("tag" + (i + 1))
+ assertThat(tag.name, "tag.getName($i)").isEqualTo("tag" + (i + 1))
}
- assertThat(entryLink.tags.size).describedAs("getTags().size() is 5").isEqualTo(5)
- assertThat(entryLink.tags).describedAs("hasTags() is true").isNotEmpty
+ assertThat(entryLink.tags, "size is 5").size().isEqualTo(5)
entryLink.setTags("-tag5")
entryLink.setTags("+mobitopia")
entryLink.setTags("tag4")
entryLink.setTags("-mobitopia")
- assertThat(entryLink.pinboardTags).describedAs("getPinboardTags()")
+ assertThat(entryLink.pinboardTags, "getPinboardTags()")
.isEqualTo(entryLink.nick + ",tag1,tag2,tag3,tag4,mobitopia")
val size = entryLink.tags.size
entryLink.setTags("")
- assertThat(entryLink.tags.size).describedAs("empty tag").isEqualTo(size)
+ assertThat(entryLink.tags.size, "empty tag").isEqualTo(size)
entryLink.setTags(" ")
- assertThat(entryLink.tags.size).describedAs("blank tag").isEqualTo(size)
+ assertThat(entryLink.tags.size, "blank tag").isEqualTo(size)
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt
new file mode 100644
index 0000000..04c36a7
--- /dev/null
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt
@@ -0,0 +1,121 @@
+/*
+ * FeedMgrTest.kt
+ *
+ * Copyright (c) 2004-2021, Erik C. Thauvin (erik@thauvin.net)
+ * All rights reserved.
+ *
+ * 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.entries
+
+import assertk.all
+import assertk.assertThat
+import assertk.assertions.endsWith
+import assertk.assertions.isEqualTo
+import assertk.assertions.isTrue
+import assertk.assertions.prop
+import net.thauvin.erik.mobibot.Utils.today
+import org.testng.annotations.BeforeSuite
+import org.testng.annotations.Test
+import java.nio.file.Paths
+import java.util.Date
+import kotlin.io.path.absolutePathString
+import kotlin.io.path.deleteIfExists
+import kotlin.io.path.exists
+import kotlin.io.path.fileSize
+import kotlin.io.path.name
+
+class FeedMgrTest {
+ private val entries = Entries()
+ private val channel = "mobibot"
+
+ @BeforeSuite(alwaysRun = true)
+ fun beforeSuite() {
+ entries.logsDir = "src/test/resources/"
+ entries.ircServer = "irc.example.com"
+ entries.channel = channel
+ entries.backlogs = "https://www.mobitopia.org/mobibot/logs"
+ }
+
+ @Test
+ fun testFeedMgr() {
+ // Load the feed
+ assertThat(FeedsMgr.loadFeed(entries), "pubDate").isEqualTo("2021-10-31")
+
+ assertThat(entries.links.size, "2 links").isEqualTo(2)
+ entries.links.forEachIndexed { i, entryLink ->
+ assertThat(entryLink, "Example $(i + 1)").all {
+ prop(EntryLink::title).isEqualTo("Example ${i + 1}")
+ prop(EntryLink::link).isEqualTo("https://www.example.com/${i + 1}")
+ prop(EntryLink::channel).isEqualTo(channel)
+ }
+ entryLink.tags.forEachIndexed { y, tag ->
+ assertThat(tag.name, "tag${i + 1}-${y + 1}").isEqualTo("tag${i + 1}-${y + 1}")
+ }
+ }
+
+ with(entries.links.first()) {
+ assertThat(nick, "first nick").isEqualTo("ErikT")
+ assertThat(date, "first date").isEqualTo(Date(1635638400000L))
+ comments.forEachIndexed { i, entryComment ->
+ assertThat(entryComment.comment, "comment ${i + 1}").endsWith("comment ${i + 1}.")
+ if (i == 0) {
+ assertThat(entryComment.nick, "comment ${i + 1} nick").isEqualTo("ErikT")
+ } else {
+ assertThat(entryComment.nick, "comment ${i + 1} nick").isEqualTo("Skynx")
+ }
+ }
+ }
+
+ assertThat(entries.links[1], "second link").all {
+ prop(EntryLink::nick).isEqualTo("Skynx")
+ prop(EntryLink::date).isEqualTo(Date(1635638460000L))
+ }
+
+ val currentFile = Paths.get("${entries.logsDir}test.xml")
+ val backlogFile = Paths.get("${entries.logsDir}${today()}.xml")
+
+ // Save the feed
+ FeedsMgr.saveFeed(entries, currentFile.name)
+
+ assertThat(currentFile.exists(), "${currentFile.absolutePathString()} exists").isTrue()
+ assertThat(backlogFile.exists(), "${backlogFile.absolutePathString()} exits").isTrue()
+
+ assertThat(currentFile.fileSize(), "files are identical").isEqualTo(backlogFile.fileSize())
+
+ // Load the test feed
+ entries.links.clear()
+ FeedsMgr.loadFeed(entries, currentFile.name)
+
+ entries.links.forEachIndexed { i, entryLink ->
+ assertThat(entryLink.title, "${currentFile.name} title ${i + 1}").isEqualTo("Example ${i + 1}")
+ }
+
+ assertThat(currentFile.deleteIfExists(), "delete ${currentFile.absolutePathString()}").isTrue()
+ assertThat(backlogFile.deleteIfExists(), "delete ${backlogFile.absolutePathString()}").isTrue()
+ }
+}
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 ad0740e..c1b9a4d 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt
@@ -31,11 +31,13 @@
*/
package net.thauvin.erik.mobibot.modules
+import assertk.assertThat
+import assertk.assertions.isEqualTo
+import assertk.assertions.isFailure
+import assertk.assertions.isInstanceOf
import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException
import net.thauvin.erik.mobibot.Utils.bold
import net.thauvin.erik.mobibot.modules.Calc.Companion.calculate
-import org.assertj.core.api.Assertions.assertThat
-import org.assertj.core.api.Assertions.assertThatThrownBy
import org.testng.annotations.Test
/**
@@ -44,11 +46,11 @@ import org.testng.annotations.Test
class CalcTest {
@Test
fun testCalculate() {
- assertThat(calculate("1 + 1")).describedAs("calculate(1+1)").isEqualTo("1+1 = %s", bold(2))
- assertThat(calculate("1 -3")).describedAs("calculate(1 -3)").isEqualTo("1-3 = %s", bold(-2))
- assertThat(calculate("pi+π+e+φ")).describedAs("calculate(pi+π+e+φ)")
- .isEqualTo("pi+π+e+φ = %s", bold("10.62"))
- assertThatThrownBy { calculate("one + one") }.describedAs("calculate(one+one)")
- .isInstanceOf(UnknownFunctionOrVariableException::class.java)
+ assertThat(calculate("1 + 1"), "calculate(1+1)").isEqualTo("1+1 = ${bold(2)}")
+ assertThat(calculate("1 -3"), "calculate(1 -3)").isEqualTo("1-3 = ${bold(-2)}")
+ assertThat(calculate("pi+π+e+φ"), "calculate(pi+π+e+φ)")
+ .isEqualTo("pi+π+e+φ = ${bold("10.62")}")
+ assertThat { calculate("one + one") }
+ .isFailure().isInstanceOf(UnknownFunctionOrVariableException::class.java)
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt
index 8d0c70a..e5f5e52 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt
@@ -31,8 +31,13 @@
*/
package net.thauvin.erik.mobibot.modules
+import assertk.all
+import assertk.assertThat
+import assertk.assertions.isEqualTo
+import assertk.assertions.isGreaterThan
+import assertk.assertions.prop
+import net.thauvin.erik.crypto.CryptoPrice
import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.currentPrice
-import org.assertj.core.api.Assertions.assertThat
import org.testng.annotations.Test
/**
@@ -43,11 +48,17 @@ class CryptoPricesTest {
@Throws(ModuleException::class)
fun testMarketPrice() {
var price = currentPrice(listOf("BTC"))
- assertThat(price).extracting("base", "currency").containsExactly("BTC", "USD")
- assertThat(price.amount.signum()).describedAs("BTC > 0").isGreaterThan(0)
+ assertThat(price, "BTC in USD").all {
+ prop(CryptoPrice::base).isEqualTo("BTC")
+ prop(CryptoPrice::currency).isEqualTo("USD")
+ prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0)
+ }
price = currentPrice(listOf("ETH", "EUR"))
- assertThat(price).extracting("base", "currency").containsExactly("ETH", "EUR")
- assertThat(price.amount.signum()).describedAs("ETH > 0").isGreaterThan(0)
+ assertThat(price, "ETH in EUR").all {
+ prop(CryptoPrice::base).isEqualTo("ETH")
+ prop(CryptoPrice::currency).isEqualTo("EUR")
+ prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0)
+ }
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt
index 84fa190..962e2c2 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt
@@ -31,10 +31,21 @@
*/
package net.thauvin.erik.mobibot.modules
+import assertk.all
+import assertk.assertThat
+import assertk.assertions.any
+import assertk.assertions.contains
+import assertk.assertions.isEqualTo
+import assertk.assertions.isInstanceOf
+import assertk.assertions.matches
+import assertk.assertions.prop
+import assertk.assertions.size
import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.convertCurrency
import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.currencyRates
import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.loadRates
-import org.assertj.core.api.Assertions.assertThat
+import net.thauvin.erik.mobibot.msg.ErrorMessage
+import net.thauvin.erik.mobibot.msg.Message
+import net.thauvin.erik.mobibot.msg.PublicMessage
import org.testng.annotations.BeforeClass
import org.testng.annotations.Test
@@ -50,14 +61,28 @@ class CurrencyConverterTest {
@Test
fun testConvertCurrency() {
- assertThat(convertCurrency("100 USD to EUR").msg)
- .describedAs("100 USD to EUR").matches("\\$100\\.00 = €\\d{2,3}\\.\\d{2}")
- assertThat(convertCurrency("100 USD to USD").msg).describedAs("100 USD to USD")
- .contains("You're kidding, right?")
- assertThat(convertCurrency("100 USD").msg).describedAs("100 USD").contains("Invalid query.")
+ assertThat(
+ convertCurrency("100 USD to EUR").msg,
+ "100 USD to EUR"
+ ).matches("\\$100\\.00 = €\\d{2,3}\\.\\d{2}".toRegex())
+ assertThat(convertCurrency("100 USD to USD"), "100 USD to USD").all {
+ prop(Message::msg).contains("You're kidding, right?")
+ isInstanceOf(PublicMessage::class.java)
+ }
+ assertThat(convertCurrency("100 USD"), "100 USD").all {
+ prop(Message::msg).contains("Invalid query.")
+ isInstanceOf(ErrorMessage::class.java)
+ }
+ }
+
+ @Test
+ fun testCurrencyRates() {
val rates = currencyRates()
- assertThat(rates.size).describedAs("currencyRates.size == 33").isEqualTo(33)
- assertThat(rates).describedAs("currencyRates(EUR< USD)").contains("EUR: 1")
- .anyMatch { it.matches("USD: .*".toRegex()) }
+ assertThat(rates).all {
+ size().isEqualTo(33)
+ any { it.matches("[A-Z]{3}: +[\\d.]+".toRegex()) }
+ contains("EUR: 1")
+ }
+
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt
index 681dc5b..dfebd9d 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt
@@ -33,14 +33,15 @@
package net.thauvin.erik.mobibot.modules
-import org.assertj.core.api.Assertions.assertThat
+import assertk.assertThat
+import assertk.assertions.isEqualTo
import org.testng.annotations.Test
class DiceTest {
@Test
fun testWinLoseOrTie() {
- assertThat(Dice.winLoseOrTie(6, 6)).describedAs("6 vs. 6").isEqualTo(Dice.Result.TIE)
- assertThat(Dice.winLoseOrTie(6, 5)).describedAs("6 vs. 5").isEqualTo(Dice.Result.WIN)
- assertThat(Dice.winLoseOrTie(5, 6)).describedAs("5 vs. 6").isEqualTo(Dice.Result.LOSE)
+ assertThat(Dice.winLoseOrTie(6, 6), "6 vs. 6").isEqualTo(Dice.Result.TIE)
+ assertThat(Dice.winLoseOrTie(6, 5), "6 vs. 5").isEqualTo(Dice.Result.WIN)
+ assertThat(Dice.winLoseOrTie(5, 6), "5 vs. 6").isEqualTo(Dice.Result.LOSE)
}
}
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 5dfc1f2..fd7b4c7 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt
@@ -31,11 +31,20 @@
*/
package net.thauvin.erik.mobibot.modules
+import assertk.all
+import assertk.assertThat
+import assertk.assertions.contains
+import assertk.assertions.hasNoCause
+import assertk.assertions.isEqualTo
+import assertk.assertions.isFailure
+import assertk.assertions.isInstanceOf
+import assertk.assertions.isNotEmpty
+import assertk.assertions.prop
+import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize
import net.thauvin.erik.mobibot.LocalProperties
-import net.thauvin.erik.mobibot.Sanitize.sanitizeException
import net.thauvin.erik.mobibot.modules.GoogleSearch.Companion.searchGoogle
-import org.assertj.core.api.Assertions.assertThat
-import org.assertj.core.api.Assertions.assertThatThrownBy
+import net.thauvin.erik.mobibot.msg.ErrorMessage
+import net.thauvin.erik.mobibot.msg.Message
import org.testng.annotations.Test
/**
@@ -49,23 +58,33 @@ class GoogleSearchTest : LocalProperties() {
val cseKey = getProperty(GoogleSearch.GOOGLE_CSE_KEY_PROP)
try {
var messages = searchGoogle("mobitopia", apiKey, cseKey)
- assertThat(messages).describedAs("mobitopia results not empty").isNotEmpty
- assertThat(messages[0].msg).describedAs("found mobibtopia").containsIgnoringCase("mobitopia")
+ assertThat(messages, "mobitopia results not empty").isNotEmpty()
+ assertThat(messages[0].msg, "found mobibtopia").contains("mobitopia", true)
+
messages = searchGoogle("aapl", apiKey, cseKey)
- assertThat(messages).describedAs("aapl results not empty").isNotEmpty
- assertThat(messages[0].msg).describedAs("found apple").containsIgnoringCase("apple")
- assertThatThrownBy { searchGoogle("test", "", "apiKey") }
- .describedAs("no API key")
+ assertThat(messages, "aapl results not empty").isNotEmpty()
+ assertThat(messages[0].msg, "found apple").contains("apple", true)
+
+ messages = searchGoogle("adadflkjl", apiKey, cseKey)
+ assertThat(messages[0], "not found").all {
+ isInstanceOf(ErrorMessage::class.java)
+ prop(Message::msg).isEqualTo("No results found.")
+ }
+
+ assertThat(
+ searchGoogle("", "apikey", "cssKey").first(),
+ "empty query"
+ ).isInstanceOf(ErrorMessage::class.java)
+
+ assertThat { searchGoogle("test", "", "apiKey") }.isFailure()
.isInstanceOf(ModuleException::class.java).hasNoCause()
- assertThatThrownBy { searchGoogle("test", "apiKey", "") }
- .describedAs("no CSE API key")
+
+ assertThat { searchGoogle("test", "apiKey", "") }.isFailure()
.isInstanceOf(ModuleException::class.java).hasNoCause()
- assertThatThrownBy { searchGoogle("", "apikey", "apiKey") }
- .describedAs("no query").isInstanceOf(ModuleException::class.java).hasNoCause()
} catch (e: ModuleException) {
// Avoid displaying api keys in CI logs
if ("true" == System.getenv("CI")) {
- throw sanitizeException(e, apiKey, cseKey)
+ throw e.sanitize(apiKey, cseKey)
} else {
throw e
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt
index 28fd592..865a65f 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt
@@ -31,8 +31,11 @@
*/
package net.thauvin.erik.mobibot.modules
+import assertk.all
+import assertk.assertThat
+import assertk.assertions.contains
+import assertk.assertions.isNotEmpty
import net.thauvin.erik.mobibot.modules.Joke.Companion.randomJoke
-import org.assertj.core.api.Assertions.assertThat
import org.testng.annotations.Test
/**
@@ -42,7 +45,9 @@ class JokeTest {
@Test
@Throws(ModuleException::class)
fun testRandomJoke() {
- assertThat(randomJoke().msg).describedAs("randomJoke() > 0").isNotEmpty
- assertThat(randomJoke().msg).describedAs("randomJoke()").containsIgnoringCase("chuck")
+ assertThat(randomJoke().msg, "randomJoke() > 0").all {
+ isNotEmpty()
+ contains("chuck", true)
+ }
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt
index 211afdd..b3e3dff 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt
@@ -31,9 +31,11 @@
*/
package net.thauvin.erik.mobibot.modules
+import assertk.assertThat
+import assertk.assertions.any
+import assertk.assertions.contains
import net.thauvin.erik.mobibot.modules.Lookup.Companion.nslookup
import net.thauvin.erik.mobibot.modules.Lookup.Companion.whois
-import org.assertj.core.api.Assertions.assertThat
import org.testng.annotations.Test
/**
@@ -44,14 +46,13 @@ class LookupTest {
@Throws(Exception::class)
fun testLookup() {
val result = nslookup("apple.com")
- assertThat(result).describedAs("lookup(apple.com)").contains("17.253.144.10")
+ assertThat(result, "lookup(apple.com)").contains("17.253.144.10")
}
@Test
@Throws(Exception::class)
fun testWhois() {
val result = whois("17.178.96.59", Lookup.WHOIS_HOST)
- assertThat(result).describedAs("whois(17.178.96.59/Apple Inc.")
- .anyMatch { it.contains("Apple Inc.") }
+ assertThat(result, "whois(17.178.96.59/Apple Inc.").any { it.contains("Apple Inc.") }
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt
index 4ad980b..d776f2c 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt
@@ -31,8 +31,16 @@
*/
package net.thauvin.erik.mobibot.modules
-import net.thauvin.erik.mobibot.Sanitize.sanitizeException
-import org.assertj.core.api.Assertions.assertThat
+import assertk.all
+import assertk.assertThat
+import assertk.assertions.contains
+import assertk.assertions.doesNotContain
+import assertk.assertions.endsWith
+import assertk.assertions.hasMessage
+import assertk.assertions.isEqualTo
+import assertk.assertions.isNotNull
+import assertk.assertions.isNull
+import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize
import org.testng.annotations.DataProvider
import org.testng.annotations.Test
import java.io.IOException
@@ -58,37 +66,41 @@ class ModuleExceptionTest {
@Test(dataProvider = "dp")
fun testGetDebugMessage(e: ModuleException) {
- assertThat(e.debugMessage).describedAs("get debug message").isEqualTo(debugMessage)
+ assertThat(e.debugMessage, "get debug message").isEqualTo(debugMessage)
}
@Test(dataProvider = "dp")
fun testGetMessage(e: ModuleException) {
- assertThat(e).describedAs("get message").hasMessage(message)
+ assertThat(e, "get message").hasMessage(message)
}
@Test
fun testSanitizeMessage() {
val apiKey = "1234567890"
var e = ModuleException(debugMessage, message, IOException("URL http://foo.com?apiKey=$apiKey&userID=me"))
- assertThat(sanitizeException(e, apiKey, "", "me")).describedAs("sanitized url")
- .hasMessageContainingAll("xxxxxxxxxx", "userID=xx", "java.io.IOException")
- .hasMessageNotContainingAny(apiKey, "me")
+ assertThat(e.sanitize(apiKey, "", "me").message, "sanitized url").isNotNull().all {
+ contains("xxxxxxxxxx", "userID=xx", "java.io.IOException")
+ doesNotContain(apiKey, "me")
+ }
e = ModuleException(debugMessage, message, null)
- assertThat(sanitizeException(e, apiKey)).describedAs("no cause").hasMessage(message)
+ assertThat(e.sanitize(apiKey), "no cause").hasMessage(message)
e = ModuleException(debugMessage, message, IOException())
- assertThat(sanitizeException(e, apiKey)).describedAs("no cause message").hasMessage(message)
+ assertThat(e.sanitize(apiKey), "no cause message").hasMessage(message)
e = ModuleException(apiKey)
- assertThat(sanitizeException(e, apiKey)).describedAs("api key in message").hasMessageNotContaining(apiKey)
+ assertThat(e.sanitize(apiKey).message, "api key in message").isNotNull().doesNotContain(apiKey)
val msg: String? = null
e = ModuleException(debugMessage, msg, IOException(msg))
- assertThat(sanitizeException(e, apiKey).message).describedAs("null message").isNull()
+ assertThat(e.sanitize(apiKey).message, "null message").isNull()
e = ModuleException(msg, msg, IOException("foo is $apiKey"))
- assertThat(sanitizeException(e, " ", apiKey, "foo").message).describedAs("key in cause")
- .doesNotContain(apiKey).endsWith("xxx is xxxxxxxxxx")
+ assertThat(e.sanitize(" ", apiKey, "foo").message, "key in cause").isNotNull().all {
+ doesNotContain(apiKey)
+ endsWith("xxx is xxxxxxxxxx")
+ }
+ assertThat(e.sanitize(), "empty").isEqualTo(e)
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt
index e79fbcc..34cbfbb 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt
@@ -31,8 +31,10 @@
*/
package net.thauvin.erik.mobibot.modules
+import assertk.assertThat
+import assertk.assertions.contains
+import assertk.assertions.isNotEmpty
import net.thauvin.erik.mobibot.modules.Ping.Companion.randomPing
-import org.assertj.core.api.Assertions.assertThat
import org.testng.annotations.Test
/**
@@ -41,13 +43,13 @@ import org.testng.annotations.Test
class PingTest {
@Test
fun testPingsArray() {
- assertThat(Ping.PINGS).describedAs("Pings array is not empty.").isNotEmpty
+ assertThat(Ping.PINGS, "Pings array is not empty.").isNotEmpty()
}
@Test
fun testRandomPing() {
for (i in 0..9) {
- assertThat(randomPing()).describedAs("Random ping $i").isIn(Ping.PINGS)
+ assertThat(Ping.PINGS, "Random ping $i").contains(randomPing())
}
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt
index 3f5352f..499c28c 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt
@@ -32,23 +32,19 @@
package net.thauvin.erik.mobibot.modules
-import org.assertj.core.api.Assertions.assertThat
+import assertk.assertThat
+import assertk.assertions.isEqualTo
import org.testng.annotations.Test
class RockPaperScissorsTest {
@Test
fun testWinLoseOrDraw() {
- assertThat(RockPaperScissors.winLoseOrDraw("scissors", "paper")).describedAs("scissors vs. paper")
- .isEqualTo("win")
- assertThat(RockPaperScissors.winLoseOrDraw("paper", "rock")).describedAs("paper vs. rock").isEqualTo("win")
- assertThat(RockPaperScissors.winLoseOrDraw("rock", "scissors")).describedAs("rock vs. scissors")
- .isEqualTo("win")
- assertThat(RockPaperScissors.winLoseOrDraw("paper", "scissors")).describedAs("paper vs. scissors")
- .isEqualTo("lose")
- assertThat(RockPaperScissors.winLoseOrDraw("rock", "paper")).describedAs("rock vs. paper").isEqualTo("lose")
- assertThat(RockPaperScissors.winLoseOrDraw("scissors", "rock")).describedAs("scissors vs. rock")
- .isEqualTo("lose")
- assertThat(RockPaperScissors.winLoseOrDraw("scissors", "scissors"))
- .describedAs("scissors vs. scissors").isEqualTo("draw")
+ assertThat(RockPaperScissors.winLoseOrDraw("scissors", "paper"), "scissors vs. paper").isEqualTo("win")
+ assertThat(RockPaperScissors.winLoseOrDraw("paper", "rock"), "paper vs. rock").isEqualTo("win")
+ assertThat(RockPaperScissors.winLoseOrDraw("rock", "scissors"), "rock vs. scissors").isEqualTo("win")
+ assertThat(RockPaperScissors.winLoseOrDraw("paper", "scissors"), "paper vs. scissors").isEqualTo("lose")
+ assertThat(RockPaperScissors.winLoseOrDraw("rock", "paper"), "rock vs. paper").isEqualTo("lose")
+ assertThat(RockPaperScissors.winLoseOrDraw("scissors", "rock"), "scissors vs. rock").isEqualTo("lose")
+ assertThat(RockPaperScissors.winLoseOrDraw("scissors", "scissors"), "scissors vs. scissors").isEqualTo("draw")
}
}
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 4eb4081..8812c21 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt
@@ -31,11 +31,20 @@
*/
package net.thauvin.erik.mobibot.modules
+import assertk.all
+import assertk.assertThat
+import assertk.assertions.hasNoCause
+import assertk.assertions.isEqualTo
+import assertk.assertions.isFailure
+import assertk.assertions.isInstanceOf
+import assertk.assertions.isNotEmpty
+import assertk.assertions.matches
+import assertk.assertions.prop
+import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize
import net.thauvin.erik.mobibot.LocalProperties
-import net.thauvin.erik.mobibot.Sanitize.sanitizeException
import net.thauvin.erik.mobibot.modules.StockQuote.Companion.getQuote
-import org.assertj.core.api.Assertions.assertThat
-import org.assertj.core.api.Assertions.assertThatThrownBy
+import net.thauvin.erik.mobibot.msg.ErrorMessage
+import net.thauvin.erik.mobibot.msg.Message
import org.testng.annotations.Test
/**
@@ -52,24 +61,25 @@ class StockQuoteTest : LocalProperties() {
val apiKey = getProperty(StockQuote.ALPHAVANTAGE_API_KEY_PROP)
try {
val messages = getQuote("apple inc", apiKey)
- assertThat(messages).describedAs("response not empty").isNotEmpty
- assertThat(messages[0].msg).describedAs("same stock symbol").matches("Symbol: AAPL .*")
- assertThat(messages[1].msg).describedAs("price label").matches(buildMatch("Price"))
- assertThat(messages[2].msg).describedAs("previous label").matches(buildMatch("Previous"))
- assertThat(messages[3].msg).describedAs("open label").matches(buildMatch("Open"))
- try {
- getQuote("blahfoo", apiKey)
- } catch (e: ModuleException) {
- assertThat(e.message).describedAs("invalid symbol").containsIgnoringCase(StockQuote.INVALID_SYMBOL)
+ assertThat(messages, "response not empty").isNotEmpty()
+ assertThat(messages[0].msg, "same stock symbol").matches("Symbol: AAPL .*".toRegex())
+ assertThat(messages[1].msg, "price label").matches(buildMatch("Price").toRegex())
+ assertThat(messages[2].msg, "previous label").matches(buildMatch("Previous").toRegex())
+ assertThat(messages[3].msg, "open label").matches(buildMatch("Open").toRegex())
+
+ assertThat(getQuote("blahfoo", apiKey).first(), "invalid symbol").all {
+ isInstanceOf(ErrorMessage::class.java)
+ prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL)
}
- assertThatThrownBy { getQuote("test", "") }.describedAs("no API key")
- .isInstanceOf(ModuleException::class.java).hasNoCause()
- assertThatThrownBy { getQuote("", "apikey") }.describedAs("no symbol")
- .isInstanceOf(ModuleException::class.java).hasNoCause()
+ assertThat(getQuote("", "apikey").first(), "empty symbol").all {
+ isInstanceOf(ErrorMessage::class.java)
+ prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL)
+ }
+ assertThat { getQuote("test", "") }.isFailure().isInstanceOf(ModuleException::class.java).hasNoCause()
} catch (e: ModuleException) {
// Avoid displaying api keys in CI logs
if ("true" == System.getenv("CI")) {
- throw sanitizeException(e, apiKey)
+ throw e.sanitize(apiKey)
} else {
throw e
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt
index 2257ac4..379e15a 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/TwitterTest.kt
@@ -31,9 +31,11 @@
*/
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.twitterPost
-import org.assertj.core.api.Assertions.assertThat
import org.testng.annotations.Test
import java.net.InetAddress
import java.net.UnknownHostException
@@ -56,7 +58,7 @@ class TwitterTest : LocalProperties() {
@Throws(ModuleException::class)
fun testPostTwitter() {
val msg = "Testing Twitter API from $ci"
- assertThat(
+ assertThat {
twitterPost(
getProperty(Twitter.CONSUMER_KEY_PROP),
getProperty(Twitter.CONSUMER_SECRET_PROP),
@@ -65,7 +67,7 @@ class TwitterTest : LocalProperties() {
getProperty(Twitter.HANDLE_PROP),
msg,
true
- ).msg
- ).describedAs("twitterPost($msg)").isEqualTo(msg)
+ )
+ }.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 1c503ca..a96e007 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,16 @@
*/
package net.thauvin.erik.mobibot.modules
+import assertk.all
+import assertk.assertThat
+import assertk.assertions.contains
+import assertk.assertions.endsWith
+import assertk.assertions.hasNoCause
+import assertk.assertions.isEqualTo
+import assertk.assertions.isFailure
+import assertk.assertions.isInstanceOf
+import assertk.assertions.isNotNull
+import assertk.assertions.isTrue
import net.aksingh.owmjapis.api.APIException
import net.aksingh.owmjapis.core.OWM
import net.thauvin.erik.mobibot.LocalProperties
@@ -39,8 +49,6 @@ import net.thauvin.erik.mobibot.modules.Weather2.Companion.ftoC
import net.thauvin.erik.mobibot.modules.Weather2.Companion.getCountry
import net.thauvin.erik.mobibot.modules.Weather2.Companion.getWeather
import net.thauvin.erik.mobibot.modules.Weather2.Companion.mphToKmh
-import org.assertj.core.api.Assertions.assertThat
-import org.assertj.core.api.Assertions.assertThatThrownBy
import org.testng.annotations.Test
import kotlin.random.Random
@@ -51,50 +59,63 @@ class Weather2Test : LocalProperties() {
@Test
fun testFtoC() {
val t = ftoC(32.0)
- assertThat(t.second).describedAs("32 °F is 0 °C").isEqualTo(0)
+ assertThat(t.second, "32 °F is 0 °C").isEqualTo(0)
}
@Test
fun testGetCountry() {
- assertThat(getCountry("foo")).describedAs("not a country").isEqualTo(OWM.Country.UNITED_STATES)
- assertThat(getCountry("fr")).describedAs("fr is france").isEqualTo(OWM.Country.FRANCE)
+ assertThat(getCountry("foo"), "not a country").isEqualTo(OWM.Country.UNITED_STATES)
+ assertThat(getCountry("fr"), "fr is france").isEqualTo(OWM.Country.FRANCE)
val country = OWM.Country.values()
repeat(3) {
val rand = country[Random.nextInt(0, country.size - 1)]
- assertThat(getCountry(rand.value)).describedAs(rand.name).isEqualTo(rand)
+ assertThat(getCountry(rand.value), rand.name).isEqualTo(rand)
}
}
@Test
fun testMphToKmh() {
val w = mphToKmh(0.62)
- assertThat(w.second).describedAs("0.62 mph is 1 km/h").isEqualTo(1)
+ assertThat(w.second, "0.62 mph is 1 km/h").isEqualTo(1)
}
@Test
@Throws(ModuleException::class)
fun testWeather() {
var messages = getWeather("98204", getProperty(OWM_API_KEY_PROP))
- assertThat(messages[0].msg).describedAs("is Everett").contains("Everett, United States").contains("US")
- assertThat(messages[messages.size - 1].msg).describedAs("is Everett zip code").endsWith("98204%2CUS")
+ assertThat(messages[0].msg, "is Everett").all {
+ contains("Everett, United States")
+ contains("US")
+ }
+ assertThat(messages[messages.size - 1].msg, "is Everett zip code").endsWith("98204%2CUS")
messages = getWeather("San Francisco", getProperty(OWM_API_KEY_PROP))
- assertThat(messages[0].msg).describedAs("is San Francisco").contains("San Francisco").contains("US")
- assertThat(messages[messages.size - 1].msg).describedAs("is San Fran city code").endsWith("5391959")
+ assertThat(messages[0].msg, "is San Francisco").all {
+ contains("San Francisco")
+ contains("US")
+ }
+ assertThat(messages[messages.size - 1].msg, "is San Fran city code").endsWith("5391959")
messages = getWeather("London, GB", getProperty(OWM_API_KEY_PROP))
- assertThat(messages[0].msg).describedAs("is UK").contains("London, United Kingdom").contains("GB")
- assertThat(messages[messages.size - 1].msg).describedAs("is London city code").endsWith("2643743")
+ assertThat(messages[0].msg, "is UK").all {
+ contains("London, United Kingdom")
+ contains("GB")
+ }
+ assertThat(messages[messages.size - 1].msg, "is London city code").endsWith("2643743")
- assertThatThrownBy { getWeather("Foo, US", getProperty(OWM_API_KEY_PROP)) }
- .describedAs("foo not found").hasCauseInstanceOf(APIException::class.java)
- assertThatThrownBy { getWeather("test", "") }
- .describedAs("no API key").isInstanceOf(ModuleException::class.java).hasNoCause()
- assertThatThrownBy { getWeather("test", null) }
- .describedAs("null API key").isInstanceOf(ModuleException::class.java).hasNoCause()
+ try {
+ getWeather("Foo, US", getProperty(OWM_API_KEY_PROP))
+ } catch (e: ModuleException) {
+ assertThat(e.cause, "cause is API exception").isNotNull().isInstanceOf(APIException::class.java)
+ }
+
+ assertThat { getWeather("test", "") }.isFailure()
+ .isInstanceOf(ModuleException::class.java).hasNoCause()
+ assertThat { getWeather("test", null) }.isFailure()
+ .isInstanceOf(ModuleException::class.java).hasNoCause()
messages = getWeather("", "apikey")
- assertThat(messages[0].isError).describedAs("no query").isTrue
+ assertThat(messages[0].isError, "no query").isTrue()
}
}
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 49e63c1..ddc6e8f 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt
@@ -31,14 +31,18 @@
*/
package net.thauvin.erik.mobibot.modules
+import assertk.assertThat
+import assertk.assertions.endsWith
+import assertk.assertions.isSuccess
+import assertk.assertions.matches
+import assertk.assertions.startsWith
import net.thauvin.erik.mobibot.Utils.bold
import net.thauvin.erik.mobibot.modules.WorldTime.Companion.BEATS_KEYWORD
import net.thauvin.erik.mobibot.modules.WorldTime.Companion.COUNTRIES_MAP
import net.thauvin.erik.mobibot.modules.WorldTime.Companion.time
-import org.assertj.core.api.Assertions.assertThat
+import org.pircbotx.Colors
import org.testng.annotations.Test
import java.time.ZoneId
-import java.time.zone.ZoneRulesException
/**
* The `WordTimeTest` class.
@@ -46,16 +50,23 @@ import java.time.zone.ZoneRulesException
class WordTimeTest {
@Test
fun testTime() {
- assertThat(time("PST").msg).describedAs("PST").endsWith(bold("Los Angeles"))
- assertThat(time("BLAH").isError).describedAs("BLAH").isTrue
- assertThat(time("BEAT").msg).describedAs(BEATS_KEYWORD).matches("[\\w ]+: .?@\\d{3}+.? .beats")
+ assertThat(time(), "no zone").matches(
+ ("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " +
+ "on ${Colors.BOLD}\\w+, \\d{1,2} \\w+ \\d{4}${Colors.BOLD} " +
+ "in ${Colors.BOLD}Los Angeles${Colors.BOLD}").toRegex()
+ )
+ assertThat(time(""), "empty zone").endsWith(bold("Los Angeles"))
+ assertThat(time("PST"), "PST").endsWith(bold("Los Angeles"))
+ assertThat(time("GB"), "GB").endsWith(bold("London"))
+ assertThat(time("FR"), "FR").endsWith(bold("Paris"))
+ assertThat(time("BLAH"), "BLAH").startsWith("Unsupported")
+ assertThat(time("BEAT"), BEATS_KEYWORD).matches("[\\w ]+ .?@\\d{3}+.? .beats".toRegex())
}
@Test
- @Throws(ZoneRulesException::class)
- fun testCountries() {
+ fun testZones() {
COUNTRIES_MAP.filter { it.value != BEATS_KEYWORD }.forEach {
- ZoneId.of(it.value)
+ assertThat { ZoneId.of(it.value) }.isSuccess()
}
}
}
diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/msg/TestMessage.kt b/src/test/kotlin/net/thauvin/erik/mobibot/msg/TestMessage.kt
index 6ab62c9..94a2de0 100644
--- a/src/test/kotlin/net/thauvin/erik/mobibot/msg/TestMessage.kt
+++ b/src/test/kotlin/net/thauvin/erik/mobibot/msg/TestMessage.kt
@@ -32,7 +32,8 @@
package net.thauvin.erik.mobibot.msg
-import org.assertj.core.api.Assertions.assertThat
+import assertk.assertThat
+import assertk.assertions.isTrue
import org.testng.annotations.Test
class TestMessage {
@@ -41,15 +42,15 @@ class TestMessage {
var msg = Message()
msg.isError = true
- assertThat(msg.isNotice).describedAs("message is notice").isTrue
+ assertThat(msg.isNotice, "message is notice").isTrue()
msg = Message("foo", isError = true)
- assertThat(msg.isNotice).describedAs("message is notice too").isTrue
+ assertThat(msg.isNotice, "message is notice too").isTrue()
}
@Test
fun testErrorMessage() {
val msg = ErrorMessage("foo")
- assertThat(msg.isNotice).describedAs("error message is notice").isTrue
+ assertThat(msg.isNotice, "error message is notice").isTrue()
}
}
diff --git a/src/test/resources/current.xml b/src/test/resources/current.xml
new file mode 100644
index 0000000..8552a9a
--- /dev/null
+++ b/src/test/resources/current.xml
@@ -0,0 +1,36 @@
+
+
+
+ #mobibot IRC Links
+ https://www.mobitopia.org/mobibot/logs
+ Links from irc.example.com on #mobibot
+ en
+ Sun, 31 Oct 2021 21:45:11 GMT
+ 2021-10-31T21:45:11Z
+ en
+ -
+ Example 2
+ https://www.example.com/2
+ Posted by <b>Skynx</b> on <a href="irc://irc.libera.chat/#mobibot"><b>#mobibot</b></a>
+ tag2-1
+ tag2-2
+ Sun, 31 Oct 2021 21:45:11 GMT
+ https://www.foo.com
+ mobibot@irc.libera.chat (Skynx)
+ 2021-10-31T00:01:00Z
+
+ -
+ Example 1
+ https://www.example.com/1
+ Posted by <b>ErikT</b> on <a href="irc://irc.libera.chat/#mobibot"><b>#mobibot</b></a>
+ <br/><br/>ErikT: This is comment 1. <br/>Skynx: This is comment 2.
+
+ tag1-1
+ tag1-2
+ Sun, 31 Oct 2021 21:43:15 GMT
+ https://www.example.com/
+ mobibot@irc.libera.chat (ErikT)
+ 2021-10-31T00:00:00Z
+
+
+
diff --git a/version.properties b/version.properties
index 772b346..f5f7c7c 100644
--- a/version.properties
+++ b/version.properties
@@ -1,9 +1,9 @@
#Generated by the Semver Plugin for Gradle
-#Wed Sep 15 17:27:25 PDT 2021
-version.buildmeta=1400
+#Mon Nov 08 13:50:12 PST 2021
+version.buildmeta=2220
version.major=0
version.minor=8
version.patch=0
version.prerelease=beta
version.project=mobibot
-version.semver=0.8.0-beta+1400
+version.semver=0.8.0-beta+2220