diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 19b4dbd..d0fbcc9 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -54,7 +54,7 @@ NestedBlockDepth:EntryLink.kt$EntryLink$private fun setTags(tags: List<String?>) NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic @Throws(IOException::class, FeedException::class) fun loadFeed(entries: Entries, currentFile: String = currentXml): String NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = currentXml) - NestedBlockDepth:GoogleSearch.kt$GoogleSearch$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) + NestedBlockDepth:GoogleSearch.kt$GoogleSearch$override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) NestedBlockDepth:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message> NestedBlockDepth:LinksManager.kt$LinksManager$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) @@ -66,7 +66,7 @@ NestedBlockDepth:TwitterOAuth.kt$TwitterOAuth$@JvmStatic fun main(args: Array<String>) NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadData(file: String, default: Any, logger: Logger, description: String): Any NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveData(file: String, data: Any, logger: Logger, description: String) - NestedBlockDepth:Weather2.kt$Weather2$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) + NestedBlockDepth:Weather2.kt$Weather2$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> PrintStackTrace:TwitterOAuth.kt$TwitterOAuth$ioe PrintStackTrace:TwitterOAuth.kt$TwitterOAuth$te @@ -86,7 +86,6 @@ ThrowsCount:WolframAlpha.kt$WolframAlpha.Companion$@JvmStatic @Throws(ModuleException::class) fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException - TooManyFunctions:EntryLink.kt$EntryLink : Serializable TooManyFunctions:Mobibot.kt$Mobibot : ListenerAdapter TooManyFunctions:Tell.kt$Tell : AbstractCommand diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt index 8720e95..db5fb25 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt @@ -46,8 +46,8 @@ import java.util.Properties */ class Addons(private val props: Properties) { private val logger: Logger = LoggerFactory.getLogger(Addons::class.java) - private val disabledModules = props.getProperty("disabled-modules", "").split(LinksManager.TAG_MATCH) - private val disableCommands = props.getProperty("disabled-commands", "").split(LinksManager.TAG_MATCH) + private val disabledModules = props.getProperty("disabled-modules", "").split(LinksManager.TAG_MATCH.toRegex()) + private val disableCommands = props.getProperty("disabled-commands", "").split(LinksManager.TAG_MATCH.toRegex()) val commands: MutableList = mutableListOf() val modules: MutableList = mutableListOf() diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt index fc43dbc..eb00137 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt @@ -65,7 +65,7 @@ class FeedReader(private val url: String, val event: GenericMessageEvent) : Runn 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 IO error has occurred while fetching the feed: ${e.message}") + event.sendMessage("An error has occurred while fetching the feed: ${e.message}") } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index fcd2d08..bae8403 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -176,7 +176,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro override fun onDisconnect(event: DisconnectEvent?) { event?.let { with(event.getBot()) { - LinksManager.socialManager.notification("$nick disconnected from $serverHostname") + LinksManager.socialManager.notification("$nick disconnected from irc://$serverHostname") seen.add(userChannelDao.getChannel(channel).users) } } @@ -202,7 +202,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro with(event.getBot()) { if (user.nick == nick) { LinksManager.socialManager.notification( - "$nick has joined ${event.channel.name} on $serverHostname" + "$nick has joined ${event.channel.name} on irc://$serverHostname" ) seen.add(userChannelDao.getChannel(channel).users) } else { @@ -215,10 +215,12 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro override fun onMessage(event: MessageEvent?) { event?.user?.let { user -> + val sender = user.nick + val message = event.message tell.send(event) - if (event.message.matches("(?i)${Pattern.quote(event.bot().nick)}:.*".toRegex())) { // mobibot: - if (logger.isTraceEnabled) logger.trace(">>> ${user.nick}: ${event.message}") - val cmds = event.message.substring(event.bot().nick.length + 1).trim().split(" ".toRegex(), 2) + 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 = cmds.lastOrEmpty().trim() if (cmd.startsWith(Constants.HELP_CMD)) { // mobibot: help @@ -228,10 +230,10 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro addons.exec(channel, cmd, args, event) } } else if (addons.match(channel, event)) { // Links, e.g.: https://www.example.com/ or L1: , etc. - if (logger.isTraceEnabled) logger.trace(">>> ${user.nick}: ${event.message}") + if (logger.isTraceEnabled) logger.trace(">>> $sender: $message") } - storeRecap(user.nick, event.message, false) - seen.add(user.nick) + storeRecap(sender, message, false) + seen.add(sender) } } @@ -250,7 +252,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro with(event.getBot()) { if (user.nick == nick) { LinksManager.socialManager.notification( - "$nick has left ${event.channel.name} on $serverHostname" + "$nick has left ${event.channel.name} on irc://$serverHostname" ) seen.add(userChannelDao.getChannel(channel).users) } else { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt index 1bc719b..9d46188 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt @@ -32,6 +32,8 @@ package net.thauvin.erik.mobibot +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import net.thauvin.erik.mobibot.entries.EntryLink import net.thauvin.erik.pinboard.PinboardPoster import java.time.ZoneId @@ -51,8 +53,16 @@ class Pinboard { */ fun addPin(ircServer: String, entry: EntryLink) { if (poster.apiToken.isNotBlank()) { - with(entry) { - poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp()) + runBlocking { + launch { + poster.addPin( + entry.link, + entry.title, + entry.postedBy(ircServer), + entry.pinboardTags, + entry.date.toTimestamp() + ) + } } } } @@ -69,9 +79,12 @@ class Pinboard { */ fun deletePin(entry: EntryLink) { if (poster.apiToken.isNotBlank()) { - poster.deletePin(entry.link) + runBlocking { + launch { + poster.deletePin(entry.link) + } + } } - } /** @@ -79,31 +92,29 @@ class Pinboard { */ fun updatePin(ircServer: String, oldUrl: String, entry: EntryLink) { if (poster.apiToken.isNotBlank()) { - with(entry) { - if (oldUrl != link) { - poster.deletePin(oldUrl) + runBlocking { + launch { + with(entry) { + if (oldUrl != link) { + poster.deletePin(oldUrl) + } + poster.addPin(link, title, entry.postedBy(ircServer), pinboardTags, date.toTimestamp()) + } } - poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp()) } } } /** - * Formats a date to a UTC timestamp. + * Format a date to a UTC timestamp. */ private fun Date.toTimestamp(): String { return ZonedDateTime.ofInstant( - toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault() + toInstant().truncatedTo(ChronoUnit.SECONDS), + ZoneId.systemDefault() ).format(DateTimeFormatter.ISO_INSTANT) } - /** - * Formats the tags for pinboard. - */ - private fun EntryLink.formatTags(): String { - return nick + formatTags(",", ",") - } - /** * Returns the pinboard.in extended attribution line. */ 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 8412af0..3cc1b1a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt @@ -32,6 +32,8 @@ 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.Utils.helpFormat import org.pircbotx.hooks.types.GenericMessageEvent @@ -53,7 +55,11 @@ class ChannelFeed(channel: String) : AbstractCommand() { override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { if (isEnabled()) { - properties[FEED_PROP]?.let { FeedReader(it, event).run() } + runBlocking { + launch { + properties[FEED_PROP]?.let { FeedReader(it, event).run() } + } + } } } 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 31a9c65..20a49d2 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt @@ -33,7 +33,6 @@ package net.thauvin.erik.mobibot.commands import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import net.thauvin.erik.mobibot.Utils.bot import net.thauvin.erik.mobibot.Utils.helpFormat @@ -52,12 +51,10 @@ class Cycle : AbstractCommand() { with(event.bot()) { if (event.isChannelOp(channel)) { runBlocking { - launch { - 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) - } + 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 { helpResponse(channel, args, event) 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 f47f057..7306cea 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt @@ -141,7 +141,7 @@ class Ignore : AbstractCommand() { override fun setProperty(key: String, value: String) { super.setProperty(key, value) if (IGNORE_PROP == key) { - ignored.addAll(value.split(LinksManager.TAG_MATCH)) + ignored.addAll(value.split(LinksManager.TAG_MATCH.toRegex())) } } 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 66c4ebf..fddb9be 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt @@ -45,7 +45,15 @@ class Users : AbstractCommand() { override val isVisible = true override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { + val nicks = mutableListOf() val ch = event.bot().userChannelDao.getChannel(channel) - event.sendList(ch.users.map { if (it.channelsOpIn.contains(ch)) "@${it.nick}" else it.nick }, 8) + ch.users.forEach { + if (it.channelsOpIn.contains(ch)) { + nicks.add("@${it.nick}") + } else { + nicks.add(it.nick) + } + } + event.sendList(nicks, 8) } } 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 5a09836..e60955a 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 @@ -38,7 +38,7 @@ 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.printComment +import net.thauvin.erik.mobibot.entries.EntriesUtils.buildComment import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel import net.thauvin.erik.mobibot.entries.EntryLink import org.pircbotx.hooks.types.GenericMessageEvent @@ -111,7 +111,7 @@ class Comment : AbstractCommand() { if (event.isChannelOp(channel) && cmd.length > 1) { val comment = entry.getComment(commentIndex) comment.nick = cmd.substring(1) - event.sendMessage(printComment(entryIndex, commentIndex, comment)) + event.sendMessage(buildComment(entryIndex, commentIndex, comment)) LinksManager.entries.save() } else { event.sendMessage("Please ask a channel op to change the author of this comment for you.") @@ -142,11 +142,11 @@ class Comment : AbstractCommand() { event: GenericMessageEvent ) { entry.setComment(commentIndex, cmd, event.user.nick) - event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) + event.sendMessage(buildComment(entryIndex, commentIndex, entry.getComment(commentIndex))) LinksManager.entries.save() } private fun showComment(entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent) { - event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) + event.sendMessage(buildComment(entryIndex, commentIndex, entry.getComment(commentIndex))) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt index af6adf4..d0c9769 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt @@ -42,7 +42,7 @@ import net.thauvin.erik.mobibot.Utils.today import net.thauvin.erik.mobibot.commands.AbstractCommand import net.thauvin.erik.mobibot.commands.Ignore.Companion.isNotIgnored import net.thauvin.erik.mobibot.entries.Entries -import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink +import net.thauvin.erik.mobibot.entries.EntriesUtils.buildLink import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel import net.thauvin.erik.mobibot.entries.EntryLink import net.thauvin.erik.mobibot.social.SocialManager @@ -65,10 +65,10 @@ class LinksManager : AbstractCommand() { } companion object { - val LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*".toRegex() + const val LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*" const val KEYWORDS_PROP = "tags-keywords" const val TAGS_PROP = "tags" - val TAG_MATCH = ", *| +".toRegex() + const val TAG_MATCH = ", *| +" /** * Entries array @@ -116,7 +116,7 @@ class LinksManager : AbstractCommand() { val data = cmds[1].trim().split("${Tags.COMMAND}:", limit = 2) title = data[0].trim() if (data.size > 1) { - tags.addAll(data[1].split(TAG_MATCH)) + tags.addAll(data[1].split(TAG_MATCH.toRegex())) } } @@ -136,7 +136,7 @@ class LinksManager : AbstractCommand() { val entry = EntryLink(link, title, sender, login, channel, tags) entries.links.add(entry) val index = entries.links.lastIndexOf(entry) - event.sendMessage(printLink(index, entry)) + event.sendMessage(buildLink(index, entry)) pinboard.addPin(event.bot().serverHostname, entry) @@ -156,7 +156,7 @@ class LinksManager : AbstractCommand() { override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean = false override fun matches(message: String): Boolean { - return message.matches(LINK_MATCH) + return message.matches(LINK_MATCH.toRegex()) } internal fun fetchTitle(link: String): String { @@ -179,7 +179,7 @@ class LinksManager : AbstractCommand() { return try { val match = entries.links.single { it.link == link } event.sendMessage( - "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match) + "Duplicate".bold() + " >> " + buildLink(entries.links.indexOf(match), match) ) true } catch (ignore: NoSuchElementException) { @@ -200,9 +200,9 @@ class LinksManager : AbstractCommand() { override fun setProperty(key: String, value: String) { super.setProperty(key, value) if (KEYWORDS_PROP == key) { - keywords.addAll(value.split(TAG_MATCH)) + keywords.addAll(value.split(TAG_MATCH.toRegex())) } else if (TAGS_PROP == key) { - defaultTags.addAll(value.split(TAG_MATCH)) + defaultTags.addAll(value.split(TAG_MATCH.toRegex())) } } } 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 9368d37..a0224b9 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 @@ -94,7 +94,7 @@ class Posting : AbstractCommand() { val entry: EntryLink = entries.links[entryIndex] val commentIndex = entry.addComment(cmd, event.user.nick) val comment = entry.getComment(commentIndex) - event.sendMessage(EntriesUtils.printComment(entryIndex, commentIndex, comment)) + event.sendMessage(EntriesUtils.buildComment(entryIndex, commentIndex, comment)) entries.save() } @@ -103,7 +103,7 @@ class Posting : AbstractCommand() { val entry: EntryLink = entries.links[entryIndex] entry.title = cmd.substring(1).trim() LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) - event.sendMessage(EntriesUtils.printLink(entryIndex, entry)) + event.sendMessage(EntriesUtils.buildLink(entryIndex, entry)) entries.save() } } @@ -112,11 +112,11 @@ class Posting : AbstractCommand() { val entry: EntryLink = entries.links[entryIndex] if (entry.login == event.user.login || event.isChannelOp(channel)) { val link = cmd.substring(1) - if (link.matches(LinksManager.LINK_MATCH)) { + if (link.matches(LinksManager.LINK_MATCH.toRegex())) { val oldLink = entry.link entry.link = link LinksManager.pinboard.updatePin(event.bot().serverHostname, oldLink, entry) - event.sendMessage(EntriesUtils.printLink(entryIndex, entry)) + event.sendMessage(EntriesUtils.buildLink(entryIndex, entry)) entries.save() } } @@ -128,7 +128,7 @@ class Posting : AbstractCommand() { val entry: EntryLink = entries.links[index] entry.nick = cmd.substring(1) LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) - event.sendMessage(EntriesUtils.printLink(index, entry)) + event.sendMessage(EntriesUtils.buildLink(index, entry)) entries.save() } } else { @@ -151,14 +151,14 @@ class Posting : AbstractCommand() { private fun showEntry(index: Int, event: GenericMessageEvent) { val entry: EntryLink = entries.links[index] - event.sendMessage(EntriesUtils.printLink(index, entry)) + event.sendMessage(EntriesUtils.buildLink(index, entry)) if (entry.tags.isNotEmpty()) { - event.sendMessage(EntriesUtils.printTags(index, entry)) + event.sendMessage(EntriesUtils.buildTags(index, entry)) } if (entry.comments.isNotEmpty()) { val comments = entry.comments for (i in comments.indices) { - event.sendMessage(EntriesUtils.printComment(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 785e3a0..8146e88 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 @@ -67,14 +67,14 @@ class Tags : AbstractCommand() { if (entry.login == event.user.login || event.isChannelOp(channel)) { entry.setTags(cmd) LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) - event.sendMessage(EntriesUtils.printTags(index, entry)) + event.sendMessage(EntriesUtils.buildTags(index, entry)) LinksManager.entries.save() } else { event.sendMessage("Please ask a channel op to change the tags for you.") } } else { if (entry.tags.isNotEmpty()) { - event.sendMessage(EntriesUtils.printTags(index, entry)) + event.sendMessage(EntriesUtils.buildTags(index, entry)) } else { 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 008ccad..ee817a0 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 @@ -97,11 +97,11 @@ class View : AbstractCommand() { entry = entries.links[index] if (query.isNotBlank()) { if (entry.matches(query)) { - event.sendMessage(EntriesUtils.printLink(index, entry, true)) + event.sendMessage(EntriesUtils.buildLink(index, entry, true)) sent++ } } else { - event.sendMessage(EntriesUtils.printLink(index, entry, true)) + event.sendMessage(EntriesUtils.buildLink(index, entry, true)) sent++ } index++ 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 7d8aaed..a504c92 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 @@ -37,7 +37,7 @@ import java.time.LocalDateTime import java.time.format.DateTimeFormatter /** - * Tell Message. + * The `TellMessage` class. */ class TellMessage( /** 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 ac2c259..2b96dac 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt @@ -40,18 +40,18 @@ import net.thauvin.erik.mobibot.Utils.green */ object EntriesUtils { /** - * Prints an entry's comment for display on the channel. + * Builds an entry's comment for display on the channel. */ @JvmStatic - fun printComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String = + fun buildComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String = ("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}") /** - * Prints an entry's link for display on the channel. + * Builds an entry's link for display on the channel. */ @JvmStatic @JvmOverloads - fun printLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String { + fun buildLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String { val buff = StringBuilder().append(entryIndex.toLinkLabel()).append(": ") .append('[').append(entry.nick).append(']') if (isView && entry.comments.isNotEmpty()) { @@ -70,14 +70,14 @@ object EntriesUtils { } /** - * Prints an entry's tags/categories for display on the channel. e.g. L1T: tag1, tag2 + * Build an entry's tags/categories for display on the channel. */ @JvmStatic - fun printTags(entryIndex: Int, entry: EntryLink): String = - entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ") + fun buildTags(entryIndex: Int, entry: EntryLink): String = + entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.pinboardTags.replace(",", ", ") /** - * Builds link label based on its index. e.g: L1 + * Build link label based on its index. e.g: L1 */ @JvmStatic fun Int.toLinkLabel(): String = Constants.LINK_CMD + (this + 1) 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 59f4e73..b70fa9d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -127,18 +127,24 @@ class EntryLink( return comments.remove(entryComment) } - /** - * Formats the tags. - */ - fun formatTags(sep: String, prefix: String = "") : String { - return tags.joinToString(separator = sep, prefix = prefix){it.name} - } - /** * Returns a comment. */ fun getComment(index: Int): EntryComment = comments[index] + /** + * Returns the tags formatted for pinboard.in + */ + val pinboardTags: String + get() { + val pinboardTags = StringBuilder(nick) + for (tag in tags) { + pinboardTags.append(',') + pinboardTags.append(tag.name) + } + return pinboardTags.toString() + } + /** * Returns true if a string is contained in the link, title, or nick. */ diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt index 1ae2690..32ba16d 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt @@ -160,7 +160,7 @@ class FeedsManager private constructor() { item.description = SyndContentImpl().apply { value = buff.toString() } item.title = title item.publishedDate = date - item.author = "${channel.removePrefix("#")}@${entries.ircServer} ($nick)" + item.author = "${channel.substring(1)}@${entries.ircServer} ($nick)" item.categories = tags items.add(item) } 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 61e2eaf..83eafcf 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt @@ -113,7 +113,7 @@ abstract class AbstractModule { */ open val isValidProperties: Boolean get() { - for (s in properties.keys) { + for (s in propertyKeys) { if (properties[s].isNullOrBlank()) { return false } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index c464928..40021e3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -46,12 +46,12 @@ import java.net.http.HttpClient import java.net.http.HttpRequest import java.net.http.HttpResponse -class ChatGpt : AbstractModule() { +class ChatGpt : ThreadedModule() { private val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java) override val name = "ChatGPT" - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { event.sendMessage( 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 66a33ae..7f9e4b7 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt @@ -46,7 +46,7 @@ import java.io.IOException /** * The Cryptocurrency Prices module. */ -class CryptoPrices : AbstractModule() { +class CryptoPrices : ThreadedModule() { private val logger: Logger = LoggerFactory.getLogger(CryptoPrices::class.java) override val name = "CryptoPrices" @@ -55,7 +55,7 @@ class CryptoPrices : AbstractModule() { * Returns the cryptocurrency market price from * [Coinbase](https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-prices#get-spot-price). */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (CURRENCIES.isEmpty()) { try { loadCurrencies() 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 3d0bf0a..712aedf 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -52,7 +52,7 @@ import java.util.TreeMap /** * The CurrencyConverter module. */ -class CurrencyConverter : AbstractModule() { +class CurrencyConverter : ThreadedModule() { private val logger: Logger = LoggerFactory.getLogger(CurrencyConverter::class.java) override val name = "CurrencyConverter" @@ -71,7 +71,7 @@ class CurrencyConverter : AbstractModule() { /** * Converts the specified currencies. */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { reload() if (SYMBOLS.isEmpty()) { 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 76451db..7499ec8 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt @@ -54,7 +54,7 @@ import java.net.URL /** * The GoogleSearch module. */ -class GoogleSearch : AbstractModule() { +class GoogleSearch : ThreadedModule() { private val logger: Logger = LoggerFactory.getLogger(GoogleSearch::class.java) override val name = "GoogleSearch" @@ -62,7 +62,7 @@ class GoogleSearch : AbstractModule() { /** * Searches Google. */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { val results = searchGoogle( 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 202dc68..e85a914 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt @@ -31,6 +31,8 @@ */ package net.thauvin.erik.mobibot.modules +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import net.thauvin.erik.jokeapi.exceptions.HttpErrorException import net.thauvin.erik.jokeapi.exceptions.JokeException import net.thauvin.erik.jokeapi.getJoke @@ -50,15 +52,21 @@ import java.io.IOException /** * The Joke module. */ -class Joke : AbstractModule() { +class Joke : ThreadedModule() { private val logger: Logger = LoggerFactory.getLogger(Joke::class.java) override val name = "Joke" + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + runBlocking { + launch { run(channel, cmd, args, event) } + } + } + /** * Returns a random joke from [JokeAPI](https://v2.jokeapi.dev/). */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { with(event.bot()) { try { randomJoke().forEach { @@ -84,8 +92,12 @@ class Joke : AbstractModule() { @Throws(ModuleException::class) fun randomJoke(): List { return try { + val messages = mutableListOf() val joke = getJoke(safe = true, type = Type.SINGLE, splitNewLine = true) - joke.joke.map { PublicMessage(it, Colors.CYAN) } + joke.joke.forEach { + messages.add(PublicMessage(it, Colors.CYAN)) + } + messages } catch (e: JokeException) { throw ModuleException("randomJoke(): ${e.additionalInfo}", e.message, e) } catch (e: HttpErrorException) { diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt index ae805cd..858676e 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt @@ -52,21 +52,23 @@ class Mastodon : SocialModule() { get() = properties[HANDLE_PROP] override val isAutoPost: Boolean - get() = isEnabled && properties[AUTO_POST_PROP].toBoolean() + get() = isEnabled && properties[Twitter.AUTO_POST_PROP].toBoolean() override val isValidProperties: Boolean - get() = !(properties[INSTANCE_PROP].isNullOrBlank() || properties[ACCESS_TOKEN_PROP].isNullOrBlank()) + get() { + for (s in propertyKeys) { + if (AUTO_POST_PROP != s && HANDLE_PROP != s && properties[s].isNullOrBlank()) { + return false + } + } + return true + } /** * Formats the entry for posting. */ override fun formatEntry(entry: EntryLink): String { - return "${entry.title} (via ${entry.nick} on ${entry.channel})${formatTags(entry)}\n\n${entry.link}" - } - - private fun formatTags(entry: EntryLink): String { - return entry.tags.filter { !it.name.equals(entry.channel.removePrefix("#"), true) } - .joinToString(separator = " ", prefix = "\n\n") { "#${it.name}" } + return "${entry.title} via ${entry.nick} on ${entry.channel}\n\n${entry.link}" } /** @@ -93,7 +95,7 @@ class Mastodon : SocialModule() { private const val MASTODON_CMD = "mastodon" /** - * Post on Mastodon. + * Toots on Mastodon. */ @JvmStatic @Throws(ModuleException::class) 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 ffca08b..4c2859f 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt @@ -52,7 +52,7 @@ import java.net.URL /** * The StockQuote module. */ -class StockQuote : AbstractModule() { +class StockQuote : ThreadedModule() { private val logger: Logger = LoggerFactory.getLogger(StockQuote::class.java) override val name = "StockQuote" @@ -60,7 +60,7 @@ class StockQuote : AbstractModule() { /** * Returns the specified stock quote from Alpha Vantage. */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { val messages = getQuote(args, properties[ALPHAVANTAGE_API_KEY_PROP]) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ThreadedModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ThreadedModule.kt new file mode 100644 index 0000000..269b24d --- /dev/null +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ThreadedModule.kt @@ -0,0 +1,58 @@ +/* + * ThreadedModule.kt + * + * Copyright (c) 2004-2022, 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.modules + +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.pircbotx.hooks.types.GenericMessageEvent + +/** + * The `ThreadedModule` class. + */ +abstract class ThreadedModule : AbstractModule() { + override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + if (isEnabled && event.message.isNotEmpty()) { + runBlocking { + launch { + run(channel, cmd, args, event) + } + } + } else { + helpResponse(event) + } + } + + /** + * Runs the thread. + */ + 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 28f9cde..91cca2a 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Twitter.kt @@ -49,8 +49,14 @@ class Twitter : SocialModule() { get() = isEnabled && properties[AUTO_POST_PROP].toBoolean() override val isValidProperties: Boolean - get() = !(properties[CONSUMER_KEY_PROP].isNullOrBlank() || properties[CONSUMER_SECRET_PROP].isNullOrBlank() - || properties[TOKEN_PROP].isNullOrBlank() || properties[TOKEN_SECRET_PROP].isNullOrBlank()) + get() { + for (s in propertyKeys) { + if (AUTO_POST_PROP != s && HANDLE_PROP != s && properties[s].isNullOrBlank()) { + return false + } + } + return true + } /** * Formats the entry for posting. @@ -88,7 +94,7 @@ class Twitter : SocialModule() { private const val TWITTER_CMD = "twitter" /** - * Post on Twitter. + * Tweets on Twitter. */ @JvmStatic @Throws(ModuleException::class) 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 5c5ae67..8dcdc15 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -54,7 +54,7 @@ import kotlin.math.roundToInt /** * The `Weather2` module. */ -class Weather2 : AbstractModule() { +class Weather2 : ThreadedModule() { private val logger: Logger = LoggerFactory.getLogger(Weather2::class.java) override val name = "Weather" @@ -62,7 +62,7 @@ class Weather2 : AbstractModule() { /** * Fetches the weather data from a specific city. */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { val messages = getWeather(args, properties[OWM_API_KEY_PROP]) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt index 56d3a3d..1d5abd3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt @@ -43,7 +43,7 @@ import org.slf4j.LoggerFactory import java.io.IOException import java.net.URL -class WolframAlpha : AbstractModule() { +class WolframAlpha : ThreadedModule() { private val logger: Logger = LoggerFactory.getLogger(WolframAlpha::class.java) override val name = "WolframAlpha" @@ -56,7 +56,7 @@ class WolframAlpha : AbstractModule() { } } - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { if (args.isNotBlank()) { try { val query = args.trim().split("units=", limit = 2, ignoreCase = true) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt index f3a86fe..c991140 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt @@ -110,8 +110,8 @@ class SocialManager { */ fun shutdown() { timer.cancel() - entries.forEach { - postEntry(it) + for (index in entries) { + postEntry(index) } } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt index e31ccdc..c15dd55 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt @@ -32,16 +32,18 @@ package net.thauvin.erik.mobibot.social +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import net.thauvin.erik.mobibot.commands.links.LinksManager import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.modules.AbstractModule import net.thauvin.erik.mobibot.modules.ModuleException +import net.thauvin.erik.mobibot.modules.ThreadedModule import org.pircbotx.hooks.types.GenericMessageEvent import org.slf4j.Logger import org.slf4j.LoggerFactory -abstract class SocialModule : AbstractModule() { +abstract class SocialModule : ThreadedModule() { private val logger: Logger = LoggerFactory.getLogger(SocialManager::class.java) abstract val handle: String? @@ -54,11 +56,15 @@ abstract class SocialModule : AbstractModule() { */ fun notification(msg: String) { if (isEnabled && !handle.isNullOrBlank()) { - try { - post(message = msg, isDm = true) - if (logger.isDebugEnabled) logger.debug("Notified $handle on $name: $msg") - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn("Failed to notify $handle on $name: $msg", e) + runBlocking { + launch { + try { + post(message = msg, isDm = true) + if (logger.isDebugEnabled) logger.debug("Notified $handle on $name: $msg") + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn("Failed to notify $handle on $name: $msg", e) + } + } } } } @@ -70,21 +76,25 @@ abstract class SocialModule : AbstractModule() { */ fun postEntry(index: Int) { if (isAutoPost && LinksManager.entries.links.size >= index) { - try { - if (logger.isDebugEnabled) { - logger.debug("Posting {} to $name.", index.toLinkLabel()) + runBlocking { + launch { + try { + if (logger.isDebugEnabled) { + logger.debug("Posting {} to $name.", index.toLinkLabel()) + } + post(message = formatEntry(LinksManager.entries.links[index]), isDm = false) + } catch (e: ModuleException) { + if (logger.isWarnEnabled) logger.warn( + "Failed to post entry ${index.toLinkLabel()} on $name.", + e + ) + } } - post(message = formatEntry(LinksManager.entries.links[index]), isDm = false) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn( - "Failed to post entry ${index.toLinkLabel()} on $name.", - e - ) } } } - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { + override fun run(channel: String, cmd: String, args: String, event: GenericMessageEvent) { try { event.respond(post("$args (by ${event.user.nick} on $channel)", false)) } catch (e: ModuleException) { diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt index 23ba01e..0de9d5e 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt @@ -36,9 +36,9 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.isEqualTo import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.entries.EntriesUtils.printComment -import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink -import net.thauvin.erik.mobibot.entries.EntriesUtils.printTags +import net.thauvin.erik.mobibot.entries.EntriesUtils.buildComment +import net.thauvin.erik.mobibot.entries.EntriesUtils.buildLink +import net.thauvin.erik.mobibot.entries.EntriesUtils.buildTags import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel import org.testng.annotations.Test @@ -60,33 +60,33 @@ class EntriesUtilsTest { } @Test(groups = ["entries"]) - fun printCommentTest() { - assertThat(printComment(0, 0, comment)).isEqualTo("${Constants.LINK_CMD}1.1: [nick] comment") + fun buildLinkLabelTest() { + assertThat(1.toLinkLabel()).isEqualTo("${Constants.LINK_CMD}2") } @Test(groups = ["entries"]) - fun printLinkTest() { + fun buildCommentTest() { + assertThat(buildComment(0, 0, comment)).isEqualTo("${Constants.LINK_CMD}1.1: [nick] comment") + } + + @Test(groups = ["entries"]) + fun buildLinkTest() { for (i in links.indices) { assertThat( - printLink(i - 1, links[i]), "link $i" + buildLink(i - 1, links[i]), "link $i" ).isEqualTo("L$i: [Skynx$i] \u0002Mobitopia$i\u0002 ( \u000303https://www.mobitopia.org/$i\u000F )") } assertThat(links.first().addComment(comment), "addComment()").isEqualTo(0) - assertThat(printLink(0, links.first(), isView = true), "printLink(isView=true)").contains("[+1]") + assertThat(buildLink(0, links.first(), isView = true), "buildLink(isView=true)").contains("[+1]") } @Test(groups = ["entries"]) - fun printTagsTest() { + fun buildTagsTest() { for (i in links.indices) { assertThat( - printTags(i - 1, links[i]), "tag $i" - ).isEqualTo("L${i}T: tag1, tag2, tag3, tag4, tag5") + buildTags(i - 1, links[i]), "tag $i" + ).isEqualTo("L${i}T: Skynx$i, tag1, tag2, tag3, tag4, tag5") } } - - @Test(groups = ["entries"]) - fun toLinkLabelTest() { - assertThat(1.toLinkLabel()).isEqualTo("${Constants.LINK_CMD}2") - } } 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 8c1a862..5c9ef99 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -94,11 +94,13 @@ class EntryLinkTest { @Test(groups = ["entries"]) fun testConstructor() { - val tags = listOf(SyndCategoryImpl().apply { name = "tag1" }, SyndCategoryImpl().apply { name = "tag2" }) + val tag = "test" + val tags = listOf(SyndCategoryImpl().apply { name = tag }) val link = EntryLink("link", "title", "nick", "channel", Date(), tags) assertThat(link, "link").all { prop(EntryLink::tags).size().isEqualTo(tags.size) - prop(EntryLink::tags).index(0).prop(SyndCategory::getName).isEqualTo("tag1") + prop(EntryLink::tags).index(0).prop(SyndCategory::getName).isEqualTo(tag) + prop(EntryLink::pinboardTags).isEqualTo("nick,$tag") } } @@ -120,17 +122,11 @@ class EntryLinkTest { assertThat(tag.name, "tag.name($i)").isEqualTo("tag${i + 1}") } assertThat(entryLink::tags).size().isEqualTo(5) - entryLink.setTags("-tag5, tag4") + entryLink.setTags("-tag5") entryLink.setTags("+mobitopia") + entryLink.setTags("tag4") entryLink.setTags("-mobitopia") - assertThat( - entryLink.formatTags(","), - "formatTags(',')" - ).isEqualTo("tag1,tag2,tag3,tag4,mobitopia") - entryLink.setTags("-tag4 tag5") - assertThat( - entryLink.formatTags(" ", ","), "formatTag(' ',',')" - ).isEqualTo(",tag1 tag2 tag3 mobitopia tag5") + assertThat(entryLink::pinboardTags).isEqualTo(entryLink.nick + ",tag1,tag2,tag3,tag4,mobitopia") val size = entryLink.tags.size entryLink.setTags("") assertThat(entryLink.tags, "setTags('')").size().isEqualTo(size) diff --git a/version.properties b/version.properties index 4eb40f3..d91b88d 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Sat Dec 10 10:16:56 PST 2022 -version.buildmeta=874 +#Mon Dec 05 21:57:24 PST 2022 +version.buildmeta=814 version.major=0 version.minor=8 version.patch=0 version.prerelease=rc version.project=mobibot -version.semver=0.8.0-rc+874 +version.semver=0.8.0-rc+814