diff --git a/.gitignore b/.gitignore index fa550e5..6c5fc87 100644 --- a/.gitignore +++ b/.gitignore @@ -54,8 +54,9 @@ atlassian-ide-plugin.xml # Editor-based Rest Client .idea/httpRequests -local.properties - +bin deploy +local.properties logs mobibot.properties +out diff --git a/bin/main/log4j2.xml b/bin/main/log4j2.xml deleted file mode 100644 index 265c88f..0000000 --- a/bin/main/log4j2.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/main/net/thauvin/erik/mobibot/Addons.kt b/bin/main/net/thauvin/erik/mobibot/Addons.kt deleted file mode 100644 index 2c5f05d..0000000 --- a/bin/main/net/thauvin/erik/mobibot/Addons.kt +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Addons.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import net.thauvin.erik.mobibot.Utils.notContains -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.links.LinksManager -import net.thauvin.erik.mobibot.modules.AbstractModule -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.util.* - -/** - * Modules and Commands addons. - */ -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) - - val commands: MutableList = mutableListOf() - val modules: MutableList = mutableListOf() - val names = Names - - /** - * Add a module with properties. - */ - fun add(module: AbstractModule): Boolean { - var enabled = false - with(module) { - if (disabledModules.notContains(name, true)) { - if (hasProperties()) { - propertyKeys.forEach { - setProperty(it, props.getProperty(it, "")) - } - } - - if (isEnabled) { - modules.add(this) - names.modules.add(name) - names.commands.addAll(commands) - enabled = true - } else { - if (logger.isDebugEnabled) { - logger.debug("Module $name is disabled.") - } - names.disabledModules.add(name) - } - } else { - names.disabledModules.add(name) - } - } - return enabled - } - - /** - * Add a command with properties. - */ - fun add(command: AbstractCommand): Boolean { - var enabled = false - with(command) { - if (disableCommands.notContains(name, true)) { - if (properties.isNotEmpty()) { - properties.keys.forEach { - setProperty(it, props.getProperty(it, "")) - } - } - if (isEnabled()) { - commands.add(this) - if (isVisible) { - if (isOpOnly) { - names.ops.add(name) - } else { - names.commands.add(name) - } - } - enabled = true - } else { - if (logger.isDebugEnabled) { - logger.debug("Command $name is disabled.") - } - names.disabledCommands.add(name) - } - } else { - names.disabledCommands.add(name) - } - } - return enabled - } - - /** - * Execute a command or module. - */ - 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(channel, args, event) - return true - } - } - val mods = if (event is PrivateMessageEvent) modules.filter { it.isPrivateMsgEnabled } else modules - for (module in mods) { - if (module.commands.contains(cmd)) { - module.commandResponse(channel, cmd, args, event) - return true - } - } - return false - } - - /** - * Match a command. - */ - fun match(channel: String, event: GenericMessageEvent): Boolean { - for (command in commands) { - if (command.matches(event.message)) { - command.commandResponse(channel, event.message, event) - return true - } - } - return false - } - - /** - * Commands and Modules help. - */ - fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean { - for (command in commands) { - if (command.isVisible && command.name.startsWith(topic)) { - return command.helpResponse(channel, topic, event) - } - } - for (module in modules) { - if (module.commands.contains(topic)) { - return module.helpResponse(event) - } - } - return false - } - - /** - * Holds commands and modules names. - */ - object Names { - val modules: MutableList = mutableListOf() - val disabledModules: MutableList = mutableListOf() - val commands: MutableList = mutableListOf() - val disabledCommands: MutableList = mutableListOf() - val ops: MutableList = mutableListOf() - - fun sort() { - modules.sort() - disabledModules.sort() - commands.sort() - disabledCommands.sort() - ops.sort() - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/Constants.kt b/bin/main/net/thauvin/erik/mobibot/Constants.kt deleted file mode 100644 index 98ef74a..0000000 --- a/bin/main/net/thauvin/erik/mobibot/Constants.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Constants.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -/** - * The `Constants`. - */ -object Constants { - /** - * The connect/read timeout in ms. - */ - const val CONNECT_TIMEOUT = 5000 - - /** - * Debug command line argument. - */ - const val DEBUG_ARG = "debug" - - /** - * Default IRC Port. - */ - const val DEFAULT_PORT = 6667 - - /** - * Default IRC Server. - */ - const val DEFAULT_SERVER = "irc.libera.chat" - - /** - * CLI command for usage. - */ - const val CLI_CMD = "java -jar ${ReleaseInfo.PROJECT}.jar" - - /** - * User-Agent - */ - const val USER_AGENT = - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" - - /** - * The help command. - */ - const val HELP_CMD = "help" - - /** - * The link command. - */ - const val LINK_CMD = "L" - - /** - * The empty title string. - */ - const val NO_TITLE = "No Title" - - /** - * Properties command line argument. - */ - const val PROPS_ARG = "properties" - - /** - * The tag command - */ - const val TAG_CMD = "T" - - /** - * The timer delay in minutes. - */ - const val TIMER_DELAY = 10L - - /** - * Properties version line argument. - */ - const val VERSION_ARG = "version" -} diff --git a/bin/main/net/thauvin/erik/mobibot/FeedReader.kt b/bin/main/net/thauvin/erik/mobibot/FeedReader.kt deleted file mode 100644 index d82f011..0000000 --- a/bin/main/net/thauvin/erik/mobibot/FeedReader.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * FeedReader.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import com.rometools.rome.io.FeedException -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.FeedsManager -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 java.io.IOException -import java.net.URL - -/** - * Reads an RSS feed. - */ -class FeedReader(private val url: String, val event: GenericMessageEvent) : Runnable { - private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java) - - /** - * Fetches the Feed's items. - */ - override fun run() { - 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 IO error has occurred while fetching the feed: ${e.message}") - } - } - - companion object { - @JvmStatic - @Throws(FeedException::class, IOException::class) - fun readFeed(url: String, maxItems: Int = 5): List { - val messages = mutableListOf() - val input = SyndFeedInput() - XmlReader(URL(url).openStream()).use { reader -> - val feed = input.build(reader) - val items = feed.entries - if (items.isEmpty()) { - messages.add(NoticeMessage("There is currently nothing to view.")) - } else { - items.take(maxItems).forEach { - messages.add(NoticeMessage(it.title)) - messages.add(NoticeMessage(helpFormat(it.link.green(), false))) - } - } - } - return messages - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/Mobibot.kt b/bin/main/net/thauvin/erik/mobibot/Mobibot.kt deleted file mode 100644 index f91c457..0000000 --- a/bin/main/net/thauvin/erik/mobibot/Mobibot.kt +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Mobibot.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot - -import kotlinx.cli.ArgParser -import kotlinx.cli.ArgType -import kotlinx.cli.default -import net.thauvin.erik.mobibot.Utils.appendIfMissing -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.getIntProperty -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.lastOrEmpty -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.commands.* -import net.thauvin.erik.mobibot.commands.Recap.Companion.storeRecap -import net.thauvin.erik.mobibot.commands.links.* -import net.thauvin.erik.mobibot.commands.seen.Seen -import net.thauvin.erik.mobibot.commands.tell.Tell -import net.thauvin.erik.mobibot.modules.* -import net.thauvin.erik.semver.Version -import org.pircbotx.Configuration -import org.pircbotx.PircBotX -import org.pircbotx.hooks.ListenerAdapter -import org.pircbotx.hooks.events.* -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.* -import java.nio.file.Files -import java.nio.file.Paths -import java.util.* -import java.util.regex.Pattern -import kotlin.system.exitProcess - -@Version(properties = "version.properties", className = "ReleaseInfo", template = "version.mustache", type = "kt") -class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Properties) : ListenerAdapter() { - // The bot configuration. - private val config: Configuration - - // Commands and Modules - private val addons: Addons - - // Seen command - private val seen: Seen - - // Tell command - private val tell: Tell - - /** Logger. */ - val logger: Logger = LoggerFactory.getLogger(Mobibot::class.java) - - /** - * Connects to the server and joins the channel. - */ - fun connect() { - PircBotX(config).startBot() - } - - /** - * Responds with the default help. - */ - 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( - helpFormat( - helpCmdSyntax("%c ${Constants.HELP_CMD} ", event.bot().nick, event is PrivateMessageEvent) - ) - ) - event.sendMessage("The commands are:") - event.sendList(addons.names.commands, 8, isBold = true, isIndent = true) - if (event.isChannelOp(channel)) { - if (addons.names.disabledCommands.isNotEmpty()) { - event.sendMessage("The disabled commands are:") - event.sendList(addons.names.disabledCommands, 8, isBold = false, isIndent = true) - } - event.sendMessage("The op commands are:") - event.sendList(addons.names.ops, 8, isBold = true, isIndent = true) - } - } - - /** - * Responds with the default, commands or modules help. - */ - private fun helpResponse(event: GenericMessageEvent, topic: String) { - if (topic.isBlank() || !addons.help(channel, topic.lowercase().trim(), event)) { - helpDefault(event) - } - } - - override fun onAction(event: ActionEvent?) { - event?.channel?.let { - if (channel == it.name) { - event.user?.let { user -> - storeRecap(user.nick, event.action, true) - } - } - } - } - - override fun onDisconnect(event: DisconnectEvent?) { - event?.let { - with(event.getBot()) { - LinksManager.socialManager.notification("$nick disconnected from $serverHostname") - seen.add(userChannelDao.getChannel(channel).users) - } - } - LinksManager.socialManager.shutdown() - } - - override fun onPrivateMessage(event: PrivateMessageEvent?) { - event?.user?.let { user -> - if (logger.isTraceEnabled) logger.trace("<<< ${user.nick}: ${event.message}") - val cmds = event.message.trim().split(" ".toRegex(), 2) - val cmd = cmds[0].lowercase() - val args = cmds.lastOrEmpty().trim() - 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?) { - event?.user?.let { user -> - with(event.getBot()) { - if (user.nick == nick) { - LinksManager.socialManager.notification( - "$nick has joined ${event.channel.name} on $serverHostname" - ) - seen.add(userChannelDao.getChannel(channel).users) - } else { - tell.send(event) - seen.add(user.nick) - } - } - } - } - - override fun onMessage(event: MessageEvent?) { - event?.user?.let { user -> - 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) - val cmd = cmds[0].lowercase() - val args = cmds.lastOrEmpty().trim() - if (cmd.startsWith(Constants.HELP_CMD)) { // mobibot: help - helpResponse(event, args) - } else { - // Execute module or command - 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}") - } - storeRecap(user.nick, event.message, false) - seen.add(user.nick) - } - } - - override fun onNickChange(event: NickChangeEvent?) { - event?.let { - tell.send(event) - if (!it.oldNick.equals(it.newNick, true)) { - seen.add(it.oldNick) - } - seen.add(it.newNick) - } - } - - override fun onPart(event: PartEvent?) { - event?.user?.let { user -> - with(event.getBot()) { - if (user.nick == nick) { - LinksManager.socialManager.notification( - "$nick has left ${event.channel.name} on $serverHostname" - ) - seen.add(userChannelDao.getChannel(channel).users) - } else { - seen.add(user.nick) - } - } - } - } - - override fun onQuit(event: QuitEvent?) { - event?.user?.let { user -> - seen.add(user.nick) - } - } - - companion object { - @JvmStatic - @Throws(Exception::class) - fun main(args: Array) { - // Set up the command line options - val parser = ArgParser(Constants.CLI_CMD) - val debug by parser.option( - ArgType.Boolean, - Constants.DEBUG_ARG, - Constants.DEBUG_ARG.substring(0, 1), - "Print debug & logging data directly to the console" - ).default(false) - val property by parser.option( - ArgType.String, - Constants.PROPS_ARG, - Constants.PROPS_ARG.substring(0, 1), - "Use alternate properties file" - ).default("./${ReleaseInfo.PROJECT}.properties") - val version by parser.option( - ArgType.Boolean, - Constants.VERSION_ARG, - Constants.VERSION_ARG.substring(0, 1), - "Print version info" - ).default(false) - - // Parse the command line - parser.parse(args) - - if (version) { - // Output the version - println( - "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" + - " (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})" - ) - println(ReleaseInfo.WEBSITE) - } else { - // Load the properties - val p = Properties() - try { - Files.newInputStream( - Paths.get(property) - ).use { fis -> - p.load(fis) - } - } catch (ignore: FileNotFoundException) { - System.err.println("Unable to find properties file.") - exitProcess(1) - } catch (ignore: IOException) { - System.err.println("Unable to open properties file.") - exitProcess(1) - } - val nickname = p.getProperty("nick", Mobibot::class.java.name.lowercase()) - val channel = p.getProperty("channel") - val logsDir = p.getProperty("logs", ".").appendIfMissing(File.separatorChar) - - // Redirect stdout and stderr - if (!debug) { - try { - val stdout = PrintStream( - BufferedOutputStream( - FileOutputStream( - logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true - ) - ), true - ) - System.setOut(stdout) - } catch (ignore: IOException) { - System.err.println("Unable to open output (stdout) log file.") - exitProcess(1) - } - try { - val stderr = PrintStream( - BufferedOutputStream( - FileOutputStream("$logsDir$nickname.err", true) - ), true - ) - System.setErr(stderr) - } catch (ignore: IOException) { - System.err.println("Unable to open error (stderr) log file.") - exitProcess(1) - } - } - - // Start the bot - Mobibot(nickname, channel, logsDir, p).connect() - } - } - } - - /** - * Initialize the bot. - */ - init { - 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() - - // Load the current entries - with(LinksManager) { - entries.channel = channel - entries.ircServer = ircServer - entries.logsDir = logsDirPath - entries.backlogs = p.getProperty("backlogs", "") - entries.load() - - // Set up pinboard - pinboard.setApiToken(p.getProperty("pinboard-api-token", "")) - } - - addons = Addons(p) - - // Load the commands - addons.add(ChannelFeed(channel.removePrefix("#"))) - addons.add(Comment()) - addons.add(Cycle()) - addons.add(Die()) - addons.add(Ignore()) - addons.add(LinksManager()) - addons.add(Me()) - addons.add(Modules(addons.names.modules, addons.names.disabledModules)) - addons.add(Msg()) - addons.add(Nick()) - addons.add(Posting()) - addons.add(Recap()) - addons.add(Say()) - - // Seen command - seen = Seen("${logsDirPath}${nickname}-seen.ser") - addons.add(seen) - - addons.add(Tags()) - - // Tell command - tell = Tell("${logsDirPath}${nickname}.ser") - addons.add(tell) - - addons.add(Users()) - addons.add(Versions()) - addons.add(View()) - - // Load social modules - LinksManager.socialManager.add(addons, Mastodon()) - - // Load the modules - addons.add(Calc()) - addons.add(ChatGpt()) - addons.add(CryptoPrices()) - addons.add(CurrencyConverter()) - addons.add(Dice()) - addons.add(GoogleSearch()) - addons.add(Info(tell, seen)) - addons.add(Joke()) - addons.add(Lookup()) - addons.add(Ping()) - addons.add(RockPaperScissors()) - addons.add(StockQuote()) - addons.add(War()) - addons.add(Weather2()) - addons.add(WolframAlpha()) - addons.add(WorldTime()) - - // Sort the addons - addons.names.sort() - } -} - diff --git a/bin/main/net/thauvin/erik/mobibot/Pinboard.kt b/bin/main/net/thauvin/erik/mobibot/Pinboard.kt deleted file mode 100644 index 7cb5aed..0000000 --- a/bin/main/net/thauvin/erik/mobibot/Pinboard.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Pinboard.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot - -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.pinboard.PinboardPoster -import java.time.ZoneId -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.time.temporal.ChronoUnit -import java.util.* - -/** - * Handles posts to pinboard.in. - */ -class Pinboard { - private val poster = PinboardPoster() - - /** - * Adds a pin. - */ - fun addPin(ircServer: String, entry: EntryLink) { - if (poster.apiToken.isNotBlank()) { - with(entry) { - poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp()) - } - } - } - - /** - * Sets the pinboard API token. - */ - fun setApiToken(apiToken: String) { - poster.apiToken = apiToken - } - - /** - * Deletes a pin. - */ - fun deletePin(entry: EntryLink) { - if (poster.apiToken.isNotBlank()) { - poster.deletePin(entry.link) - } - - } - - /** - * Updates a pin. - */ - fun updatePin(ircServer: String, oldUrl: String, entry: EntryLink) { - if (poster.apiToken.isNotBlank()) { - with(entry) { - if (oldUrl != link) { - poster.deletePin(oldUrl) - } - poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp()) - } - } - } - - /** - * Formats a date to a UTC timestamp. - */ - private fun Date.toTimestamp(): String { - return ZonedDateTime.ofInstant( - 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. - */ - private fun EntryLink.postedBy(ircServer: String): String { - return "Posted by $nick on $channel ( $ircServer )" - } -} - diff --git a/bin/main/net/thauvin/erik/mobibot/Utils.kt b/bin/main/net/thauvin/erik/mobibot/Utils.kt deleted file mode 100644 index e4760d2..0000000 --- a/bin/main/net/thauvin/erik/mobibot/Utils.kt +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Utils.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR -import net.thauvin.erik.urlencoder.UrlEncoderUtil -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 org.slf4j.Logger -import java.io.* -import java.net.HttpURLConnection -import java.net.URL -import java.nio.file.Files -import java.nio.file.Paths -import java.time.LocalDateTime -import java.time.ZoneId -import java.time.format.DateTimeFormatter -import java.util.* -import kotlin.io.path.exists -import kotlin.io.path.fileSize - -/** - * Miscellaneous utilities. - */ -@Suppress("TooManyFunctions") -object Utils { - private val searchFlags = arrayOf("%c", "%n") - - /** - * Prepends a prefix if not present. - */ - @JvmStatic - fun String.prefixIfMissing(prefix: Char): String { - return if (first() != prefix) { - "$prefix${this}" - } else { - this - } - } - - /** - * Appends a suffix to the end of the String if not present. - */ - @JvmStatic - fun String.appendIfMissing(suffix: Char): String { - return if (last() != suffix) { - "$this${suffix}" - } else { - this - } - } - - /** - * Makes the given int bold. - */ - @JvmStatic - fun Int.bold(): String = toString().bold() - - /** - * Makes the given long bold. - */ - @JvmStatic - fun Long.bold(): String = toString().bold() - - /** - * Makes the given string bold. - */ - @JvmStatic - fun String?.bold(): String = colorize(Colors.BOLD) - - /** - * Returns the [PircBotX] instance. - */ - fun GenericMessageEvent.bot(): PircBotX { - return getBot() as PircBotX - } - - /** - * Capitalize a string. - */ - @JvmStatic - fun String.capitalise(): String = lowercase().replaceFirstChar { it.uppercase() } - - /** - * Capitalize words - */ - @JvmStatic - fun String.capitalizeWords(): String = split(" ").joinToString(" ") { it.capitalise() } - - /** - * Colorize a string. - */ - @JvmStatic - fun String?.colorize(color: String): String { - return when { - isNullOrEmpty() -> { - "" - } - - color == DEFAULT_COLOR -> { - this - } - - Colors.BOLD == color || Colors.REVERSE == color -> { - color + this + color - } - - else -> { - color + this + Colors.NORMAL - } - } - } - - /** - * Makes the given string cyan. - */ - @JvmStatic - fun String?.cyan(): String = colorize(Colors.CYAN) - - /** - * URL encodes the given string. - */ - @JvmStatic - fun String.encodeUrl(): String = UrlEncoderUtil.encode(this) - - /** - * Returns a property as an int. - */ - @JvmStatic - fun Properties.getIntProperty(key: String, defaultValue: Int): Int { - return getProperty(key)?.toIntOrDefault(defaultValue) ?: defaultValue - } - - /** - * Makes the given string green. - */ - @JvmStatic - fun String?.green(): String = colorize(Colors.DARK_GREEN) - - /** - * Build a help command by replacing `%c` with the bot's pub/priv command, and `%n` with the bot's - * nick. - */ - @JvmStatic - fun helpCmdSyntax(text: String, botNick: String, isPrivate: Boolean): String { - val replace = arrayOf(if (isPrivate) "/msg $botNick" else "$botNick:", botNick) - return text.replaceEach(searchFlags, replace) - } - - /** - * Returns a formatted help string. - */ - @JvmStatic - @JvmOverloads - fun helpFormat(help: String, isBold: Boolean = true, isIndent: Boolean = true): String { - val s = if (isBold) help.bold() else help - return if (isIndent) s.prependIndent() else s - } - - /** - * Returns `true` if the specified user is an operator on the [channel]. - */ - @JvmStatic - fun GenericMessageEvent.isChannelOp(channel: String): Boolean { - return this.bot().userChannelDao.getChannel(channel).isOp(this.user) - } - - /** - * Returns `true` if a HTTP status code indicates a successful response. - */ - @JvmStatic - fun Int.isHttpSuccess() = this in 200..399 - - /** - * Returns the last item of a list of strings or empty if none. - */ - @JvmStatic - fun List.lastOrEmpty(): String { - return if (this.size >= 2) { - this.last() - } else - "" - } - - /** - * Load serial data from file. - */ - @JvmStatic - fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any { - val serialFile = Paths.get(file) - if (serialFile.exists() && serialFile.fileSize() > 0) { - try { - ObjectInputStream( - BufferedInputStream(Files.newInputStream(serialFile)) - ).use { input -> - if (logger.isDebugEnabled) logger.debug("Loading the ${description}.") - return input.readObject() - } - } catch (e: IOException) { - logger.error("An IO error occurred loading the ${description}.", e) - } catch (e: ClassNotFoundException) { - logger.error("An error occurred loading the ${description}.", e) - } - } - return default - } - - /** - * Returns `true` if the list does not contain the given string. - */ - @JvmStatic - fun List.notContains(text: String, ignoreCase: Boolean = false) = this.none { it.equals(text, ignoreCase) } - - /** - * Obfuscates the given string. - */ - @JvmStatic - fun String.obfuscate(): String { - return if (isNotBlank()) { - "x".repeat(length) - } else this - } - - /** - * Returns the plural form of a word, if count > 1. - */ - @JvmStatic - fun String.plural(count: Long): String { - return if (count > 1) "${this}s" else this - } - - /** - * Makes the given string red. - */ - @JvmStatic - fun String?.red(): String = colorize(Colors.RED) - - /** - * Replaces all occurrences of Strings within another String. - */ - @JvmStatic - fun String.replaceEach(search: Array, replace: Array): String { - var result = this - if (search.size == replace.size) { - search.forEachIndexed { i, s -> - result = result.replace(s, replace[i]) - } - } - return result - } - - /** - * Makes the given string reverse color. - */ - @JvmStatic - fun String?.reverseColor(): String = colorize(Colors.REVERSE) - - /** - * Save data - */ - @JvmStatic - fun saveSerialData(file: String, data: Any, logger: Logger, description: String) { - try { - BufferedOutputStream(Files.newOutputStream(Paths.get(file))).use { bos -> - ObjectOutputStream(bos).use { output -> - if (logger.isDebugEnabled) logger.debug("Saving the ${description}.") - output.writeObject(data) - } - } - } catch (e: IOException) { - logger.error("Unable to save the ${description}.", e) - } - } - - /** - * Send a formatted commands/modules, etc. list. - */ - @JvmStatic - @JvmOverloads - 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, message.msg.colorize(message.color)) - } else if (message.isPrivate || this is PrivateMessageEvent || channel.isBlank()) { - respondPrivateMessage(message.msg.colorize(message.color)) - } else { - bot().sendIRC().message(channel, message.msg.colorize(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. - */ - @JvmStatic - fun today(): String = LocalDateTime.now().toIsoLocalDate() - - /** - * Converts a string to an int. - */ - @JvmStatic - fun String.toIntOrDefault(defaultValue: Int): Int { - return try { - toInt() - } catch (e: NumberFormatException) { - defaultValue - } - } - - /** - * Returns the specified date as an ISO local date string. - */ - @JvmStatic - fun Date.toIsoLocalDate(): String { - return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()).toIsoLocalDate() - } - - /** - * Returns the specified date as an ISO local date string. - */ - @JvmStatic - fun LocalDateTime.toIsoLocalDate(): String = format(DateTimeFormatter.ISO_LOCAL_DATE) - - /** - * Returns the specified date formatted as `yyyy-MM-dd HH:mm`. - */ - @JvmStatic - fun Date.toUtcDateTime(): String { - return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()).toUtcDateTime() - } - - /** - * Returns the specified date formatted as `yyyy-MM-dd HH:mm`. - */ - @JvmStatic - fun LocalDateTime.toUtcDateTime(): String = format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) - - /** - * Makes the given string bold. - */ - @JvmStatic - fun String?.underline(): String = colorize(Colors.UNDERLINE) - - - /** - * Converts XML/XHTML entities to plain text. - */ - @JvmStatic - fun String.unescapeXml(): String = Jsoup.parse(this).text() - - /** - * Reads contents of a URL. - */ - @JvmStatic - @Throws(IOException::class) - fun URL.reader(): UrlReaderResponse { - val connection = this.openConnection() as HttpURLConnection - connection.setRequestProperty( - "User-Agent", - "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" - ) - return if (connection.responseCode.isHttpSuccess()) { - UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().use { it.readText() }) - } else { - UrlReaderResponse(connection.responseCode, connection.errorStream.bufferedReader().use { it.readText() }) - } - } - - /** - * Holds the [URL.reader] response code and body text. - */ - data class UrlReaderResponse(val responseCode: Int, val body: String) -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt deleted file mode 100644 index 5f79472..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/AbstractCommand.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * AbstractCommand.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -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 - -abstract class AbstractCommand { - abstract val name: String - abstract val help: List - abstract val isOpOnly: Boolean - abstract val isPublic: Boolean - abstract val isVisible: Boolean - - val properties: MutableMap = mutableMapOf() - - abstract fun commandResponse(channel: String, args: String, event: GenericMessageEvent) - - open fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - if (!isOpOnly || isOpOnly == event.isChannelOp(channel)) { - for (h in help) { - event.sendMessage(helpCmdSyntax(h, event.bot().nick, event is PrivateMessageEvent || !isPublic)) - } - return true - } - return false - } - - open fun initProperties(vararg keys: String) { - keys.forEach { - properties[it] = "" - } - } - - open fun isEnabled(): Boolean { - return true - } - - open fun matches(message: String): Boolean { - return false - } - - open fun setProperty(key: String, value: String) { - properties[key] = value - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt deleted file mode 100644 index 038e378..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/ChannelFeed.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ChannelFeed.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.FeedReader -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - -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 isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val FEED_PROP = "feed" - } - - init { - initProperties(FEED_PROP) - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (isEnabled()) { - properties[FEED_PROP]?.let { FeedReader(it, event).run() } - } - } - - override fun isEnabled(): Boolean { - return !properties[FEED_PROP].isNullOrBlank() - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt b/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt deleted file mode 100644 index 9608ca8..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Cycle.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Cycle.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.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 -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -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 isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - 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) - } - } - } else { - helpResponse(channel, args, event) - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Die.kt b/bin/main/net/thauvin/erik/mobibot/commands/Die.kt deleted file mode 100644 index f271bfa..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Die.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Die.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Die : AbstractCommand() { - override val name = "die" - override val help = emptyList() - override val isOpOnly = true - override val isPublic = false - override val isVisible = false - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - with(event.bot()) { - if (event.isChannelOp(channel) && (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 { - const val DIE_PROP = "die" - } - - init { - initProperties(DIE_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt b/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt deleted file mode 100644 index d083c10..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Ignore.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Ignore.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -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.LinksManager -import org.pircbotx.hooks.types.GenericMessageEvent - -class Ignore : AbstractCommand() { - private val me = "me" - - init { - initProperties(IGNORE_PROP) - } - - override val name = IGNORE_CMD - override val help = listOf( - "To ignore a link posted to the channel:", - helpFormat("https://www.foo.bar %n"), - "To check your ignore status:", - helpFormat("%c $name"), - "To toggle your ignore status:", - helpFormat("%c $name $me") - ) - private val helpOp = help.plus( - arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name [ ...]")) - ) - - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val IGNORE_CMD = "ignore" - const val IGNORE_PROP = IGNORE_CMD - private val ignored = mutableSetOf() - - @JvmStatic - fun isNotIgnored(nick: String): Boolean { - return !ignored.contains(nick.lowercase()) - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val isMe = args.trim().equals(me, true) - if (isMe || !event.isChannelOp(channel)) { - val nick = event.user.nick.lowercase() - ignoreNick(nick, isMe, event) - } else { - ignoreOp(args, event) - } - } - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - return if (event.isChannelOp(channel)) { - for (h in helpOp) { - event.sendMessage(helpCmdSyntax(h, event.bot().nick, true)) - } - true - } else { - super.helpResponse(channel, topic, event) - } - } - - private fun ignoreNick(sender: String, isMe: Boolean, event: GenericMessageEvent) { - if (isMe) { - if (ignored.remove(sender)) { - event.sendMessage("You are no longer ignored.") - } else { - ignored.add(sender) - event.sendMessage("You are now ignored.") - } - } else { - if (ignored.contains(sender)) { - event.sendMessage("You are currently ignored.") - } else { - event.sendMessage("You are not currently ignored.") - } - } - } - - private fun ignoreOp(args: String, event: GenericMessageEvent) { - if (args.isNotEmpty()) { - val nicks = args.lowercase().split(" ") - for (nick in nicks) { - val ignore = if (me == nick) { - nick.lowercase() - } else { - nick - } - if (!ignored.remove(ignore)) { - ignored.add(ignore) - } - } - } - - if (ignored.isNotEmpty()) { - event.sendMessage("The following nicks are ignored:") - event.sendList(ignored.sorted(), 8, isIndent = true) - } else { - event.sendMessage("No one is currently ${"ignored".bold()}.") - } - } - - override fun setProperty(key: String, value: String) { - super.setProperty(key, value) - if (IGNORE_PROP == key) { - ignored.addAll(value.split(LinksManager.TAG_MATCH)) - } - } - -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Info.kt b/bin/main/net/thauvin/erik/mobibot/commands/Info.kt deleted file mode 100644 index ed0b6ef..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Info.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Info.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands - -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.plural -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.links.LinksManager -import net.thauvin.erik.mobibot.commands.seen.Seen -import net.thauvin.erik.mobibot.commands.tell.Tell -import org.pircbotx.hooks.types.GenericMessageEvent -import java.lang.management.ManagementFactory -import kotlin.time.DurationUnit -import kotlin.time.toDuration - -class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() { - private val allVersions = listOf( - "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})", - "Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})" - ) - override val name = "info" - override val help = listOf("To view information about the bot:", helpFormat("%c $name")) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - /** - * Converts milliseconds to year month week day hour and minutes. - */ - @JvmStatic - fun Long.toUptime(): String { - this.toDuration(DurationUnit.MILLISECONDS).toComponents { wholeDays, hours, minutes, seconds, _ -> - val years = wholeDays / 365 - var days = wholeDays % 365 - val months = days / 30 - days %= 30 - val weeks = days / 7 - days %= 7 - - with(StringBuffer()) { - if (years > 0) { - append(years).append(" year".plural(years)).append(' ') - } - if (months > 0) { - append(months).append(" month".plural(months)).append(' ') - } - if (weeks > 0) { - append(weeks).append(" week".plural(weeks)).append(' ') - } - if (days > 0) { - append(days).append(" day".plural(days)).append(' ') - } - if (hours > 0) { - append(hours).append(" hour".plural(hours.toLong())).append(' ') - } - - if (minutes > 0) { - append(minutes).append(" minute".plural(minutes.toLong())) - } else { - append(seconds).append(" second".plural(seconds.toLong())) - } - - return toString() - } - } - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - event.sendList(allVersions, 1) - val info = StringBuilder() - info.append("Uptime: ") - .append(ManagementFactory.getRuntimeMXBean().uptime.toUptime()) - .append(" [Entries: ") - .append(LinksManager.entries.links.size) - if (seen.isEnabled()) { - info.append(", Seen: ").append(seen.count()) - } - if (event.isChannelOp(channel)) { - if (tell.isEnabled()) { - info.append(", Messages: ").append(tell.size()) - } - if (LinksManager.socialManager.entriesCount() > 0) { - info.append(", Social: ").append(LinksManager.socialManager.entriesCount()) - } - } - info.append(", Recap: ").append(Recap.recaps.size).append(']') - event.sendMessage(info.toString()) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Me.kt b/bin/main/net/thauvin/erik/mobibot/commands/Me.kt deleted file mode 100644 index ec7823b..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Me.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Me.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -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 : AbstractCommand() { - override val name = "me" - override val help = listOf("To have the bot perform an action:", helpFormat("%c $name ")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.bot().sendIRC().action(channel, args) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt b/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt deleted file mode 100644 index b2293b0..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Modules.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Modules.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -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(private val modules: List, private val disabledModules: List) : AbstractCommand() { - override val name = "modules" - override val help = listOf("To view a list of enabled/disabled modules:", helpFormat("%c $name")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - if (modules.isEmpty()) { - event.respondPrivateMessage("There are no enabled modules.") - } else { - event.respondPrivateMessage("The enabled modules are: ") - event.sendList(modules, 7, isIndent = true) - } - if (disabledModules.isNotEmpty()) { - event.respondPrivateMessage("The disabled modules are: ") - event.sendList(disabledModules, 7, isIndent = true) - } - } else { - helpResponse(channel, args, event) - } - } -} - diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt b/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt deleted file mode 100644 index 20a6635..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Msg.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Msg.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -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 : AbstractCommand() { - override val name = "msg" - override val help = listOf( - "To have the bot send a private message to someone:", - helpFormat("%c $name ") - ) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - val msg = args.split(" ", limit = 2) - if (args.length > 2) { - event.bot().sendIRC().message(msg[0], msg[1]) - event.respondPrivateMessage("A message was sent to ${msg[0]}") - } else { - helpResponse(channel, args, event) - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt b/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt deleted file mode 100644 index 85a03ab..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Nick.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Nick.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -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 : AbstractCommand() { - override val name = "nick" - override val help = listOf("To change the bot's nickname:", helpFormat("%c $name ")) - override val isOpOnly = true - override val isPublic = true - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.bot().sendIRC().changeNick(args) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt b/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt deleted file mode 100644 index 77154c7..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Recap.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Recap.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -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 : AbstractCommand() { - override val name = "recap" - override val help = listOf( - "To list the last 10 public channel messages:", - helpFormat("%c $name") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val MAX_RECAPS = 10 - - @JvmField - val recaps = mutableListOf() - - /** - * Stores the last 10 public messages and actions. - */ - @JvmStatic - fun storeRecap(sender: String, message: String, isAction: Boolean) { - recaps.add( - LocalDateTime.now(Clock.systemUTC()).toUtcDateTime() - + " - $sender" + (if (isAction) " " else ": ") + message - ) - if (recaps.size > MAX_RECAPS) { - recaps.removeFirst() - } - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (recaps.isNotEmpty()) { - for (r in recaps) { - event.sendMessage(r) - } - } else { - event.sendMessage("Sorry, nothing to recap.") - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Say.kt b/bin/main/net/thauvin/erik/mobibot/commands/Say.kt deleted file mode 100644 index 7f76d35..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Say.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Say.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -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 : AbstractCommand() { - override val name = "say" - override val help = listOf("To have the bot say something on the channel:", helpFormat("%c $name ")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.bot().sendIRC().message(channel, args) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Users.kt b/bin/main/net/thauvin/erik/mobibot/commands/Users.kt deleted file mode 100644 index 33d6fef..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Users.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Users.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -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 : AbstractCommand() { - override val name = "users" - override val help = listOf("To list the users present on the channel:", helpFormat("%c $name")) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val ch = event.bot().userChannelDao.getChannel(channel) - event.sendList(ch.users.map { if (it.channelsOpIn.contains(ch)) "@${it.nick}" else it.nick }, 8) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt b/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt deleted file mode 100644 index 896c569..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/Versions.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Versions.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands - -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.PircBotX -import org.pircbotx.hooks.types.GenericMessageEvent - -class Versions : AbstractCommand() { - private val allVersions = listOf( - "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})", - "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + - ", JVM ${System.getProperty("java.runtime.version")}", - "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" - ) - override val name = "versions" - override val help = listOf("To view the versions data (bot, platform, java, etc.):", helpFormat("%c $name")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.sendList(allVersions, 1) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt deleted file mode 100644 index 1443d44..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Comment.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -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.printComment -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import org.pircbotx.hooks.types.GenericMessageEvent - -class Comment : AbstractCommand() { - override val name = COMMAND - override val help = listOf( - "To add a comment:", - helpFormat("${Constants.LINK_CMD}1:This is a comment"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", - "To edit a comment, use its label: ", - helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"), - "To delete a comment, use its label and a minus sign: ", - helpFormat("${Constants.LINK_CMD}1.1:-") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val COMMAND = "comment" - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val cmds = args.substring(1).split("[.:]".toRegex(), 3) - val entryIndex = cmds[0].toInt() - 1 - - if (entryIndex < LinksManager.entries.links.size && LinksManager.isUpToDate(event)) { - val entry: EntryLink = LinksManager.entries.links[entryIndex] - val commentIndex = cmds[1].toInt() - 1 - if (commentIndex < entry.comments.size) { - when (val cmd = cmds[2].trim()) { - "" -> showComment(entry, entryIndex, commentIndex, event) // L1.1: - "-" -> deleteComment(channel, entry, entryIndex, commentIndex, event) // L1.1:- - else -> { - if (cmd.startsWith('?')) { // L1.1:? - changeAuthor(channel, cmd, entry, entryIndex, commentIndex, event) - } else { // L1.1: - setComment(cmd, entry, entryIndex, commentIndex, event) - } - } - } - } - } - } - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - if (super.helpResponse(channel, topic, event)) { - if (event.isChannelOp(channel)) { - event.sendMessage("To change a comment's author:") - event.sendMessage(helpFormat("${Constants.LINK_CMD}1.1:?")) - } - return true - } - return false - } - - override fun matches(message: String): Boolean { - return message.matches("^${Constants.LINK_CMD}\\d+\\.\\d+:.*".toRegex()) - } - - private fun changeAuthor( - channel: String, - cmd: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent - ) { - if (event.isChannelOp(channel) && cmd.length > 1) { - val comment = entry.getComment(commentIndex) - comment.nick = cmd.substring(1) - event.sendMessage(printComment(entryIndex, commentIndex, comment)) - LinksManager.entries.save() - } else { - event.sendMessage("Please ask a channel op to change the author of this comment for you.") - } - } - - private fun deleteComment( - channel: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent - ) { - if (event.isChannelOp(channel) || event.user.nick == entry.getComment(commentIndex).nick) { - entry.deleteComment(commentIndex) - event.sendMessage("Comment ${entryIndex.toLinkLabel()}.${commentIndex + 1} removed.") - LinksManager.entries.save() - } else { - event.sendMessage("Please ask a channel op to delete this comment for you.") - } - } - - private fun setComment( - cmd: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent - ) { - entry.setComment(commentIndex, cmd, event.user.nick) - event.sendMessage(printComment(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))) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt deleted file mode 100644 index fba6b99..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ /dev/null @@ -1,207 +0,0 @@ -/* - * LinksManager.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -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.Companion.isNotIgnored -import net.thauvin.erik.mobibot.entries.Entries -import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.social.SocialManager -import org.jsoup.Jsoup -import org.pircbotx.hooks.types.GenericMessageEvent -import java.io.IOException - -class LinksManager : AbstractCommand() { - private val defaultTags: MutableList = mutableListOf() - private val keywords: MutableList = mutableListOf() - - override val name = Constants.LINK_CMD - override val help = emptyList() - override val isOpOnly = false - override val isPublic = false - override val isVisible = false - - init { - initProperties(TAGS_PROP, KEYWORDS_PROP) - } - - companion object { - val LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*".toRegex() - const val KEYWORDS_PROP = "tags-keywords" - const val TAGS_PROP = "tags" - val TAG_MATCH = ", *| +".toRegex() - - /** - * Entries array - */ - @JvmField - val entries = Entries() - - /** - * Pinboard handler. - */ - @JvmField - val pinboard = Pinboard() - - /** - * Social Manager handler. - */ - @JvmField - val socialManager = SocialManager() - - /** - * Let the user know if the entries are too old to be modified. - */ - @JvmStatic - fun isUpToDate(event: GenericMessageEvent): Boolean { - if (entries.lastPubDate != today()) { - event.sendMessage("The links are too old to be updated.") - return false - } - return true - } - } - - 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 (isNotIgnored(sender) && (cmds.size == 1 || !cmds[1].contains(botNick))) { - val link = cmds[0].trim() - if (!isDupEntry(link, event)) { - var title = "" - val tags = ArrayList(defaultTags) - if (cmds.size == 2) { - 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)) - } - } - - if (title.isBlank()) { - title = fetchTitle(link) - } - - if (title != Constants.NO_TITLE) { - matchTagKeywords(title, tags) - } - - // Links are old, clear them - if (entries.lastPubDate != today()) { - entries.links.clear() - } - - val entry = EntryLink(link, title, sender, login, channel, tags) - entries.links.add(entry) - val index = entries.links.lastIndexOf(entry) - event.sendMessage(printLink(index, entry)) - - pinboard.addPin(event.bot().serverHostname, entry) - - // Queue link for posting to social media. - socialManager.queueEntry(index) - - entries.save() - - if (Constants.NO_TITLE == entry.title) { - event.sendMessage("Please specify a title, by typing:") - event.sendMessage(helpFormat("${index.toLinkLabel()}:|This is the title")) - } - } - } - } - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean = false - - override fun matches(message: String): Boolean { - return message.matches(LINK_MATCH) - } - - internal fun fetchTitle(link: String): String { - try { - val html = Jsoup.connect(link) - .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0") - .get() - val title = html.title() - if (title.isNotBlank()) { - return title - } - } catch (ignore: IOException) { - // Do nothing - } - return Constants.NO_TITLE - } - - private fun isDupEntry(link: String, event: GenericMessageEvent): Boolean { - synchronized(entries) { - return try { - val match = entries.links.single { it.link == link } - event.sendMessage( - "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match) - ) - true - } catch (ignore: NoSuchElementException) { - false - } - } - } - - internal fun matchTagKeywords(title: String, tags: MutableList) { - for (match in keywords) { - val m = Regex.escape(match) - if (title.matches("(?i).*\\b$m\\b.*".toRegex())) { - tags.add(match) - } - } - } - - override fun setProperty(key: String, value: String) { - super.setProperty(key, value) - if (KEYWORDS_PROP == key) { - keywords.addAll(value.split(TAG_MATCH)) - } else if (TAGS_PROP == key) { - defaultTags.addAll(value.split(TAG_MATCH)) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt deleted file mode 100644 index ff4278d..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Posting.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -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.LinksManager.Companion.entries -import net.thauvin.erik.mobibot.entries.EntriesUtils -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import org.pircbotx.hooks.types.GenericMessageEvent - -class Posting : AbstractCommand() { - override val name = "posting" - override val help = listOf( - "Post a URL, by saying it on a line on its own:", - helpFormat(" [] ${Tags.COMMAND}: <+tag> [...]]"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1", - "To add a title, use its label and a pipe:", - helpFormat("${Constants.LINK_CMD}1:|This is the title"), - "To add a comment:", - helpFormat("${Constants.LINK_CMD}1:This is a comment"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", - "To edit a comment, see: ", - helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val cmds = args.substring(1).split(":", limit = 2) - val entryIndex = cmds[0].toInt() - 1 - - if (entryIndex < entries.links.size) { - val cmd = cmds[1].trim() - if (cmd.isBlank()) { - showEntry(entryIndex, event) // L1: - } else if (LinksManager.isUpToDate(event)) { - if (cmd == "-") { - removeEntry(channel, entryIndex, event) // L1:- - } else { - when (cmd[0]) { - '|' -> changeTitle(cmd, entryIndex, event) // L1:|<title> - '=' -> changeUrl(channel, cmd, entryIndex, event) // L1:=<url> - '?' -> changeAuthor(channel, cmd, entryIndex, event) // L1:?<author> - else -> addComment(cmd, entryIndex, event) // L1:<comment> - } - } - } - } - } - - override fun matches(message: String): Boolean { - return message.matches("${Constants.LINK_CMD}\\d+:.*".toRegex()) - } - - 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) - event.sendMessage(EntriesUtils.printComment(entryIndex, commentIndex, comment)) - entries.save() - } - - private fun changeTitle(cmd: String, entryIndex: Int, event: GenericMessageEvent) { - if (cmd.length > 1) { - 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)) - entries.save() - } - } - - private fun changeUrl(channel: String, cmd: String, entryIndex: Int, event: GenericMessageEvent) { - 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)) { - val oldLink = entry.link - entry.link = link - LinksManager.pinboard.updatePin(event.bot().serverHostname, oldLink, entry) - event.sendMessage(EntriesUtils.printLink(entryIndex, entry)) - entries.save() - } - } - } - - private fun changeAuthor(channel: String, cmd: String, index: Int, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - if (cmd.length > 1) { - 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)) - entries.save() - } - } else { - event.sendMessage("Please ask a channel op to change the author of this link for you.") - } - } - - private fun removeEntry(channel: String, index: Int, event: GenericMessageEvent) { - val entry: EntryLink = entries.links[index] - if (entry.login == event.user.login || event.isChannelOp(channel)) { - LinksManager.pinboard.deletePin(entry) - LinksManager.socialManager.removeEntry(index) - entries.links.removeAt(index) - event.sendMessage("Entry ${index.toLinkLabel()} removed.") - entries.save() - } else { - event.sendMessage("Please ask a channel op to remove this entry for you.") - } - } - - private fun showEntry(index: Int, event: GenericMessageEvent) { - val entry: EntryLink = entries.links[index] - event.sendMessage(EntriesUtils.printLink(index, entry)) - if (entry.tags.isNotEmpty()) { - event.sendMessage(EntriesUtils.printTags(index, entry)) - } - if (entry.comments.isNotEmpty()) { - val comments = entry.comments - for (i in comments.indices) { - event.sendMessage(EntriesUtils.printComment(index, i, comments[i])) - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt deleted file mode 100644 index 1662857..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/links/Tags.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Tags.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -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 : 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 isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val COMMAND = "tags" - } - - 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 < LinksManager.entries.links.size && LinksManager.isUpToDate(event)) { - val cmd = cmds[1].trim() - val entry: EntryLink = LinksManager.entries.links[index] - if (cmd.isNotEmpty()) { - 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)) - 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)) - } else { - event.sendMessage("The entry has no tags. Why don't add some?") - } - } - } - } - - override fun matches(message: String): Boolean { - return message.matches("^${Constants.LINK_CMD}\\d+${Constants.TAG_CMD}:.*".toRegex()) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt b/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt deleted file mode 100644 index 825e374..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/links/View.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * View.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.lastOrEmpty -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.links.LinksManager.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 : AbstractCommand() { - override val name = VIEW_CMD - override val help = listOf( - "To list or search the current URL posts:", - helpFormat("%c $name [<start>] [<query>]") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val MAX_ENTRIES = 6 - const val VIEW_CMD = "view" - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (entries.links.isNotEmpty()) { - val p = parseArgs(args) - showPosts(p.first, p.second, event) - } else { - event.sendMessage("There is currently nothing to view. Why don't you post something?") - } - } - - internal fun parseArgs(args: String): Pair<Int, String> { - var query = args.lowercase().trim() - var start = 0 - if (query.isEmpty() && entries.links.size > MAX_ENTRIES) { - start = entries.links.size - MAX_ENTRIES - } - if (query.matches("^\\d+(| .*)".toRegex())) { // view [<start>] [<query>] - val split = query.split(" ", limit = 2) - try { - start = split[0].toInt() - 1 - query = split.lastOrEmpty().trim() - if (start > entries.links.size) { - start = 0 - } - } catch (ignore: NumberFormatException) { - // Do nothing - } - } - return Pair(start, query) - } - - private fun showPosts(start: Int, query: String, event: GenericMessageEvent) { - var index = start - var entry: EntryLink - var sent = 0 - while (index < entries.links.size && sent < MAX_ENTRIES) { - entry = entries.links[index] - if (query.isNotBlank()) { - if (entry.matches(query)) { - event.sendMessage(EntriesUtils.printLink(index, entry, true)) - sent++ - } - } else { - event.sendMessage(EntriesUtils.printLink(index, entry, true)) - sent++ - } - index++ - if (sent == MAX_ENTRIES && index < entries.links.size) { - event.sendMessage("To view more, try: ") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent) - ) - ) - } - } - if (sent == 0) { - event.sendMessage("No matches. Please try again.") - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt deleted file mode 100644 index cfd2c27..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * NickComparator.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.seen - -import java.io.Serializable - -class NickComparator : Comparator<String>, Serializable { - override fun compare(a: String, b: String): Int { - return a.lowercase().compareTo(b.lowercase()) - } - - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 1L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt deleted file mode 100644 index c9ee0f3..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Seen.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.seen - -import com.google.common.collect.ImmutableSortedSet -import net.thauvin.erik.mobibot.Utils -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.loadSerialData -import net.thauvin.erik.mobibot.Utils.saveSerialData -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime -import org.pircbotx.User -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.util.* - - -class Seen(private val serialObject: String) : AbstractCommand() { - private val logger: Logger = LoggerFactory.getLogger(Seen::class.java) - private val allKeyword = "all" - val seenNicks = TreeMap<String, SeenNick>(NickComparator()) - - override val name = "seen" - override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>")) - private val helpOp = help.plus( - arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword")) - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (isEnabled()) { - if (args.isNotBlank() && !args.contains(' ')) { - val ch = event.bot().userChannelDao.getChannel(channel) - if (args == allKeyword && ch.isOp(event.user) && seenNicks.isNotEmpty()) { - event.sendMessage("The ${"seen".bold()} nicks are:") - event.sendList(seenNicks.keys.toList(), 7, separator = ", ", isIndent = true) - return - } - ch.users.forEach { - if (args.equals(it.nick, true)) { - event.sendMessage("${it.nick} is on ${channel}.") - return - } - } - if (seenNicks.containsKey(args)) { - val seenNick = seenNicks.getValue(args) - val lastSeen = System.currentTimeMillis() - seenNick.lastSeen - event.sendMessage("${seenNick.nick} was last seen on $channel ${lastSeen.toUptime()} ago.") - return - } - event.sendMessage("I haven't seen $args on $channel lately.") - } else { - helpResponse(channel, args, event) - } - } - } - - fun add(nick: String) { - if (isEnabled()) { - seenNicks[nick] = SeenNick(nick, System.currentTimeMillis()) - save() - } - } - - fun add(users: ImmutableSortedSet<User>) { - if (isEnabled()) { - users.forEach { - seenNicks[it.nick] = SeenNick(it.nick, System.currentTimeMillis()) - } - save() - } - } - - fun clear() { - seenNicks.clear() - } - - fun count(): Int = seenNicks.size - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - return if (event.isChannelOp(channel)) { - for (h in helpOp) { - event.sendMessage(Utils.helpCmdSyntax(h, event.bot().nick, true)) - } - true - } else { - super.helpResponse(channel, topic, event) - } - } - - fun load() { - if (isEnabled()) { - @Suppress("UNCHECKED_CAST") - seenNicks.putAll( - loadSerialData( - serialObject, - TreeMap<String, SeenNick>(), - logger, - "seen nicknames" - ) as TreeMap<String, SeenNick> - ) - } - } - - fun save() { - saveSerialData(serialObject, seenNicks, logger, "seen nicknames") - } - - init { - load() - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt deleted file mode 100644 index 7924977..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SeenNick.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.seen - -import java.io.Serializable - -data class SeenNick(val nick: String, val lastSeen: Long) : Serializable { - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 1L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt deleted file mode 100644 index 061ca6a..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Tell.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands.tell - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -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(private val serialObject: String) : AbstractCommand() { - // Messages queue - private val messages: MutableList<TellMessage> = mutableListOf() - - // Maximum number of days to keep messages - private var maxDays = 7 - - // Message maximum queue size - private var maxSize = 50 - - /** - * The tell command. - */ - override val name = "tell" - - override val help = listOf( - "To send a message to someone when they join the channel:", - helpFormat("%c $name <nick> <message>"), - "To view queued and sent messages:", - helpFormat("%c $name ${View.VIEW_CMD}"), - "Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.' - ) - override val isOpOnly: Boolean = false - override val isPublic: Boolean = isEnabled() - override val isVisible: Boolean = isEnabled() - - /** - * Cleans the messages queue. - */ - private fun clean(): Boolean { - return TellManager.clean(messages, maxDays.toLong()) - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (isEnabled()) { - when { - args.isBlank() -> { - helpResponse(channel, args, event) - } - - args.startsWith(View.VIEW_CMD) -> { - if (event.isChannelOp(channel) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) { - viewAll(event) - } else { - viewMessages(event) - } - } - - args.startsWith("$TELL_DEL_KEYWORD ") -> { - deleteMessage(channel, args, event) - } - - else -> { - newMessage(channel, args, event) - } - } - if (clean()) { - save() - } - } - } - - // Delete message. - private fun deleteMessage(channel: String, args: String, event: GenericMessageEvent) { - val split = args.split(" ") - if (split.size == 2) { - val id = split[1] - if (TELL_ALL_KEYWORD.equals(id, ignoreCase = true)) { - if (messages.removeIf { it.sender.equals(event.user.nick, true) && it.isReceived }) { - save() - event.sendMessage("Delivered messages have been deleted.") - } else { - event.sendMessage("No delivered messages were found.") - } - } else { - if (messages.removeIf { - it.id == id && - (it.sender.equals(event.user.nick, true) || event.isChannelOp(channel)) - }) { - save() - event.sendMessage("The message was deleted from the queue.") - } else { - event.sendMessage("The specified message [ID $id] could not be found.") - } - } - } else { - helpResponse(channel, args, event) - } - } - - override fun isEnabled(): Boolean { - return maxSize > 0 && maxDays > 0 - } - - override fun setProperty(key: String, value: String) { - super.setProperty(key, value) - if (MAX_DAYS_PROP == key) { - maxDays = value.toIntOrDefault(maxDays) - } else if (MAX_SIZE_PROP == key) { - maxSize = value.toIntOrDefault(maxSize) - } - } - - // New message. - 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(event.user.nick, split[0], split[1].trim()) - messages.add(message) - save() - event.sendMessage("Message [ID ${message.id}] was queued for ${message.recipient.bold()}") - } else { - event.sendMessage("Sorry, the messages queue is currently full.") - } - } else { - helpResponse(channel, args, event) - } - } - - /** - * Saves the messages queue. - */ - private fun save() { - TellManager.save(serialObject, messages) - } - - /** - * Checks and sends messages. - */ - fun send(event: GenericUserEvent) { - val nickname = event.user.nick - if (isEnabled() && nickname != event.getBot<PircBotX>().nick) { - messages.filter { it.isMatch(nickname) }.forEach { message -> - if (message.recipient.equals(nickname, ignoreCase = true) && !message.isReceived) { - if (message.sender == nickname) { - if (event !is MessageEvent) { - event.user.send().message( - "${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}" - ) - message.isReceived = true - message.isNotified = true - save() - } - } else { - event.user.send().message( - "${message.sender} wanted me to tell you: ${message.message.reverseColor()}" - ) - message.isReceived = true - save() - } - } else if (message.sender.equals(nickname, ignoreCase = true) && message.isReceived - && !message.isNotified - ) { - event.user.send().message( - "Your message ${"[ID ${message.id}]".reverseColor()} was sent to " - + "${message.recipient.bold()} on ${message.receptionDate}" - ) - message.isNotified = true - save() - } - } - } - } - - /** - * Returns the messages queue size. - * - * @return The size. - */ - fun size(): Int = messages.size - - // View all messages. - private fun viewAll(event: GenericMessageEvent) { - if (messages.isNotEmpty()) { - for (message in messages) { - event.sendMessage( - "${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " + - (if (message.isReceived) "DELIVERED]" else "QUEUED]") - ) - } - } else { - event.sendMessage("There are no messages in the queue.") - } - } - - // View messages. - private fun viewMessages(event: GenericMessageEvent) { - var hasMessage = false - for (message in messages.filter { it.isMatch(event.user.nick) }) { - if (!hasMessage) { - hasMessage = true - event.sendMessage("Here are your messages: ") - } - if (message.isReceived) { - event.sendMessage( - message.sender.bold() + ARROW + message.recipient.bold() + - " [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]" - ) - } else { - event.sendMessage( - message.sender.bold() + ARROW + message.recipient.bold() + - " [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]" - ) - } - event.sendMessage(helpFormat(message.message)) - } - if (!hasMessage) { - event.sendMessage("You have no messages in the queue.") - } else { - event.sendMessage("To delete one or all delivered messages:") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $name $TELL_DEL_KEYWORD <id|$TELL_ALL_KEYWORD>", event.bot().nick, true) - ) - ) - event.sendMessage(help.last()) - } - } - - companion object { - /** - * Max days property. - */ - const val MAX_DAYS_PROP = "tell-max-days" - - /** - * Max size property. - */ - const val MAX_SIZE_PROP = "tell-max-size" - - // Arrow - private const val ARROW = " --> " - - // All keyword - private const val TELL_ALL_KEYWORD = "all" - - //T he delete command. - private const val TELL_DEL_KEYWORD = "del" - } - - /** - * Creates a new instance. - */ - init { - initProperties(MAX_DAYS_PROP, MAX_SIZE_PROP) - - // Load the message queue - messages.addAll(TellManager.load(serialObject)) - if (clean()) { - save() - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt deleted file mode 100644 index b65a4da..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellManager.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * TellManager.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands.tell - -import net.thauvin.erik.mobibot.Utils.loadSerialData -import net.thauvin.erik.mobibot.Utils.saveSerialData -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.time.Clock -import java.time.LocalDateTime - -/** - * The Tell Messages Manager. - */ -object TellManager { - private val logger: Logger = LoggerFactory.getLogger(TellManager::class.java) - - /** - * Cleans the messages queue. - */ - @JvmStatic - fun clean(tellMessages: MutableList<TellMessage>, tellMaxDays: Long): Boolean { - if (logger.isDebugEnabled) logger.debug("Cleaning the messages.") - val today = LocalDateTime.now(Clock.systemUTC()) - return tellMessages.removeIf { o: TellMessage -> o.queued.plusDays(tellMaxDays).isBefore(today) } - } - - /** - * Loads the messages. - */ - @JvmStatic - fun load(file: String): List<TellMessage> { - @Suppress("UNCHECKED_CAST") - return loadSerialData(file, emptyList<TellMessage>(), logger, "message queue") as List<TellMessage> - } - - /** - * Saves the messages. - */ - @JvmStatic - fun save(file: String, messages: List<TellMessage?>?) { - if (messages != null) { - saveSerialData(file, messages, logger, "messages") - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt deleted file mode 100644 index d17fbb5..0000000 --- a/bin/main/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * TellMessage.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands.tell - -import java.io.Serializable -import java.time.Clock -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter - -/** - * Tell Message. - */ -class TellMessage( - /** - * Returns the message's sender. - */ - val sender: String, - - /** - * Returns the message's recipient. - */ - val recipient: String, - - /** - * Returns the message text. - */ - val message: String -) : Serializable { - /** - * Returns the queued date/time. - */ - var queued: LocalDateTime = LocalDateTime.now(Clock.systemUTC()) - - /** - * Returns the message id. - */ - var id: String = queued.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) - - /** - * Returns `true` if a notification was sent. - */ - var isNotified = false - - /** - * Returns `true` if the message was received. - */ - var isReceived = false - set(value) { - if (value) { - receptionDate = LocalDateTime.now(Clock.systemUTC()) - } - field = value - } - - /** - * Returns the message creating date. - */ - var receptionDate: LocalDateTime = LocalDateTime.MIN - - /** - * Matches the message sender or recipient. - */ - fun isMatch(nick: String?): Boolean { - return sender.equals(nick, ignoreCase = true) || recipient.equals(nick, ignoreCase = true) - } - - override fun toString(): String { - return ("TellMessage{id='$id', isNotified=$isNotified, isReceived=$isReceived, message='$message', " + - "queued=$queued, received=$receptionDate, recipient='$recipient', sender='$sender'}") - } - - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 2L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt b/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt deleted file mode 100644 index e8676ec..0000000 --- a/bin/main/net/thauvin/erik/mobibot/entries/Entries.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Entries.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.entries - -import net.thauvin.erik.mobibot.Utils.today - -class Entries( - var channel: String = "", - var ircServer: String = "", - var logsDir: String = "", - var backlogs: String = "" -) { - val links = mutableListOf<EntryLink>() - - var lastPubDate = today() - - fun load() { - lastPubDate = FeedsManager.loadFeed(this) - } - - fun save() { - lastPubDate = today() - FeedsManager.saveFeed(this) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt deleted file mode 100644 index 9c09626..0000000 --- a/bin/main/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * EntriesUtils.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.entries - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.green - -/** - * Entries utilities. - */ -object EntriesUtils { - /** - * Prints an entry's comment for display on the channel. - */ - @JvmStatic - fun printComment(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. - */ - @JvmStatic - @JvmOverloads - fun printLink(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()) { - buff.append("[+").append(entry.comments.size).append(']') - } - buff.append(' ') - with(entry) { - if (Constants.NO_TITLE == title) { - buff.append(title) - } else { - buff.append(title.bold()) - } - buff.append(" ( ").append(link.green()).append(" )") - } - return buff.toString() - } - - /** - * Prints an entry's tags/categories for display on the channel. e.g. L1T: tag1, tag2 - */ - @JvmStatic - fun printTags(entryIndex: Int, entry: EntryLink): String = - entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ") - - /** - * Builds link label based on its index. e.g: L1 - */ - @JvmStatic - fun Int.toLinkLabel(): String = Constants.LINK_CMD + (this + 1) -} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt deleted file mode 100644 index e18d692..0000000 --- a/bin/main/net/thauvin/erik/mobibot/entries/EntryComment.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * EntryComment.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.entries - -import java.io.Serializable -import java.time.LocalDateTime - -/** - * Entry comments data class. - */ -data class EntryComment(var comment: String, var nick: String) : Serializable { - /** - * Creation date. - */ - val date: LocalDateTime = LocalDateTime.now() - - override fun toString(): String = "EntryComment{comment='$comment', date=$date, nick='$nick'}" - - companion object { - // Serial version UID - @Suppress("ConstPropertyName") - private const val serialVersionUID: Long = 1L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt b/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt deleted file mode 100644 index 4a69446..0000000 --- a/bin/main/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ /dev/null @@ -1,213 +0,0 @@ -/* - * EntryLink.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.entries - -import com.rometools.rome.feed.synd.SyndCategory -import com.rometools.rome.feed.synd.SyndCategoryImpl -import net.thauvin.erik.mobibot.commands.links.LinksManager -import java.io.Serializable -import java.util.* - -/** - * The class used to store link entries. - */ -class EntryLink( - // Link's comments - val comments: MutableList<EntryComment> = mutableListOf(), - - // Tags/categories - val tags: MutableList<SyndCategory> = mutableListOf(), - - // Channel - var channel: String, - - // Creation date - var date: Date = Calendar.getInstance().time, - - // Link's URL - var link: String, - - // Author's login - var login: String = "", - - // Author's nickname - var nick: String, - - // Link's title - var title: String -) : Serializable { - /** - * Creates a new entry. - */ - constructor( - link: String, - title: String, - nick: String, - login: String, - channel: String, - tags: List<String?> - ) : this(link = link, title = title, nick = nick, login = login, channel = channel) { - setTags(tags) - } - - /** - * Creates a new entry. - */ - constructor( - link: String, - title: String, - nick: String, - channel: String, - date: Date, - tags: List<SyndCategory> - ) : this(link = link, title = title, nick = nick, channel = channel, date = Date(date.time)) { - this.tags.addAll(tags) - } - - /** - * Adds a new comment - */ - fun addComment(comment: EntryComment): Int { - comments.add(comment) - return comments.lastIndex - } - - /** - * Adds a new comment. - */ - fun addComment(comment: String, nick: String): Int { - return addComment(EntryComment(comment, nick)) - } - - /** - * Deletes a specific comment. - */ - 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) - } - - /** - * 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 true if a string is contained in the link, title, or nick. - */ - fun matches(match: String?): Boolean { - return if (match.isNullOrEmpty()) { - false - } else { - link.contains(match, true) || title.contains(match, true) || nick.contains(match, true) - } - } - - /** - * Sets a comment. - */ - fun setComment(index: Int, comment: String?, nick: String?) { - if (index < comments.size && !comment.isNullOrBlank() && !nick.isNullOrBlank()) { - comments[index] = EntryComment(comment, nick) - } - } - - /** - * Sets the tags. - */ - fun setTags(tags: String) { - setTags(tags.split(LinksManager.TAG_MATCH)) - } - - /** - * Sets the tags. - */ - private fun setTags(tags: List<String?>) { - if (tags.isNotEmpty()) { - var category: SyndCategoryImpl - for (tag in tags) { - if (!tag.isNullOrBlank()) { - val t = tag.lowercase() - val mod = t[0] - if (mod == '-') { - // Don't remove the channel tag - if (channel.substring(1) != t.substring(1)) { - category = SyndCategoryImpl() - category.name = t.substring(1) - this.tags.remove(category) - } - } else { - category = SyndCategoryImpl() - if (mod == '+') { - category.name = t.substring(1) - } else { - category.name = t - } - if (!this.tags.contains(category)) { - this.tags.add(category) - } - } - } - } - } - } - - /** - * Returns a string representation of the object. - */ - override fun toString(): String { - return ("EntryLink{channel='$channel', comments=$comments, date=$date, link='$link', login='$login'," + - "nick='$nick', tags=$tags, title='$title'}") - } - - companion object { - // Serial version UID - @Suppress("ConstPropertyName") - private const val serialVersionUID: Long = 1L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt deleted file mode 100644 index f786cb2..0000000 --- a/bin/main/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ /dev/null @@ -1,187 +0,0 @@ -/* - * FeedsManager.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.entries - -import com.rometools.rome.feed.synd.* -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.* -import kotlin.io.path.exists - -/** - * Manages the RSS feeds. - */ -class FeedsManager private constructor() { - companion object { - private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java) - - // The file containing the current entries. - private const val CURRENT_XML = "current.xml" - - // The .xml extension. - private const val DOT_XML = ".xml" - - /** - * Loads the current feed. - */ - @JvmStatic - @Throws(IOException::class, FeedException::class) - fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): 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<String> - for (comment in description.value.split("<br/>")) { - 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. - */ - @JvmStatic - fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) { - if (logger.isDebugEnabled) logger.debug("Saving the feeds...") - if (entries.logsDir.isNotBlank()) { - try { - val output = SyndFeedOutput() - val rss: SyndFeed = SyndFeedImpl() - val items: MutableList<SyndEntry> = 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 <b>") - .append(nick) - .append("</b> on <a href=\"irc://") - .append(entries.ircServer).append('/') - .append(channel) - .append("\"><b>") - .append(channel) - .append("</b></a>") - if (comments.isNotEmpty()) { - buff.append(" <br/><br/>") - for (j in comments.indices) { - if (j > 0) { - buff.append(" <br/>") - } - 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.removePrefix("#")}@${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() + DOT_XML - ) - ), 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/bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt b/bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt deleted file mode 100644 index 8c8e736..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/AbstractModule.kt +++ /dev/null @@ -1,131 +0,0 @@ -/* - * AbstractModule.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -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 { - /** - * The module name. - */ - abstract val name: String - - /** - * The module's commands, if any. - */ - @JvmField - val commands: MutableList<String> = mutableListOf() - - @JvmField - val help: MutableList<String> = mutableListOf() - val properties: MutableMap<String, String> = mutableMapOf() - - /** - * Responds to a command. - */ - abstract fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) - - /** - * Returns the module's property keys. - */ - val propertyKeys: Set<String> - get() = properties.keys - - /** - * Returns `true` if the module has properties. - */ - fun hasProperties(): Boolean { - return properties.isNotEmpty() - } - - /** - * Responds with the module's help. - */ - open fun helpResponse(event: GenericMessageEvent): Boolean { - for (h in help) { - event.sendMessage(helpCmdSyntax(h, event.bot().nick, isPrivateMsgEnabled && event is PrivateMessageEvent)) - } - return true - } - - /** - * Initializes the properties. - */ - fun initProperties(vararg keys: String) { - for (key in keys) { - properties[key] = "" - } - } - - /** - * Returns `true` if the module is enabled. - */ - val isEnabled: Boolean - get() = if (hasProperties()) { - isValidProperties - } else { - true - } - - /** - * Returns `true` if the module responds to private messages. - */ - open val isPrivateMsgEnabled: Boolean = false - - /** - * Ensures that all properties have values. - */ - open val isValidProperties: Boolean - get() { - for (s in properties.keys) { - if (properties[s].isNullOrBlank()) { - return false - } - } - return true - } - - /** - * Sets a property key and value. - */ - fun setProperty(key: String, value: String) { - if (key.isNotBlank()) { - properties[key] = value - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Calc.kt b/bin/main/net/thauvin/erik/mobibot/modules/Calc.kt deleted file mode 100644 index b7aae28..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Calc.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Calc.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.objecthunter.exp4j.ExpressionBuilder -import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException -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 : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Calc::class.java) - - override val name = "Calc" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - 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(event) - } - } - - companion object { - // Calc command - private const val CALC_CMD = "calc" - - /** - * Performs a calculation. e.g.: 1 + 1 * 2 - */ - @JvmStatic - @Throws(IllegalArgumentException::class) - fun calculate(query: String): String { - val decimalFormat = DecimalFormat("#.##") - val calc = ExpressionBuilder(query).build() - return query.replace(" ", "") + " = " + decimalFormat.format(calc.evaluate()).bold() - } - } - - init { - commands.add(CALC_CMD) - help.add("To solve a mathematical calculation:") - help.add(helpFormat("%c $CALC_CMD <calculation>")) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt b/bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt deleted file mode 100644 index bd92332..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/ChatGpt.kt +++ /dev/null @@ -1,176 +0,0 @@ -/* - * ChatGpt.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.apache.commons.text.WordUtils -import org.json.JSONException -import org.json.JSONObject -import org.json.JSONWriter -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URI -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse - -class ChatGpt : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java) - - override val name = CHATGPT_NAME - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val answer = chat( - args.trim(), properties[API_KEY_PROP], - properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() - ) - if (answer.isNotBlank()) { - event.sendMessage(WordUtils.wrap(answer, 400)) - } else { - event.respond("$name is stumped.") - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } catch (e: NumberFormatException) { - if (logger.isErrorEnabled) logger.error("Invalid $MAX_TOKENS_PROP property.", e) - event.respond("The $name module is misconfigured.") - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The service name. - */ - const val CHATGPT_NAME = "ChatGPT" - - /** - * The API Key property. - */ - const val API_KEY_PROP = "chatgpt-api-key" - - /** - * The max tokens property. - */ - const val MAX_TOKENS_PROP = "chatgpt-max-tokens" - - // ChatGPT API URL - private const val API_URL = "https://api.openai.com/v1/completions" - - // ChatGPT command - private const val CHATGPT_CMD = "chatgpt" - - - @JvmStatic - @Throws(ModuleException::class) - fun chat(query: String, apiKey: String?, maxTokens: Int): String { - if (!apiKey.isNullOrEmpty()) { - val prompt = JSONWriter.valueToString("Q:$query\nA:") - val request = HttpRequest.newBuilder() - .uri(URI.create(API_URL)) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer $apiKey") - .header("User-Agent", Constants.USER_AGENT) - .POST( - HttpRequest.BodyPublishers.ofString( - """{ - "model": "text-davinci-003", - "prompt": $prompt, - "temperature": 0, - "max_tokens": $maxTokens, - "top_p": 1, - "frequency_penalty": 0, - "presence_penalty": 0 - }""".trimIndent() - ) - ) - .build() - try { - val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) - if (response.statusCode() == 200) { - try { - val jsonResponse = JSONObject(response.body()) - val choices = jsonResponse.getJSONArray("choices") - return choices.getJSONObject(0).getString("text").trim() - } catch (e: JSONException) { - throw ModuleException( - "$CHATGPT_CMD($query): JSON", - "A JSON error has occurred while conversing with $CHATGPT_NAME.", - e - ) - } - } else { - if (response.statusCode() == 429) { - throw ModuleException( - "$CHATGPT_CMD($query): Rate limit reached", - "Rate limit reached. Please try again later." - ) - } else { - throw IOException("HTTP Status Code: " + response.statusCode()) - } - } - } catch (e: IOException) { - throw ModuleException( - "$CHATGPT_CMD($query): IO", - "An IO error has occurred while conversing with $CHATGPT_NAME.", - e - ) - } - } else { - throw ModuleException("$CHATGPT_CMD($query)", "No $CHATGPT_NAME API key specified.") - } - } - } - - init { - commands.add(CHATGPT_CMD) - with(help) { - add("To get answers from $name:") - add(Utils.helpFormat("%c $CHATGPT_CMD <query>")) - add("For example:") - add(Utils.helpFormat("%c $CHATGPT_CMD explain quantum computing in simple terms")) - add(Utils.helpFormat("%c $CHATGPT_CMD how do I make an HTTP request in Javascript?")) - } - initProperties(API_KEY_PROP, MAX_TOKENS_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt deleted file mode 100644 index d14056e..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ /dev/null @@ -1,159 +0,0 @@ -/* - * CryptoPrices.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.crypto.CryptoException -import net.thauvin.erik.crypto.CryptoPrice -import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.json.JSONObject -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException - -/** - * The Cryptocurrency Prices module. - */ -class CryptoPrices : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(CryptoPrices::class.java) - - override val name = "CryptoPrices" - - /** - * 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) { - if (CURRENCIES.isEmpty()) { - try { - loadCurrencies() - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - } - } - - val debugMessage = "crypto($cmd $args)" - if (args == CODES_KEYWORD) { - event.sendMessage("The supported currencies are:") - event.sendList(ArrayList(CURRENCIES.keys), 10, isIndent = true) - } else 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 - } - event.respond("${price.base} current price is $amount [${CURRENCIES[price.currency]}]") - } catch (e: CryptoException) { - if (logger.isWarnEnabled) logger.warn("$debugMessage => ${e.statusCode}", e) - e.message?.let { - event.respond(it) - } - } catch (e: IOException) { - if (logger.isErrorEnabled) logger.error(debugMessage, e) - event.respond("An IO error has occurred while retrieving the cryptocurrency market price.") - } - } else { - helpResponse(event) - } - - } - - companion object { - // Crypto command - private const val CRYPTO_CMD = "crypto" - - // Fiat Currencies - private val CURRENCIES: MutableMap<String, String> = mutableMapOf() - - // Currency codes keyword - private const val CODES_KEYWORD = "codes" - - /** - * Get current market price. - */ - @JvmStatic - fun currentPrice(args: List<String>): CryptoPrice { - return if (args.size == 2) - spotPrice(args[0], args[1]) - else - spotPrice(args[0]) - } - - /** - * For testing purposes. - */ - fun getCurrencyName(code: String): String? { - return CURRENCIES[code] - } - - /** - * Loads the Fiat currencies.. - */ - @JvmStatic - @Throws(ModuleException::class) - fun loadCurrencies() { - try { - val json = JSONObject(CryptoPrice.apiCall(listOf("currencies"))) - val data = json.getJSONArray("data") - for (i in 0 until data.length()) { - val d = data.getJSONObject(i) - CURRENCIES[d.getString("id")] = d.getString("name") - } - } catch (e: CryptoException) { - throw ModuleException( - "loadCurrencies(): CE", - "An error has occurred while retrieving the currencies table.", - e - ) - } - } - } - - init { - commands.add(CRYPTO_CMD) - with(help) { - add("To retrieve a cryptocurrency's market price:") - add(helpFormat("%c $CRYPTO_CMD <symbol> [<currency>]")) - add("For example:") - add(helpFormat("%c $CRYPTO_CMD BTC")) - add(helpFormat("%c $CRYPTO_CMD ETH EUR")) - add(helpFormat("%c $CRYPTO_CMD ETH2 GPB")) - add("To list the supported currencies:") - add(helpFormat("%c $CRYPTO_CMD $CODES_KEYWORD")) - } - loadCurrencies() - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt deleted file mode 100644 index da0efd8..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ /dev/null @@ -1,222 +0,0 @@ -/* - * CurrencyConverter.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendList -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.PublicMessage -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 -import java.text.DecimalFormat -import java.util.* - - -/** - * The CurrencyConverter module. - */ -class CurrencyConverter : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(CurrencyConverter::class.java) - - override val name = "CurrencyConverter" - - // Reload currency codes - private fun reload(apiKey: String?) { - if (!apiKey.isNullOrEmpty() && SYMBOLS.isEmpty()) { - try { - loadSymbols(apiKey) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - } - } - } - - /** - * Converts the specified currencies. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - reload(properties[API_KEY_PROP]) - - when { - SYMBOLS.isEmpty() -> { - event.respond(EMPTY_SYMBOLS_TABLE) - } - - args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ (to|in) [a-zA-Z]{3}+".toRegex()) -> { - val msg = convertCurrency(properties[API_KEY_PROP], args) - event.respond(msg.msg) - if (msg.isError) { - helpResponse(event) - } - } - - args.contains(CODES_KEYWORD) -> { - event.sendMessage("The supported currency codes are:") - event.sendList(SYMBOLS.keys.toList(), 11, isIndent = true) - } - - else -> { - helpResponse(event) - } - } - } - - override fun helpResponse(event: GenericMessageEvent): Boolean { - reload(properties[API_KEY_PROP]) - - if (SYMBOLS.isEmpty()) { - event.sendMessage(EMPTY_SYMBOLS_TABLE) - } else { - val nick = event.bot().nick - event.sendMessage("To convert from one currency to another:") - event.sendMessage(helpFormat(helpCmdSyntax("%c $CURRENCY_CMD 100 USD to EUR", nick, isPrivateMsgEnabled))) - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD 50,000 GBP to USD", nick, isPrivateMsgEnabled) - ) - ) - event.sendMessage("To list the supported currency codes:") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD $CODES_KEYWORD", nick, isPrivateMsgEnabled) - ) - ) - } - return true - } - - companion object { - /** - * The API Key property. - */ - const val API_KEY_PROP = "exchangerate-api-key" - - // Currency command - private const val CURRENCY_CMD = "currency" - - // Currency codes keyword - private const val CODES_KEYWORD = "codes" - - // Empty symbols table. - private const val EMPTY_SYMBOLS_TABLE = "Sorry, but the currency table is empty." - - // Currency symbols - private val SYMBOLS: TreeMap<String, String> = TreeMap() - - // Decimal format - private val DECIMAL_FORMAT = DecimalFormat("0.00#") - - /** - * Converts from a currency to another. - */ - @JvmStatic - fun convertCurrency(apiKey: String?, query: String): Message { - if (apiKey.isNullOrEmpty()) { - throw ModuleException("${CURRENCY_CMD}($query)", "No Exchange Rate API key specified.") - } - - val cmds = query.split(" ") - return if (cmds.size == 4) { - if (cmds[3] == cmds[1] || "0" == cmds[0]) { - PublicMessage("You're kidding, right?") - } else { - val to = cmds[1].uppercase() - val from = cmds[3].uppercase() - if (SYMBOLS.contains(to) && SYMBOLS.contains(from)) { - try { - val amt = cmds[0].replace(",", "") - val url = URL("https://v6.exchangerate-api.com/v6/$apiKey/pair/$to/$from/$amt") - val body = url.reader().body - val json = JSONObject(body) - - if (json.getString("result") == "success") { - val result = DECIMAL_FORMAT.format(json.getDouble("conversion_result")) - PublicMessage( - "${cmds[0]} ${SYMBOLS[to]} = $result ${SYMBOLS[from]}" - ) - } else { - ErrorMessage("Sorry, an error occurred while converting the currencies.") - } - } catch (ignore: IOException) { - ErrorMessage("Sorry, an IO error occurred while converting the currencies.") - } - } else { - ErrorMessage("Sounds like monopoly money to me!") - } - } - } else { - ErrorMessage("Invalid query. Let's try again.") - } - } - - /** - * Loads the currency ISO symbols. - */ - @JvmStatic - @Throws(ModuleException::class) - fun loadSymbols(apiKey: String?) { - if (!apiKey.isNullOrEmpty()) { - try { - val url = URL("https://v6.exchangerate-api.com/v6/$apiKey/codes") - val json = JSONObject(url.reader().body) - if (json.getString("result") == "success") { - val codes = json.getJSONArray("supported_codes") - for (i in 0 until codes.length()) { - val code = codes.getJSONArray(i) - SYMBOLS[code.getString(0)] = code.getString(1) - } - } - } catch (e: IOException) { - throw ModuleException( - "loadCodes(): IOE", - "An IO error has occurred while retrieving the currencies.", - e - ) - } - } - } - } - - init { - commands.add(CURRENCY_CMD) - initProperties(API_KEY_PROP) - loadSymbols(properties[ChatGpt.API_KEY_PROP]) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Dice.kt b/bin/main/net/thauvin/erik/mobibot/modules/Dice.kt deleted file mode 100644 index 8420fb1..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Dice.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Dice.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - -/** - * The Dice module. - */ -class Dice : AbstractModule() { - override val name = "Dice" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - val arg = if (args.isBlank()) "2d6" else args.trim() - val match = Regex("^([1-9]|[12]\\d|3[0-2])[dD]([1-9]|[12]\\d|3[0-2])$").find(arg) - if (match != null) { - val (dice, sides) = match.destructured - event.respond("you rolled " + roll(dice.toInt(), sides.toInt())) - } else { - helpResponse(event) - } - } - - companion object { - // Dice command - private const val DICE_CMD = "dice" - - @JvmStatic - fun roll(dice: Int, sides: Int): String { - val result = StringBuilder() - var total = 0 - - repeat(dice) { - val roll = (1..sides).random() - total += roll - - if (result.isNotEmpty()) { - result.append(" + ") - } - - result.append(roll.bold()) - } - - if (dice != 1) { - result.append(" = ${total.bold()}") - } - - return result.toString() - } - } - - init { - commands.add(DICE_CMD) - help.add("To roll 2 dice with 6 sides:") - help.add(helpFormat("%c $DICE_CMD [2d6]")) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt deleted file mode 100644 index f426d1e..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ /dev/null @@ -1,162 +0,0 @@ -/* - * GoogleSearch.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.ReleaseInfo -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.colorize -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.unescapeXml -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.NoticeMessage -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 : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(GoogleSearch::class.java) - - override val name = "GoogleSearch" - - /** - * Searches Google. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val results = searchGoogle( - args, - properties[API_KEY_PROP], - properties[CSE_KEY_PROP], - event.user.nick - ) - for (msg in results) { - if (msg.isError) { - event.respond(msg.msg.colorize(msg.color)) - } else { - event.sendMessage(channel, msg) - } - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - // Google API Key property - const val API_KEY_PROP = "google-api-key" - - // Google Custom Search Engine ID property - const val CSE_KEY_PROP = "google-cse-cx" - - // Google command - private const val GOOGLE_CMD = "google" - - /** - * Performs a search on Google. - */ - @JvmStatic - @Throws(ModuleException::class) - fun searchGoogle( - query: String, - apiKey: String?, - cseKey: String?, - quotaUser: String = ReleaseInfo.PROJECT - ): List<Message> { - if (apiKey.isNullOrBlank() || cseKey.isNullOrBlank()) { - throw ModuleException( - "${GoogleSearch::class.java.name} is disabled.", - "${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing." - ) - } - val results = mutableListOf<Message>() - if (query.isNotBlank()) { - try { - val url = URL( - "https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" + - ""aUser=${quotaUser}&q=${query.encodeUrl()}&filter=1&num=5&alt=json" - ) - val json = JSONObject(url.reader().body) - if (json.has("items")) { - val ja = json.getJSONArray("items") - for (i in 0 until ja.length()) { - val j = ja.getJSONObject(i) - results.add(NoticeMessage(j.getString("title").unescapeXml())) - results.add(NoticeMessage(helpFormat(j.getString("link"), false), Colors.DARK_GREEN)) - } - } else if (json.has("error")) { - val error = json.getJSONObject("error") - val message = error.getString("message") - throw ModuleException("searchGoogle($query): ${error.getInt("code")} : $message", message) - } else { - results.add(ErrorMessage("No results found.", Colors.RED)) - } - } catch (e: IOException) { - throw ModuleException("searchGoogle($query): IOE", "An IO error has occurred searching Google.", e) - } catch (e: JSONException) { - throw ModuleException( - "searchGoogle($query): JSON", - "A JSON error has occurred searching Google.", - e - ) - } - } else { - results.add(ErrorMessage("Invalid query. Please try again.")) - } - return results - } - } - - init { - commands.add(GOOGLE_CMD) - help.add("To search Google:") - help.add(helpFormat("%c $GOOGLE_CMD <query>")) - initProperties(API_KEY_PROP, CSE_KEY_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Joke.kt b/bin/main/net/thauvin/erik/mobibot/modules/Joke.kt deleted file mode 100644 index 2760fa7..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Joke.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Joke.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.jokeapi.exceptions.HttpErrorException -import net.thauvin.erik.jokeapi.exceptions.JokeException -import net.thauvin.erik.jokeapi.joke -import net.thauvin.erik.jokeapi.models.Type -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.colorize -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.PublicMessage -import org.json.JSONException -import org.pircbotx.Colors -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException - -/** - * The Joke module. - */ -class Joke : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Joke::class.java) - - override val name = "Joke" - - /** - * Returns a random joke from [JokeAPI](https://v2.jokeapi.dev/). - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - with(event.bot()) { - try { - randomJoke().forEach { - sendIRC().notice(channel, it.msg.colorize(it.color)) - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } - } - - companion object { - // Joke command - private const val JOKE_CMD = "joke" - - /** - * Retrieves a random joke. - */ - @JvmStatic - @Throws(ModuleException::class) - fun randomJoke(): List<Message> { - return try { - val joke = joke(safe = true, type = Type.SINGLE, splitNewLine = true) - joke.joke.map { PublicMessage(it, Colors.CYAN) } - } catch (e: JokeException) { - throw ModuleException("randomJoke(): ${e.additionalInfo}", e.message, e) - } catch (e: HttpErrorException) { - throw ModuleException("randomJoke(): HTTP: ${e.statusCode}", e.message, e) - } catch (e: IOException) { - throw ModuleException("randomJoke(): IOE", "An IO error has occurred retrieving a random joke.", e) - } catch (e: JSONException) { - throw ModuleException("randomJoke(): JSON", "A parsing error has occurred retrieving a random joke.", e) - } - } - } - - init { - commands.add(JOKE_CMD) - help.add("To display a random joke:") - help.add(helpFormat("%c $JOKE_CMD")) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt b/bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt deleted file mode 100644 index 9ab2ead..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Lookup.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Lookup.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Constants -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 - -/** - * The Lookup module. - */ -class Lookup : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Lookup::class.java) - - override val name = "Lookup" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.matches("(\\S.)+(\\S)+".toRegex())) { - 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]?)\\.){3}(?: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 { - event.respond("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(event) - } - } - - companion object { - /** - * The whois default host. - */ - const val WHOIS_HOST = "whois.arin.net" - - // Lookup command - private const val LOOKUP_CMD = "lookup" - - /** - * Performs a DNS lookup on the specified query. - */ - @JvmStatic - @Throws(UnknownHostException::class) - fun nslookup(query: String): String { - val buffer = StringBuilder() - val results = InetAddress.getAllByName(query) - var hostInfo: String - for (result in results) { - if (result.hostAddress == query) { - hostInfo = result.hostName - if (hostInfo == query) { - throw UnknownHostException() - } - } else { - hostInfo = result.hostAddress - } - if (buffer.isNotEmpty()) { - buffer.append(", ") - } - buffer.append(hostInfo) - } - return buffer.toString() - } - - /** - * Performs a whois IP query. - */ - @Throws(IOException::class) - private fun whois(query: String): List<String> { - return whois(query, WHOIS_HOST) - } - - /** - * Performs a whois IP query. - */ - @JvmStatic - @Throws(IOException::class) - fun whois(query: String, host: String): List<String> { - val whoisClient = WhoisClient() - val lines: List<String> - with(whoisClient) { - try { - defaultTimeout = Constants.CONNECT_TIMEOUT - connect(host) - soTimeout = Constants.CONNECT_TIMEOUT - setSoLinger(false, 0) - lines = if (WHOIS_HOST == host) { - query("n - $query").split("\n") - } else { - query(query).split("\n") - } - } finally { - disconnect() - } - } - return lines - } - } - - init { - commands.add(LOOKUP_CMD) - help.add("To perform a DNS lookup query:") - help.add(helpFormat("%c $LOOKUP_CMD <ip address or hostname>")) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt b/bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt deleted file mode 100644 index 3be3a5f..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Mastodon.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.prefixIfMissing -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.social.SocialModule -import org.json.JSONException -import org.json.JSONObject -import org.json.JSONWriter -import java.io.IOException -import java.net.URI -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse - -class Mastodon : SocialModule() { - override val name = "Mastodon" - - override val handle: String? - get() = properties[HANDLE_PROP] - - override val isAutoPost: Boolean - get() = isEnabled && properties[AUTO_POST_PROP].toBoolean() - - override val isValidProperties: Boolean - get() = !(properties[INSTANCE_PROP].isNullOrBlank() || properties[ACCESS_TOKEN_PROP].isNullOrBlank()) - - /** - * 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}" } - } - - /** - * Posts on Mastodon. - */ - @Throws(ModuleException::class) - override fun post(message: String, isDm: Boolean): String { - return toot( - apiKey = properties[ACCESS_TOKEN_PROP], - instance = properties[INSTANCE_PROP], - handle = handle, - message = message, - isDm = isDm - ) - } - - companion object { - // Property keys - const val ACCESS_TOKEN_PROP = "mastodon-access-token" - const val AUTO_POST_PROP = "mastodon-auto-post" - const val HANDLE_PROP = "mastodon-handle" - const val INSTANCE_PROP = "mastodon-instance" - - private const val MASTODON_CMD = "mastodon" - private const val TOOT_CMD = "toot" - - /** - * Post on Mastodon. - */ - @JvmStatic - @Throws(ModuleException::class) - fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String { - val request = HttpRequest.newBuilder() - .uri(URI.create("https://$instance/api/v1/statuses")) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer $apiKey") - .POST( - HttpRequest.BodyPublishers.ofString( - JSONWriter.valueToString( - if (isDm) { - mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct") - } else { - mapOf("status" to message) - } - ) - ) - ) - .build() - try { - val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) - if (response.statusCode() == 200) { - return try { - val jsonResponse = JSONObject(response.body()) - if (isDm) { - jsonResponse.getString("content") - } else { - "Your message was posted to ${jsonResponse.getString("url")}" - } - } catch (e: JSONException) { - throw ModuleException("mastodonPost($message)", "A JSON error has occurred: ${e.message}", e) - } - } else { - throw IOException("Status Code: " + response.statusCode()) - } - } catch (e: IOException) { - throw ModuleException("mastodonPost($message)", "An IO error has occurred: ${e.message}", e) - } catch (e: InterruptedException) { - throw ModuleException("mastodonPost($message)", "An error has occurred: ${e.message}", e) - } - } - } - - init { - commands.add(MASTODON_CMD) - commands.add(TOOT_CMD) - help.add("To toot on Mastodon:") - help.add(Utils.helpFormat("%c $TOOT_CMD <message>")) - properties[AUTO_POST_PROP] = "false" - initProperties(ACCESS_TOKEN_PROP, HANDLE_PROP, INSTANCE_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt b/bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt deleted file mode 100644 index a7416c2..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/ModuleException.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ModuleException.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -/** - * The `ModuleException` class. - */ -class ModuleException @JvmOverloads constructor( - val debugMessage: String, - message: String? = null, - cause: Throwable? = null -) : Exception(message, cause) { - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 1L - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Ping.kt b/bin/main/net/thauvin/erik/mobibot/modules/Ping.kt deleted file mode 100644 index 944dbc1..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Ping.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Ping.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - -/** - * The Ping module. - */ -class Ping : AbstractModule() { - override val name = "Ping" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - event.bot().sendIRC().action(channel, randomPing()) - } - - companion object { - /** - * The ping responses. - */ - @JvmField - val PINGS = listOf( - "is barely alive.", - "is trying to stay awake.", - "has gone fishing.", - "is somewhere over the rainbow.", - "has fallen and can't get up.", - "is running. You better go chase it.", - "has just spontaneously combusted.", - "is talking to itself... don't interrupt. That's rude.", - "is bartending at an AA meeting.", - "is hibernating.", - "is saving energy: apathetic mode activated.", - "is busy. Go away!" - ) - - @JvmStatic - fun randomPing(): String { - return PINGS[PINGS.indices.random()] - } - - /** - * The ping command. - */ - private const val PING_CMD = "ping" - } - - init { - commands.add(PING_CMD) - help.add("To ping the bot:") - help.add(helpFormat("%c $PING_CMD")) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt deleted file mode 100644 index a299d8d..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * RockPaperScissors.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - - -/** - * Simple module example in Kotlin. - */ -class RockPaperScissors : AbstractModule() { - override val name = "RockPaperScissors" - - init { - with(commands) { - add(Hands.ROCK.name.lowercase()) - add(Hands.PAPER.name.lowercase()) - add(Hands.SCISSORS.name.lowercase()) - } - - with(help) { - add("To play Rock Paper Scissors:") - add( - helpFormat( - "%c ${Hands.ROCK.name.lowercase()} | ${Hands.PAPER.name.lowercase()}" - + " | ${Hands.SCISSORS.name.lowercase()}" - ) - ) - } - } - - enum class Hands(val action: String) { - ROCK("crushes") { - override fun beats(hand: Hands): Boolean { - return hand == SCISSORS - } - }, - PAPER("covers") { - override fun beats(hand: Hands): Boolean { - return hand == ROCK - } - }, - SCISSORS("cuts") { - override fun beats(hand: Hands): Boolean { - return hand == PAPER - } - }; - - abstract fun beats(hand: Hands): Boolean - } - - companion object { - // For testing. - fun winLoseOrDraw(player: String, bot: String): String { - val hand = Hands.valueOf(player.uppercase()) - val botHand = Hands.valueOf(bot.uppercase()) - - return when { - hand == botHand -> "draw" - hand.beats(botHand) -> "win" - else -> "lose" - } - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - val hand = Hands.valueOf(cmd.uppercase()) - val botHand = Hands.entries[(0..Hands.entries.size).random()] - when { - hand == botHand -> { - event.respond("${hand.name} vs. ${botHand.name} » You ${"tie".bold()}.") - } - - hand.beats(botHand) -> { - event.respond("${hand.name.bold()} ${hand.action} ${botHand.name} » You ${"win".bold()}!") - } - - else -> { - event.respond("${botHand.name.bold()} ${botHand.action} ${hand.name} » You ${"lose".bold()}!") - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt b/bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt deleted file mode 100644 index dcae5e7..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ /dev/null @@ -1,236 +0,0 @@ -/* - * StockQuote.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.unescapeXml -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.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 : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(StockQuote::class.java) - - override val name = "StockQuote" - - /** - * Returns the specified stock quote from Alpha Vantage. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val messages = getQuote(args, properties[API_KEY_PROP]) - for (msg in messages) { - event.sendMessage(channel, msg) - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The API property key. - */ - const val API_KEY_PROP = "alphavantage-api-key" - - /** - * The Invalid Symbol error string. - */ - const val INVALID_SYMBOL = "Invalid symbol." - - // API URL - private const val API_URL = "https://www.alphavantage.co/query?function=" - - // Quote command - private const val STOCK_CMD = "stock" - - @Throws(ModuleException::class) - private fun getJsonResponse(response: String, debugMessage: String): JSONObject { - return if (response.isNotBlank()) { - val json = JSONObject(response) - try { - val info = json.getString("Information") - if (info.isNotEmpty()) { - throw ModuleException(debugMessage, info.unescapeXml()) - } - } catch (ignore: JSONException) { - // Do nothing - } - try { - var error = json.getString("Note") - if (error.isNotEmpty()) { - throw ModuleException(debugMessage, error.unescapeXml()) - } - error = json.getString("Error Message") - if (error.isNotEmpty()) { - throw ModuleException(debugMessage, error.unescapeXml()) - } - } catch (ignore: JSONException) { - // Do nothing - } - json - } else { - throw ModuleException(debugMessage, "Empty Response.") - } - } - - /** - * Retrieves a stock quote. - */ - @JvmStatic - @Throws(ModuleException::class) - fun getQuote(symbol: String, apiKey: String?): List<Message> { - if (apiKey.isNullOrBlank()) { - throw ModuleException( - "${StockQuote::class.java.name} is disabled.", - "${STOCK_CMD.capitalise()} is disabled. The API key is missing." - ) - } - val messages = mutableListOf<Message>() - if (symbol.isNotBlank()) { - val debugMessage = "getQuote($symbol)" - var response: String - try { - with(messages) { - // Search for symbol/keywords - response = URL( - "${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" - + apiKey.encodeUrl() - ).reader().body - var json = getJsonResponse(response, debugMessage) - val symbols = json.getJSONArray("bestMatches") - if (symbols.isEmpty) { - messages.add(ErrorMessage(INVALID_SYMBOL)) - } else { - val symbolInfo = symbols.getJSONObject(0) - - // Get quote for symbol - response = URL( - "${API_URL}GLOBAL_QUOTE&symbol=" - + symbolInfo.getString("1. symbol").encodeUrl() + "&apikey=" - + apiKey.encodeUrl() - ).reader().body - json = getJsonResponse(response, debugMessage) - val quote = json.getJSONObject("Global Quote") - if (quote.isEmpty) { - add(ErrorMessage(INVALID_SYMBOL)) - } else { - - add( - PublicMessage( - "Symbol: " + quote.getString("01. symbol").unescapeXml() - + " [" + symbolInfo.getString("2. name").unescapeXml() + ']' - ) - ) - - val pad = 10 - - add( - PublicMessage( - "Price:".padEnd(pad).prependIndent() - + quote.getString("05. price").unescapeXml() - ) - ) - add( - PublicMessage( - "Previous:".padEnd(pad).prependIndent() - + quote.getString("08. previous close").unescapeXml() - ) - ) - - 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() - + quote.getString(it.second).unescapeXml() - ) - ) - } - - add( - NoticeMessage( - "Change:".padEnd(pad).prependIndent() - + quote.getString("09. change").unescapeXml() - + " [" + quote.getString("10. change percent").unescapeXml() + ']' - ) - ) - } - } - } - } catch (e: IOException) { - throw ModuleException("$debugMessage: IOE", "An IO error has occurred retrieving a stock quote.", e) - } catch (e: NullPointerException) { - throw ModuleException("$debugMessage: NPE", "An error has occurred retrieving a stock quote.", e) - } - } else { - messages.add(ErrorMessage(INVALID_SYMBOL)) - } - return messages - } - } - - init { - commands.add(STOCK_CMD) - help.add("To retrieve a stock quote:") - help.add(helpFormat("%c $STOCK_CMD <symbol|keywords>")) - initProperties(API_KEY_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/War.class b/bin/main/net/thauvin/erik/mobibot/modules/War.class deleted file mode 100644 index 6c36e54..0000000 Binary files a/bin/main/net/thauvin/erik/mobibot/modules/War.class and /dev/null differ diff --git a/bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt b/bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt deleted file mode 100644 index 80a06fa..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/Weather2.kt +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Weather2.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.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.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.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 : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Weather2::class.java) - - override val name = "Weather" - - /** - * Fetches the weather data from a specific city. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val messages = getWeather(args, properties[API_KEY_PROP]) - if (messages[0].isError) { - helpResponse(event) - } else { - for (msg in messages) { - event.sendMessage(channel, msg) - } - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The OpenWeatherMap API Key property. - */ - const val API_KEY_PROP = "owm-api-key" - - // Weather command - private const val WEATHER_CMD = "weather" - - /** - * Converts and rounds temperature from °F to °C. - */ - fun ftoC(d: Double): Pair<Int, Int> { - val c = (d - 32) * 5 / 9 - return d.roundToInt() to c.roundToInt() - } - - /** - * Returns a country based on its country code. Defaults to [Country.UNITED_STATES] if not found. - */ - fun getCountry(countryCode: String): Country { - for (c in Country.entries) { - if (c.value.equals(countryCode, ignoreCase = true)) { - return c - } - } - return Country.UNITED_STATES - } - - /** - * Retrieves the weather data. - */ - @JvmStatic - @Throws(ModuleException::class) - fun getWeather(query: String, apiKey: String?): List<Message> { - if (apiKey.isNullOrBlank()) { - throw ModuleException( - "${Weather2::class.java.name} is disabled.", - "${WEATHER_CMD.capitalise()} is disabled. The API key is missing." - ) - } - val owm = OWM(apiKey) - val messages = mutableListOf<Message>() - owm.unit = OWM.Unit.IMPERIAL - if (query.isNotBlank()) { - val argv = query.split(",") - if (argv.size in 1..2) { - val city = argv[0].trim() - val code: String = if (argv.size > 1 && argv[1].isNotBlank()) { - argv[1].trim() - } else { - "US" - } - try { - val country = getCountry(code) - val cwd: CurrentWeather = if (city.matches("\\d+".toRegex())) { - owm.currentWeatherByZipCode(city.toInt(), country) - } else { - owm.currentWeatherByCityName(city, country) - } - if (cwd.hasCityName()) { - messages.add( - PublicMessage( - "City: ${cwd.cityName}, " + - country.name.replace('_', ' ').capitalizeWords() + " [${country.value}]" - ) - ) - cwd.mainData?.let { - with(it) { - if (hasTemp()) { - temp?.let { t -> - val (f, c) = ftoC(t) - messages.add(PublicMessage("Temperature: ${f}°F, ${c}°C")) - } - } - if (hasHumidity()) { - humidity?.let { h -> - messages.add(NoticeMessage("Humidity: ${h.roundToInt()}%")) - } - } - } - } - if (cwd.hasWindData()) { - cwd.windData?.let { - if (it.hasSpeed()) { - it.speed?.let { s -> - val w = mphToKmh(s) - messages.add(NoticeMessage("Wind: ${w.first} mph, ${w.second} km/h")) - } - } - } - } - if (cwd.hasWeatherList()) { - val condition = StringBuilder("Condition:") - cwd.weatherList?.let { - for (w in it) { - w?.let { - condition.append(' ') - .append(w.getDescription().capitalise()) - .append('.') - } - } - messages.add(NoticeMessage(condition.toString())) - } - } - if (cwd.hasCityId()) { - cwd.cityId?.let { - if (it > 0) { - messages.add( - NoticeMessage("https://openweathermap.org/city/$it", Colors.GREEN) - ) - } else { - messages.add( - NoticeMessage( - "https://openweathermap.org/find?q=" - + "$city,${code.uppercase()}".encodeUrl(), - Colors.GREEN - ) - ) - } - } - } - } - } catch (e: APIException) { - if (e.code == 404) { - throw ModuleException( - "getWeather($query): API ${e.code}", - "The requested city was not found.", - e - ) - } else { - throw ModuleException("getWeather($query): API ${e.code}", e.message, e) - } - } catch (e: NullPointerException) { - throw ModuleException("getWeather($query): NPE", "Unable to perform weather lookup.", e) - } - } - } - if (messages.isEmpty()) { - messages.add(ErrorMessage("Invalid syntax.")) - } - return messages - } - - /** - * Converts and rounds temperature from mph to km/h. - */ - fun mphToKmh(w: Double): Pair<Int, Int> { - val kmh = w * 1.60934 - return w.roundToInt() to kmh.roundToInt() - } - } - - init { - commands.add(WEATHER_CMD) - with(help) { - add("To display weather information:") - add(helpFormat("%c $WEATHER_CMD <city> [, <country code>]")) - add("For example:") - add(helpFormat("%c $WEATHER_CMD paris, fr")) - add("The default ISO 3166 country code is ${"US".bold()}. Zip codes supported in most countries.") - } - initProperties(API_KEY_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt deleted file mode 100644 index a72efab..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * WolframAlpha.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.isHttpSuccess -import net.thauvin.erik.mobibot.Utils.reader -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 -import java.net.URL - -class WolframAlpha : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(WolframAlpha::class.java) - - override val name = "WolframAlpha" - - private fun getUnits(unit: String?): String { - return if (unit?.lowercase() == METRIC) { - METRIC - } else { - IMPERIAL - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val query = args.trim().split("units=", limit = 2, ignoreCase = true) - event.sendMessage( - queryWolfram( - query[0].trim(), - units = if (query.size == 2) { - getUnits(query[1].trim()) - } else { - getUnits(properties[UNITS_PROP]) - }, - appId = properties[APPID_KEY_PROP] - ) - ) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The Wolfram Alpha API Key property. - */ - const val APPID_KEY_PROP = "wolfram-appid" - - /** - * The Wolfram units properties - */ - const val UNITS_PROP = "wolfram-units" - - const val METRIC = "metric" - const val IMPERIAL = "imperial" - - // Wolfram command - private const val WOLFRAM_CMD = "wolfram" - - // Wolfram Alpha API URL - private const val API_URL = "http://api.wolframalpha.com/v1/spoken?appid=" - - @JvmStatic - @Throws(ModuleException::class) - fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String { - if (!appId.isNullOrEmpty()) { - try { - val urlReader = URL("${API_URL}${appId}&units=${units}&i=" + query.encodeUrl()).reader() - if (urlReader.responseCode.isHttpSuccess()) { - return urlReader.body - } else { - throw ModuleException( - "wolfram($query): ${urlReader.responseCode} : ${urlReader.body} ", - urlReader.body.ifEmpty { - "Looks like Wolfram Alpha isn't able to answer that. (${urlReader.responseCode})" - } - ) - } - } catch (ioe: IOException) { - throw ModuleException( - "wolfram($query): IOE", "An IO Error occurred while querying Wolfram Alpha.", ioe - ) - } - } else { - throw ModuleException("wolfram($query): No API Key", "No Wolfram Alpha API key specified.") - } - } - } - - init { - commands.add(WOLFRAM_CMD) - with(help) { - add("To get answers from Wolfram Alpha:") - add(Utils.helpFormat("%c $WOLFRAM_CMD <query> [units=(${METRIC}|${IMPERIAL})]")) - add("For example:") - add(Utils.helpFormat("%c $WOLFRAM_CMD days until christmas")) - add(Utils.helpFormat("%c $WOLFRAM_CMD distance earth moon units=metric")) - } - initProperties(APPID_KEY_PROP, UNITS_PROP) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt b/bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt deleted file mode 100644 index 18072bc..0000000 --- a/bin/main/net/thauvin/erik/mobibot/modules/WorldTime.kt +++ /dev/null @@ -1,390 +0,0 @@ -/* - * WorldTime.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -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 -import java.time.temporal.ChronoField - -/** - * The WorldTime module. - */ -class WorldTime : AbstractModule() { - override val name = "WorldTime" - - companion object { - /** - * Beats (Internet Time) keyword - */ - const val BEATS_KEYWORD = ".beats" - - /** - * Supported countries - */ - val COUNTRIES_MAP = buildMap<String, String> { - put("AG", "America/Antigua") - put("AI", "America/Anguilla") - put("AE", "Asia/Dubai") - put("AD", "Europe/Andorra") - put("AKDT", "America/Anchorage") - put("AF", "Asia/Kabul") - put("AKST", "America/Anchorage") - put("AL", "Europe/Tirane") - put("AM", "Asia/Yerevan") - put("AO", "Africa/Luanda") - put("AQ", "Antarctica/South_Pole") - put("AR", "America/Argentina/Buenos_Aires") - put("AS", "Pacific/Pago_Pago") - put("AT", "Europe/Vienna") - put("AU", "Australia/Sydney") - put("AW", "America/Aruba") - put("AX", "Europe/Mariehamn") - put("AZ", "Asia/Baku") - put("BA", "Europe/Sarajevo") - put("BB", "America/Barbados") - put("BD", "Asia/Dhaka") - put("BE", "Europe/Brussels") - put("BEAT", BEATS_KEYWORD) - put("BF", "Africa/Ouagadougou") - put("BG", "Europe/Sofia") - put("BH", "Asia/Bahrain") - put("BI", "Africa/Bujumbura") - put("BJ", "Africa/Porto-Novo") - put("BL", "America/St_Barthelemy") - put("BM", "Atlantic/Bermuda") - put("BMT", BEATS_KEYWORD) - put("BN", "Asia/Brunei") - put("BO", "America/La_Paz") - put("BQ", "America/Kralendijk") - put("BR", "America/Sao_Paulo") - put("BS", "America/Nassau") - put("BT", "Asia/Thimphu") - put("BW", "Africa/Gaborone") - put("BY", "Europe/Minsk") - put("BZ", "America/Belize") - put("CA", "America/Montreal") - put("CC", "Indian/Cocos") - put("CD", "Africa/Kinshasa") - put("CDT", "America/Chicago") - put("CET", "CET") - put("CF", "Africa/Bangui") - put("CG", "Africa/Brazzaville") - put("CH", "Europe/Zurich") - put("CI", "Africa/Abidjan") - put("CK", "Pacific/Rarotonga") - put("CL", "America/Santiago") - put("CM", "Africa/Douala") - put("CN", "Asia/Shanghai") - put("CO", "America/Bogota") - put("CR", "America/Costa_Rica") - put("CST", "America/Chicago") - put("CU", "Cuba") - put("CV", "Atlantic/Cape_Verde") - put("CW", "America/Curacao") - put("CX", "Indian/Christmas") - put("CY", "Asia/Nicosia") - put("CZ", "Europe/Prague") - put("DE", "Europe/Berlin") - put("DJ", "Africa/Djibouti") - put("DK", "Europe/Copenhagen") - put("DM", "America/Dominica") - put("DO", "America/Santo_Domingo") - put("DZ", "Africa/Algiers") - put("EC", "Pacific/Galapagos") - put("EDT", "America/New_York") - put("EE", "Europe/Tallinn") - put("EG", "Africa/Cairo") - put("EH", "Africa/El_Aaiun") - put("ER", "Africa/Asmara") - put("ES", "Europe/Madrid") - put("EST", "America/New_York") - put("ET", "Africa/Addis_Ababa") - put("FI", "Europe/Helsinki") - put("FJ", "Pacific/Fiji") - put("FK", "Atlantic/Stanley") - put("FM", "Pacific/Yap") - put("FO", "Atlantic/Faroe") - put("FR", "Europe/Paris") - put("GA", "Africa/Libreville") - put("GB", "Europe/London") - put("GD", "America/Grenada") - put("GE", "Asia/Tbilisi") - put("GF", "America/Cayenne") - put("GG", "Europe/Guernsey") - put("GH", "Africa/Accra") - put("GI", "Europe/Gibraltar") - put("GL", "America/Thule") - put("GM", "Africa/Banjul") - put("GMT", "GMT") - put("GN", "Africa/Conakry") - put("GP", "America/Guadeloupe") - put("GQ", "Africa/Malabo") - put("GR", "Europe/Athens") - put("GS", "Atlantic/South_Georgia") - put("GT", "America/Guatemala") - put("GU", "Pacific/Guam") - put("GW", "Africa/Bissau") - put("GY", "America/Guyana") - put("HK", "Asia/Hong_Kong") - put("HN", "America/Tegucigalpa") - put("HR", "Europe/Zagreb") - put("HST", "Pacific/Honolulu") - put("HT", "America/Port-au-Prince") - put("HU", "Europe/Budapest") - put("ID", "Asia/Jakarta") - put("IE", "Europe/Dublin") - put("IL", "Asia/Tel_Aviv") - put("IM", "Europe/Isle_of_Man") - put("IN", "Asia/Kolkata") - put("IO", "Indian/Chagos") - put("IQ", "Asia/Baghdad") - put("IR", "Asia/Tehran") - put("IS", "Atlantic/Reykjavik") - put("IT", "Europe/Rome") - put("JE", "Europe/Jersey") - put("JM", "Jamaica") - put("JO", "Asia/Amman") - put("JP", "Asia/Tokyo") - put("KE", "Africa/Nairobi") - put("KG", "Asia/Bishkek") - put("KH", "Asia/Phnom_Penh") - put("KI", "Pacific/Tarawa") - put("KM", "Indian/Comoro") - put("KN", "America/St_Kitts") - put("KP", "Asia/Pyongyang") - put("KR", "Asia/Seoul") - put("KW", "Asia/Riyadh") - put("KY", "America/Cayman") - put("KZ", "Asia/Oral") - put("LA", "Asia/Vientiane") - put("LB", "Asia/Beirut") - put("LC", "America/St_Lucia") - put("LI", "Europe/Vaduz") - put("LK", "Asia/Colombo") - put("LR", "Africa/Monrovia") - put("LS", "Africa/Maseru") - put("LT", "Europe/Vilnius") - put("LU", "Europe/Luxembourg") - put("LV", "Europe/Riga") - put("LY", "Africa/Tripoli") - put("MA", "Africa/Casablanca") - put("MC", "Europe/Monaco") - put("MD", "Europe/Chisinau") - put("MDT", "America/Denver") - put("ME", "Europe/Podgorica") - put("MF", "America/Marigot") - put("MG", "Indian/Antananarivo") - put("MH", "Pacific/Majuro") - put("MK", "Europe/Skopje") - put("ML", "Africa/Timbuktu") - put("MM", "Asia/Yangon") - put("MN", "Asia/Ulaanbaatar") - put("MO", "Asia/Macau") - put("MP", "Pacific/Saipan") - put("MQ", "America/Martinique") - put("MR", "Africa/Nouakchott") - put("MS", "America/Montserrat") - put("MST", "America/Denver") - put("MT", "Europe/Malta") - put("MU", "Indian/Mauritius") - put("MV", "Indian/Maldives") - put("MW", "Africa/Blantyre") - put("MX", "America/Mexico_City") - put("MY", "Asia/Kuala_Lumpur") - put("MZ", "Africa/Maputo") - put("NA", "Africa/Windhoek") - put("NC", "Pacific/Noumea") - put("NE", "Africa/Niamey") - put("NF", "Pacific/Norfolk") - put("NG", "Africa/Lagos") - put("NI", "America/Managua") - put("NL", "Europe/Amsterdam") - put("NO", "Europe/Oslo") - put("NP", "Asia/Kathmandu") - put("NR", "Pacific/Nauru") - put("NU", "Pacific/Niue") - put("NZ", "Pacific/Auckland") - put("OM", "Asia/Muscat") - put("PA", "America/Panama") - put("PDT", "America/Los_Angeles") - put("PE", "America/Lima") - put("PF", "Pacific/Tahiti") - put("PG", "Pacific/Port_Moresby") - put("PH", "Asia/Manila") - put("PK", "Asia/Karachi") - put("PL", "Europe/Warsaw") - put("PM", "America/Miquelon") - put("PN", "Pacific/Pitcairn") - put("PR", "America/Puerto_Rico") - put("PS", "Asia/Gaza") - put("PST", "America/Los_Angeles") - put("PT", "Europe/Lisbon") - put("PW", "Pacific/Palau") - put("PY", "America/Asuncion") - put("QA", "Asia/Qatar") - put("RE", "Indian/Reunion") - put("RO", "Europe/Bucharest") - put("RS", "Europe/Belgrade") - put("RU", "Europe/Moscow") - put("RW", "Africa/Kigali") - put("SA", "Asia/Riyadh") - put("SB", "Pacific/Guadalcanal") - put("SC", "Indian/Mahe") - put("SD", "Africa/Khartoum") - put("SE", "Europe/Stockholm") - put("SG", "Asia/Singapore") - put("SH", "Atlantic/St_Helena") - put("SI", "Europe/Ljubljana") - put("SJ", "Atlantic/Jan_Mayen") - put("SK", "Europe/Bratislava") - put("SL", "Africa/Freetown") - put("SM", "Europe/San_Marino") - put("SN", "Africa/Dakar") - put("SO", "Africa/Mogadishu") - put("SR", "America/Paramaribo") - put("SS", "Africa/Juba") - put("ST", "Africa/Sao_Tome") - put("SV", "America/El_Salvador") - put("SX", "America/Lower_Princes") - put("SY", "Asia/Damascus") - put("SZ", "Africa/Mbabane") - put("TC", "America/Grand_Turk") - put("TD", "Africa/Ndjamena") - put("TF", "Indian/Kerguelen") - put("TG", "Africa/Lome") - put("TH", "Asia/Bangkok") - put("TJ", "Asia/Dushanbe") - put("TK", "Pacific/Fakaofo") - put("TL", "Asia/Dili") - put("TM", "Asia/Ashgabat") - put("TN", "Africa/Tunis") - put("TO", "Pacific/Tongatapu") - put("TR", "Europe/Istanbul") - put("TT", "America/Port_of_Spain") - put("TV", "Pacific/Funafuti") - put("TW", "Asia/Taipei") - put("TZ", "Africa/Dar_es_Salaam") - put("UA", "Europe/Kiev") - put("UG", "Africa/Kampala") - put("UK", "Europe/London") - put("UM", "Pacific/Wake") - put("US", "America/New_York") - put("UTC", "UTC") - put("UY", "America/Montevideo") - put("UZ", "Asia/Tashkent") - put("VA", "Europe/Vatican") - put("VC", "America/St_Vincent") - put("VE", "America/Caracas") - put("VG", "America/Tortola") - put("VI", "America/St_Thomas") - put("VN", "Asia/Ho_Chi_Minh") - put("VU", "Pacific/Efate") - put("WF", "Pacific/Wallis") - put("WS", "Pacific/Apia") - put("YE", "Asia/Aden") - put("YT", "Indian/Mayotte") - put("ZA", "Africa/Johannesburg") - put("ZM", "Africa/Lusaka") - put("ZULU", "Zulu") - put("ZW", "Africa/Harare") - ZoneId.getAvailableZoneIds().filter { it.length <= 3 && !containsKey(it) } - .forEach { tz -> put(tz, tz) } - } - - // 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 ${"'HH:mm'".bold()} on ${"'EEEE, d MMMM yyyy'".bold()} in '") - - /** - * Returns the current Internet (beat) Time. - */ - 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 "%c%03d".format('@', beats) - } - - /** - * Returns the time for the given timezone/city. - */ - @JvmStatic - 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 ${internetTime().bold()} $BEATS_KEYWORD" - } else { - (ZonedDateTime.now().withZoneSameInstant(ZoneId.of(tz)).format(dtf) - + tz.substring(tz.lastIndexOf('/') + 1).replace('_', ' ').bold()) - } - } else { - "Unsupported country/zone. Please try again." - } - } - } - - 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)) - } - } - - override val isPrivateMsgEnabled = true - - init { - with(help) { - add("To display a country's current date/time:") - add(helpFormat("%c $TIME_CMD [<country code or zone>]")) - add("For a listing of the supported countries/zones:") - add(helpFormat("%c $TIME_CMD $ZONES_ARGS")) - } - commands.add(TIME_CMD) - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt deleted file mode 100644 index 0607936..0000000 --- a/bin/main/net/thauvin/erik/mobibot/msg/ErrorMessage.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ErrorMessage.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.msg - -/** - * The `ErrorMessage` class. - */ -class ErrorMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isError = true) diff --git a/bin/main/net/thauvin/erik/mobibot/msg/Message.kt b/bin/main/net/thauvin/erik/mobibot/msg/Message.kt deleted file mode 100644 index 23a33b9..0000000 --- a/bin/main/net/thauvin/erik/mobibot/msg/Message.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Message.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.msg - -import net.thauvin.erik.semver.Constants - -/** - * The `Message` class. - */ -open class Message @JvmOverloads constructor( - var msg: String, - var color: String = DEFAULT_COLOR, - var isNotice: Boolean = false, - isError: Boolean = false, - var isPrivate: Boolean = false -) { - companion object { - var DEFAULT_COLOR = Constants.EMPTY - } - - init { - if (isError) { - isNotice = true - } - } - - /** Error flag. */ - var isError = isError - set(value) { - if (value) isNotice = true - field = value - } - - override fun toString(): String { - return "Message(color='$color', isError=$isError, isNotice=$isNotice, isPrivate=$isPrivate, msg='$msg')" - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt deleted file mode 100644 index 037d504..0000000 --- a/bin/main/net/thauvin/erik/mobibot/msg/NoticeMessage.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * NoticeMessage.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.msg - -/** - * The `NoticeMessage` class. - */ -class NoticeMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isNotice = true) - diff --git a/bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt deleted file mode 100644 index b424fdf..0000000 --- a/bin/main/net/thauvin/erik/mobibot/msg/PrivateMessage.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * PrivateMessage.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.msg - -/** - * The `PrivateMessage` class. - */ -class PrivateMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isPrivate = true) diff --git a/bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt b/bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt deleted file mode 100644 index 9c5e088..0000000 --- a/bin/main/net/thauvin/erik/mobibot/msg/PublicMessage.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * PublicMessage.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.msg - -/** - * The `PublicMessage` class. - */ -class PublicMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : Message(msg, color) diff --git a/bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt b/bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt deleted file mode 100644 index 91f2dd9..0000000 --- a/bin/main/net/thauvin/erik/mobibot/social/SocialManager.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * SocialManager.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.social - -import net.thauvin.erik.mobibot.Addons -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.util.* - -/** - * Social Manager. - */ -class SocialManager { - private val entries: MutableSet<Int> = HashSet() - private val logger: Logger = LoggerFactory.getLogger(SocialManager::class.java) - private val modules = ArrayList<SocialModule>() - private val timer = Timer(true) - - /** - * Adds social modules. - */ - fun add(addons: Addons, vararg modules: SocialModule) { - modules.forEach { - if (addons.add(it)) { - this.modules.add(it) - } - } - } - - /** - * Returns the number of entries. - */ - fun entriesCount(): Int = entries.size - - /** - * Sends a social notification (dm, etc.) - */ - fun notification(msg: String) { - modules.forEach { - it.notification(msg) - } - } - - /** - * Posts to social media. - */ - fun postEntry(index: Int) { - if (entries.contains(index)) { - modules.forEach { - it.postEntry(index) - } - entries.remove(index) - } - } - - /** - * Queues an entry for posting to social media. - */ - fun queueEntry(index: Int) { - if (modules.isNotEmpty()) { - entries.add(index) - if (logger.isDebugEnabled) { - logger.debug("Scheduling {} for posting on social media.", index.toLinkLabel()) - } - timer.schedule(SocialTimer(this, index), Constants.TIMER_DELAY * 60L * 1000L) - } - } - - /** - * Removes entries from queue. - */ - fun removeEntry(index: Int) { - entries.remove(index) - } - - /** - * Posts all entries on shutdown. - */ - fun shutdown() { - timer.cancel() - entries.forEach { - postEntry(it) - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt b/bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt deleted file mode 100644 index b594670..0000000 --- a/bin/main/net/thauvin/erik/mobibot/social/SocialModule.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SocialModule.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.social - -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 org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -abstract class SocialModule : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(SocialManager::class.java) - - abstract val handle: String? - abstract val isAutoPost: Boolean - - abstract fun formatEntry(entry: EntryLink): String - - /** - * Sends a DM. - */ - 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) - } - } - } - - abstract fun post(message: String, isDm: Boolean): String - - /** - * Post entry to social media. - */ - fun postEntry(index: Int) { - if (isAutoPost && LinksManager.entries.links.size >= index) { - 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 - ) - } - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - try { - event.respond(post("$args (by ${event.user.nick} on $channel)", false)) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } -} diff --git a/bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt b/bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt deleted file mode 100644 index 3fd315e..0000000 --- a/bin/main/net/thauvin/erik/mobibot/social/SocialTimer.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SocialTimer.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.social - -import java.util.* - -class SocialTimer(private var socialManager: SocialManager, private var index: Int) : TimerTask() { - override fun run() { - socialManager.postEntry(index) - } -} diff --git a/bin/test/current.xml b/bin/test/current.xml deleted file mode 100644 index 535a400..0000000 --- a/bin/test/current.xml +++ /dev/null @@ -1,67 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ~ current.xml - ~ - ~ Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - ~ - ~ Redistribution and use in source and binary forms, with or without - ~ modification, are permitted provided that the following conditions are met: - ~ - ~ Redistributions of source code must retain the above copyright notice, this - ~ list of conditions and the following disclaimer. - ~ - ~ Redistributions in binary form must reproduce the above copyright notice, - ~ this list of conditions and the following disclaimer in the documentation - ~ and/or other materials provided with the distribution. - ~ - ~ Neither the name of this project nor the names of its contributors may be - ~ used to endorse or promote products derived from this software without - ~ specific prior written permission. - ~ - ~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - ~ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - ~ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - ~ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - ~ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - ~ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - ~ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - ~ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - ~ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - ~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - --> - -<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"> - <channel> - <title>#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/bin/test/net/thauvin/erik/mobibot/AddonsTest.kt b/bin/test/net/thauvin/erik/mobibot/AddonsTest.kt deleted file mode 100644 index afb8ce6..0000000 --- a/bin/test/net/thauvin/erik/mobibot/AddonsTest.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * AddonsTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot - -import assertk.assertThat -import assertk.assertions.containsExactly -import assertk.assertions.isEqualTo -import assertk.assertions.size -import net.thauvin.erik.mobibot.commands.ChannelFeed -import net.thauvin.erik.mobibot.commands.Cycle -import net.thauvin.erik.mobibot.commands.Die -import net.thauvin.erik.mobibot.commands.Ignore -import net.thauvin.erik.mobibot.commands.links.Comment -import net.thauvin.erik.mobibot.commands.links.View -import net.thauvin.erik.mobibot.modules.* -import kotlin.test.Test -import java.util.* - -class AddonsTest { - private val p = Properties().apply { - put("disabled-modules", "war,dice Lookup") - put("disabled-commands", "View | comment") - } - private val addons = Addons(p) - - @Test - fun addTest() { - // Modules - addons.add(Joke()) - addons.add(RockPaperScissors()) - addons.add(War()) - addons.add(Dice()) - addons.add(Lookup()) - assertThat(addons::modules).size().isEqualTo(2) - assertThat(addons.names.modules, "names.modules").containsExactly("Joke", "RockPaperScissors") - - // Commands - addons.add(View()) - addons.add(Comment()) - addons.add(Cycle()) - addons.add(Die()) // invisible - addons.add(ChannelFeed("channel")) // no properties, disabled - p[Ignore.IGNORE_PROP] = "nick" - addons.add(Ignore()) - assertThat(addons::commands).size().isEqualTo(3) - - assertThat(addons.names.ops, "names.ops").containsExactly("cycle") - - assertThat(addons.names.commands, "names.command").containsExactly( - "joke", - "rock", - "paper", - "scissors", - "ignore" - ) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt deleted file mode 100644 index a3994ec..0000000 --- a/bin/test/net/thauvin/erik/mobibot/ExceptionSanitizer.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ExceptionSanitizer.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot - -import net.thauvin.erik.mobibot.Utils.obfuscate -import net.thauvin.erik.mobibot.Utils.replaceEach -import net.thauvin.erik.mobibot.modules.ModuleException - -object ExceptionSanitizer { - /** - * Returns a sanitized exception to avoid displaying api keys, etc. in CI logs. - */ - 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(this) { - if (!cause?.message.isNullOrBlank()) { - return ModuleException( - debugMessage, - cause?.javaClass?.name + ": " + cause?.message?.replaceEach(search, obfuscate), - this - ) - } else if (!message.isNullOrBlank()) { - return ModuleException(debugMessage, message?.replaceEach(search, obfuscate), this) - } - } - } - return this - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt b/bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt deleted file mode 100644 index 6e5fa8f..0000000 --- a/bin/test/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * FeedReaderTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import com.rometools.rome.io.FeedException -import net.thauvin.erik.mobibot.FeedReader.Companion.readFeed -import net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test -import java.io.IOException -import java.net.MalformedURLException -import java.net.UnknownHostException - -/** - * The `FeedReader Test` class. - */ -class FeedReaderTest { - @Test - fun readFeedTest() { - var messages = readFeed("https://feeds.thauvin.net/ethauvin") - assertThat(messages, "messages").all { - size().isEqualTo(10) - index(1).prop(Message::msg).contains("erik.thauvin.net") - } - - messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=0") - assertThat(messages, "messages").index(0).prop(Message::msg).contains("nothing") - - messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=84", 42) - assertThat(messages, "messages").size().isEqualTo(84) - messages.forEachIndexed { i, m -> - if (i % 2 == 0) { - assertThat(m, "messages($i)").prop(Message::msg).startsWith("Lorem ipsum") - } else { - assertThat(m, "messages($i)").prop(Message::msg).contains("http://example.com/test/") - } - } - - assertFailure { readFeed("blah") }.isInstanceOf(MalformedURLException::class.java) - - assertFailure { readFeed("https://www.example.com") }.isInstanceOf(FeedException::class.java) - - assertFailure { readFeed("https://www.thauvin.net/foo") }.isInstanceOf(IOException::class.java) - - assertFailure { readFeed("https://www.examplesfoo.com/") }.isInstanceOf(UnknownHostException::class.java) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/LocalProperties.kt b/bin/test/net/thauvin/erik/mobibot/LocalProperties.kt deleted file mode 100644 index 1384a72..0000000 --- a/bin/test/net/thauvin/erik/mobibot/LocalProperties.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * LocalProperties.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import org.testng.annotations.BeforeSuite -import java.io.IOException -import java.net.InetAddress -import java.net.UnknownHostException -import java.nio.file.Files -import java.nio.file.Paths -import java.util.* - -/** - * Access to `local.properties`. - */ -open class LocalProperties { - @BeforeSuite(alwaysRun = true) - fun loadProperties() { - val localPath = Paths.get("local.properties") - if (Files.exists(localPath)) { - try { - Files.newInputStream(localPath).use { stream -> localProps.load(stream) } - } catch (ignore: IOException) { - // Do nothing - } - } - } - - companion object { - private val localProps = Properties() - - fun getHostName(): String { - val ciName = System.getenv("CI_NAME") - return ciName ?: try { - InetAddress.getLocalHost().hostName - } catch (ignore: UnknownHostException) { - "Unknown Host" - } - } - - fun getProperty(key: String): String { - return if (localProps.containsKey(key)) { - localProps.getProperty(key) - } else { - val env = System.getenv(keyToEnv(key)) - env?.let { - localProps.setProperty(key, env) - } - env - } - } - - private fun keyToEnv(key: String): String { - return key.replace('-', '_').uppercase() - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/PinboardTest.kt b/bin/test/net/thauvin/erik/mobibot/PinboardTest.kt deleted file mode 100644 index b527fc5..0000000 --- a/bin/test/net/thauvin/erik/mobibot/PinboardTest.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * PinboardTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot - -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.entries.EntryLink -import org.testng.Assert.assertFalse -import org.testng.Assert.assertTrue -import kotlin.test.Test -import java.net.URL - -class PinboardTest : LocalProperties() { - private val pinboard = Pinboard() - - @Test - fun testPinboard() { - val apiToken = getProperty("pinboard-api-token") - val url = "https://www.example.com/${(1000..5000).random()}" - val ircServer = "irc.test.com" - val entry = EntryLink(url, "Test Example", "ErikT", "", "#mobitopia", listOf("test")) - - pinboard.setApiToken(apiToken) - - pinboard.addPin(ircServer, entry) - assertTrue(validatePin(apiToken, url = entry.link, entry.title, entry.nick, entry.channel), "addPin") - - entry.link = "https://www.example.com/${(5001..9999).random()}" - pinboard.updatePin(ircServer, url, entry) - assertTrue(validatePin(apiToken, url = entry.link, ircServer), "updatePin") - - entry.title = "Foo Title" - pinboard.updatePin(ircServer, entry.link, entry) - assertTrue(validatePin(apiToken, url = entry.link, entry.title), "updatePin(${entry.title}") - - pinboard.deletePin(entry) - assertFalse(validatePin(apiToken, url = entry.link), "deletePin") - } - - private fun validatePin(apiToken: String, url: String, vararg matches: String): Boolean { - val response = - URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body - - matches.forEach { - if (!response.contains(it)) { - return false - } - } - - return response.contains(url) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/UtilsTest.kt b/bin/test/net/thauvin/erik/mobibot/UtilsTest.kt deleted file mode 100644 index 7b7ba8c..0000000 --- a/bin/test/net/thauvin/erik/mobibot/UtilsTest.kt +++ /dev/null @@ -1,278 +0,0 @@ -/* - * UtilsTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.length -import net.thauvin.erik.mobibot.Utils.appendIfMissing -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.colorize -import net.thauvin.erik.mobibot.Utils.cyan -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.getIntProperty -import net.thauvin.erik.mobibot.Utils.green -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.lastOrEmpty -import net.thauvin.erik.mobibot.Utils.obfuscate -import net.thauvin.erik.mobibot.Utils.plural -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.red -import net.thauvin.erik.mobibot.Utils.replaceEach -import net.thauvin.erik.mobibot.Utils.reverseColor -import net.thauvin.erik.mobibot.Utils.toIntOrDefault -import net.thauvin.erik.mobibot.Utils.toIsoLocalDate -import net.thauvin.erik.mobibot.Utils.toUtcDateTime -import net.thauvin.erik.mobibot.Utils.today -import net.thauvin.erik.mobibot.Utils.underline -import net.thauvin.erik.mobibot.Utils.unescapeXml -import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR -import org.pircbotx.Colors -import org.testng.annotations.BeforeClass -import kotlin.test.Test -import java.io.File -import java.io.IOException -import java.net.URL -import java.time.LocalDateTime -import java.util.* - -/** - * The `Utils Test` class. - */ -class UtilsTest { - private val ascii = - " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" - private val cal = Calendar.getInstance() - private val localDateTime = LocalDateTime.of(1952, 2, 17, 12, 30, 0) - private val test = "This is a test." - - @BeforeClass - fun setUp() { - cal[1952, Calendar.FEBRUARY, 17, 12, 30] = 0 - } - - @Test - fun testAppendIfMissing() { - val dir = "dir" - val sep = '/' - val url = "https://erik.thauvin.net" - assertThat(dir.appendIfMissing(File.separatorChar), "appendIfMissing(dir)") - .isEqualTo(dir + File.separatorChar) - assertThat(url.appendIfMissing(sep), "appendIfMissing(url)").isEqualTo("$url$sep") - assertThat("$url$sep".appendIfMissing(sep), "appendIfMissing($url$sep)").isEqualTo("$url$sep") - } - - @Test - fun testBold() { - assertThat(1.bold(), "bold(1)").isEqualTo(Colors.BOLD + "1" + Colors.BOLD) - assertThat(2L.bold(), "bold(2L)").isEqualTo(Colors.BOLD + "2" + Colors.BOLD) - assertThat(ascii.bold(), "ascii.bold()").isEqualTo(Colors.BOLD + ascii + Colors.BOLD) - assertThat("test".bold(), "test.bold()").isEqualTo(Colors.BOLD + "test" + Colors.BOLD) - } - - - @Test - fun testCapitalise() { - 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(), "captiatlizeWords(test)").isEqualTo("This Is A Test.") - assertThat("Already Capitalized".capitalizeWords(), "already capitalized") - .isEqualTo("Already Capitalized") - assertThat(" a test ".capitalizeWords(), "with spaces").isEqualTo(" A Test ") - } - - @Test - fun testColorize() { - assertThat(ascii.colorize(Colors.REVERSE), "reverse.colorize()").isEqualTo( - Colors.REVERSE + ascii + Colors.REVERSE - ) - assertThat(ascii.colorize(Colors.RED), "red.colorize()") - .isEqualTo(Colors.RED + ascii + Colors.NORMAL) - assertThat(ascii.colorize(Colors.BOLD), "colorized(bold)") - .isEqualTo(Colors.BOLD + ascii + Colors.BOLD) - assertThat(null.colorize(Colors.RED), "null.colorize()").isEqualTo("") - assertThat("".colorize(Colors.RED), "colorize()").isEqualTo("") - assertThat(ascii.colorize(DEFAULT_COLOR), "ascii.colorize()").isEqualTo(ascii) - assertThat(" ".colorize(Colors.NORMAL), "blank.colorize()") - .isEqualTo(Colors.NORMAL + " " + Colors.NORMAL) - } - - @Test - fun testCyan() { - assertThat(ascii.cyan()).isEqualTo(Colors.CYAN + ascii + Colors.NORMAL) - } - - @Test - fun testEncodeUrl() { - assertThat("Hello Günter".encodeUrl()).isEqualTo("Hello%20G%C3%BCnter") - } - - @Test - fun testGetIntProperty() { - val p = Properties() - p["one"] = "1" - p["two"] = "two" - 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 - fun testGreen() { - assertThat(ascii.green()).isEqualTo(Colors.DARK_GREEN + ascii + Colors.NORMAL) - } - - @Test - fun testHelpCmdSyntax() { - val bot = "mobibot" - assertThat(helpCmdSyntax("%c $test %n $test", bot, false), "helpCmdSyntax(private)") - .isEqualTo("$bot: $test $bot $test") - assertThat(helpCmdSyntax("%c %n $test %c $test %n", bot, true), "helpCmdSyntax(public)") - .isEqualTo("/msg $bot $bot $test /msg $bot $test $bot") - } - - @Test - fun testHelpFormat() { - assertThat(helpFormat(test, isBold = true, isIndent = false), "helpFormat(bold)") - .isEqualTo("${Colors.BOLD}$test${Colors.BOLD}") - assertThat(helpFormat(test, isBold = false, isIndent = true), "helpFormat(indent)") - .isEqualTo(test.prependIndent()) - assertThat(helpFormat(test, isBold = true, isIndent = true), "helpFormat(bold,indent)") - .isEqualTo(test.colorize(Colors.BOLD).prependIndent()) - - } - - @Test - fun testIsoLocalDate() { - assertThat(cal.time.toIsoLocalDate(), "isoLocalDate(date)").isEqualTo("1952-02-17") - assertThat(localDateTime.toIsoLocalDate(), "isoLocalDate(localDate)").isEqualTo("1952-02-17") - } - - @Test - fun testLastOrEmpty() { - val two = listOf("1", "2") - assertThat(two.lastOrEmpty(), "lastOrEmpty(1,2)").isEqualTo("2") - val one = listOf("1") - assertThat(one.lastOrEmpty(), "lastOrEmpty(1)").isEqualTo("") - } - - @Test - fun testObfuscate() { - assertThat(ascii.obfuscate(), "obfuscate()").all { - length().isEqualTo(ascii.length) - isEqualTo(("x".repeat(ascii.length))) - } - assertThat(" ".obfuscate(), "obfuscate(blank)").isEqualTo(" ") - } - - @Test - fun testPlural() { - val week = "week" - val weeks = "weeks" - - for (i in -1..3) { - assertThat(week.plural(i.toLong()), "plural($i)").isEqualTo(if (i > 1) weeks else week) - } - } - - @Test - fun testReplaceEach() { - val search = arrayOf("one", "two", "three") - val replace = arrayOf("1", "2", "3") - assertThat(search.joinToString(",").replaceEach(search, replace), "replaceEach(1,2,3") - .isEqualTo(replace.joinToString(",")) - - assertThat(test.replaceEach(search, replace), "replaceEach(nothing)").isEqualTo(test) - - assertThat(test.replaceEach(arrayOf("t", "e"), arrayOf("", "E")), "replaceEach($test)") - .isEqualTo(test.replace("t", "").replace("e", "E")) - - assertThat(test.replaceEach(search, emptyArray()), "replaceEach(search, empty)") - .isEqualTo(test) - } - - @Test - fun testRed() { - assertThat(ascii.red()).isEqualTo(ascii.colorize(Colors.RED)) - } - - @Test - fun testReverseColor() { - assertThat(ascii.reverseColor()).isEqualTo(Colors.REVERSE + ascii + Colors.REVERSE) - } - - @Test - fun testToday() { - assertThat(today()).isEqualTo(LocalDateTime.now().toIsoLocalDate()) - } - - @Test - fun testToIntOrDefault() { - assertThat("10".toIntOrDefault(1), "toIntOrDefault(10, 1)").isEqualTo(10) - assertThat("a".toIntOrDefault(2), "toIntOrDefault(a, 2)").isEqualTo(2) - } - - @Test - fun testUnderline() { - assertThat(ascii.underline()).isEqualTo(ascii.colorize(Colors.UNDERLINE)) - } - - @Test - fun testUnescapeXml() { - assertThat("<a name="test & ''">".unescapeXml()).isEqualTo( - "" - ) - } - - @Test - @Throws(IOException::class) - fun testUrlReader() { - val reader = URL("https://postman-echo.com/status/200").reader() - assertThat(reader.body).isEqualTo("{\n \"status\": 200\n}") - assertThat(reader.responseCode).isEqualTo(200) - } - - @Test - fun testUtcDateTime() { - 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/bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt deleted file mode 100644 index 99ba951..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/InfoTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * InfoTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import assertk.assertThat -import assertk.assertions.isEqualTo -import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime -import kotlin.test.Test - -class InfoTest { - @Test - fun testToUptime() { - assertThat( - 547800300076L.toUptime(), - "upTime(full)" - ).isEqualTo("17 years 4 months 2 weeks 1 day 6 hours 45 minutes") - assertThat(24300000L.toUptime(), "upTime(hours minutes)").isEqualTo("6 hours 45 minutes") - assertThat(110700000L.toUptime(), "upTime(days hours minutes)").isEqualTo("1 day 6 hours 45 minutes") - assertThat( - 1320300000L.toUptime(), - "upTime(weeks days hours minutes)" - ).isEqualTo("2 weeks 1 day 6 hours 45 minutes") - assertThat(2700000L.toUptime(), "upTime(45 minutes)").isEqualTo("45 minutes") - assertThat(60000L.toUptime(), "upTime(1 minute)").isEqualTo("1 minute") - assertThat(59000L.toUptime(), "upTime(59 seconds)").isEqualTo("59 seconds") - assertThat(0L.toUptime(), "upTime(0 second)").isEqualTo("0 second") - - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt deleted file mode 100644 index b6fbbff..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/RecapTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * RecapTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.matches -import assertk.assertions.prop -import assertk.assertions.size -import kotlin.test.Test - -class RecapTest { - @Test - fun storeRecapTest() { - for (i in 1..20) { - Recap.storeRecap("sender$i", "test $i", false) - } - assertThat(Recap.recaps, "Recap.recaps").all { - size().isEqualTo(Recap.MAX_RECAPS) - prop(MutableList::first) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender11: test 11".toRegex()) - prop(MutableList::last) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender20: test 20".toRegex()) - } - - Recap.storeRecap("sender", "test action", true) - assertThat(Recap.recaps.last()) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender test action".toRegex()) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt deleted file mode 100644 index fa2bb70..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * LinksManagerTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import assertk.all -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isEqualTo -import assertk.assertions.isTrue -import assertk.assertions.size -import net.thauvin.erik.mobibot.Constants -import kotlin.test.Test - -class LinksManagerTest { - private val linksManager = LinksManager() - - @Test - fun fetchTitle() { - assertThat(linksManager.fetchTitle("https://erik.thauvin.net/"), "fetchTitle(Erik)").contains("Erik's Weblog") - assertThat( - linksManager.fetchTitle("https://www.google.com/foo"), - "fetchTitle(Foo)" - ).isEqualTo(Constants.NO_TITLE) - } - - @Test - fun testMatches() { - assertThat(linksManager.matches("https://www.example.com/"), "matches(url)").isTrue() - assertThat(linksManager.matches("HTTP://erik.thauvin.net/blog/ Erik's Weblog"), "matches(HTTP)").isTrue() - } - - @Test - fun matchTagKeywordsTest() { - linksManager.setProperty(LinksManager.KEYWORDS_PROP, "key1 key2,key3") - val tags = mutableListOf() - - linksManager.matchTagKeywords("Test title with key2", tags) - assertThat(tags, "tags").contains("key2") - tags.clear() - - linksManager.matchTagKeywords("Test key3 title with key1", tags) - assertThat(tags, "tags(key1, key3)").all { - contains("key1") - contains("key3") - size().isEqualTo(2) - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt deleted file mode 100644 index e315891..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/links/ViewTest.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * ViewTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.links - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.prop -import net.thauvin.erik.mobibot.entries.EntryLink -import kotlin.test.Test - -class ViewTest { - @Test - fun testParseArgs() { - val view = View() - - for (i in 1..10) { - LinksManager.entries.links.add( - EntryLink( - "https://www.example.com/$i", - "Example $i", - "nick$i", - "login$i", - "#channel", - emptyList() - ) - ) - } - - assertThat(view.parseArgs("1"), "parseArgs(1)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("") - } - - assertThat(view.parseArgs("2 foo"), "parseArgs(2, foo)").all { - prop(Pair::first).isEqualTo(1) - prop(Pair::second).isEqualTo("foo") - } - - assertThat(view.parseArgs("3 FOO"), "parseArgs(3, FOO)").all { - prop(Pair::first).isEqualTo(2) - prop(Pair::second).isEqualTo("foo") - } - - assertThat(view.parseArgs(" 4 foo bar "), "parseArgs( 4 foo bar )").all { - prop(Pair::first).isEqualTo(3) - prop(Pair::second).isEqualTo("foo bar") - } - - assertThat(view.parseArgs("foo bar"), "parseArgs(foo bar)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("foo bar") - } - - assertThat(view.parseArgs("${Int.MAX_VALUE}1"), "parseArgs(overflow)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("${Int.MAX_VALUE}1") - } - - assertThat(view.parseArgs("1a"), "parseArgs(1a)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("1a") - } - - assertThat(view.parseArgs("20"), "parseArgs(20)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("") - } - - assertThat(view.parseArgs(""), "parseArgs()").all { - prop(Pair::first).isEqualTo(LinksManager.entries.links.size - View.MAX_ENTRIES) - prop(Pair::second).isEqualTo("") - } - - LinksManager.entries.links.clear() - - assertThat(view.parseArgs("4"), "parseArgs(4)").all { - prop(Pair::first).isEqualTo(0) - prop(Pair::second).isEqualTo("") - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt deleted file mode 100644 index 37b884b..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SeenTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.seen - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import org.testng.annotations.AfterClass -import org.testng.annotations.BeforeClass -import kotlin.test.Test -import kotlin.io.path.deleteIfExists -import kotlin.io.path.fileSize - -class SeenTest { - private val tmpFile = kotlin.io.path.createTempFile(suffix = ".ser") - private val seen = Seen(tmpFile.toAbsolutePath().toString()) - private val nick = "ErikT" - - @BeforeClass - fun saveTest() { - seen.add("ErikT") - assertThat(tmpFile.fileSize(), "tmpFile.size").isGreaterThan(0) - } - - @AfterClass(alwaysRun = true) - fun afterClass() { - tmpFile.deleteIfExists() - } - - @Test(priority = 1, groups = ["commands"]) - fun loadTest() { - seen.clear() - assertThat(seen::seenNicks).isEmpty() - seen.load() - assertThat(seen::seenNicks).key(nick).isNotNull() - } - - @Test - fun addTest() { - val last = seen.seenNicks[nick]?.lastSeen - seen.add(nick.lowercase()) - assertThat(seen).all { - prop(Seen::seenNicks).size().isEqualTo(1) - prop(Seen::seenNicks).key(nick).isNotNull().prop(SeenNick::lastSeen).isNotEqualTo(last) - prop(Seen::seenNicks).key(nick).isNotNull().prop(SeenNick::nick).isNotNull().isEqualTo(nick.lowercase()) - } - } - - @Test(priority = 10, groups = ["commands"]) - fun clearTest() { - seen.clear() - seen.save() - seen.load() - assertThat(seen::seenNicks).size().isEqualTo(0) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt deleted file mode 100644 index cc09237..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * TellMessageTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.commands.tell - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isFalse -import assertk.assertions.isTrue -import assertk.assertions.prop -import kotlin.test.Test -import java.time.Duration -import java.time.LocalDateTime -import java.time.temporal.Temporal - -/** - * The `TellMessageTest` class. - */ -class TellMessageTest { - private fun isValidDate(date: Temporal): Boolean { - return Duration.between(date, LocalDateTime.now()).toMinutes() < 1 - } - - @Test - fun testTellMessage() { - val message = "Test message." - val recipient = "recipient" - val sender = "sender" - val tellMessage = TellMessage(sender, recipient, message) - assertThat(tellMessage).all { - prop(TellMessage::sender).isEqualTo(sender) - prop(TellMessage::recipient).isEqualTo(recipient) - prop(TellMessage::message).isEqualTo(message) - } - assertThat(isValidDate(tellMessage.queued), "isValidDate()").isTrue() - assertThat(tellMessage.isMatch(sender), "isMatch(sender)").isTrue() - assertThat(tellMessage.isMatch(recipient), "isMatch(recipient)").isTrue() - assertThat(tellMessage.isMatch("foo"), "isMatch(foo)").isFalse() - tellMessage.isReceived = false - assertThat(tellMessage.receptionDate, "receptionDate").isEqualTo(LocalDateTime.MIN) - tellMessage.isReceived = true - assertThat(isValidDate(tellMessage.receptionDate), "isValidDate(creationDate)").isTrue() - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt b/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt deleted file mode 100644 index 5acba78..0000000 --- a/bin/test/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * TellMessagesMgrTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.commands.tell - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import org.testng.annotations.AfterClass -import org.testng.annotations.BeforeClass -import kotlin.test.Test -import java.time.LocalDateTime -import kotlin.io.path.createTempFile -import kotlin.io.path.deleteIfExists -import kotlin.io.path.fileSize - -class TellMessagesMgrTest { - private val testFile = createTempFile(suffix = ".ser") - private val maxDays = 10L - private val testMessages = mutableListOf().apply { - for (i in 0..5) { - this.add(i, TellMessage("sender$i", "recipient$i", "message $i")) - } - } - - @BeforeClass - fun saveTest() { - TellManager.save(testFile.toAbsolutePath().toString(), testMessages) - assertThat(testFile.fileSize()).isGreaterThan(0) - } - - @AfterClass - fun afterClass() { - testFile.deleteIfExists() - } - - @Test - fun cleanTest() { - testMessages.add(TellMessage("sender", "recipient", "message").apply { - queued = LocalDateTime.now().minusDays(maxDays) - }) - val size = testMessages.size - assertThat(TellManager.clean(testMessages, maxDays + 2), "clean(maxDays=${maxDays + 2})").isFalse() - assertThat(TellManager.clean(testMessages, maxDays), "clean(maxDays=$maxDays)").isTrue() - assertThat(testMessages, "testMessages").size().isEqualTo(size - 1) - } - - @Test - fun loadTest() { - val messages = TellManager.load(testFile.toAbsolutePath().toString()) - for (i in messages.indices) { - assertThat(messages).index(i).all { - prop(TellMessage::sender).isEqualTo(testMessages[i].sender) - prop(TellMessage::recipient).isEqualTo(testMessages[i].recipient) - prop(TellMessage::message).isEqualTo(testMessages[i].message) - } - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt deleted file mode 100644 index 0ad26b5..0000000 --- a/bin/test/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * EntriesUtilsTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.entries - -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.toLinkLabel -import kotlin.test.Test - -class EntriesUtilsTest { - private val comment = EntryComment("comment", "nick") - private val links = buildList { - for (i in 0..5) { - add( - EntryLink( - "https://www.mobitopia.org/$i", - "Mobitopia$i", - "Skynx$i", - "JimH$i", - "#mobitopia$i", - listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") - ) - ) - } - } - - @Test - fun printCommentTest() { - assertThat(printComment(0, 0, comment)).isEqualTo("${Constants.LINK_CMD}1.1: [nick] comment") - } - - @Test - fun printLinkTest() { - for (i in links.indices) { - assertThat( - printLink(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]") - } - - @Test - fun printTagsTest() { - for (i in links.indices) { - assertThat( - printTags(i - 1, links[i]), "tag $i" - ).isEqualTo("L${i}T: tag1, tag2, tag3, tag4, tag5") - } - } - - @Test - fun toLinkLabelTest() { - assertThat(1.toLinkLabel()).isEqualTo("${Constants.LINK_CMD}2") - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt deleted file mode 100644 index f421099..0000000 --- a/bin/test/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * EntryLinkTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.entries - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import com.rometools.rome.feed.synd.SyndCategory -import com.rometools.rome.feed.synd.SyndCategoryImpl -import kotlin.test.Test -import java.security.SecureRandom -import java.util.* - -/** - * The `EntryUtilsTest` class. - * - * @author [Erik C. Thauvin](https://erik.thauvin.net/) - * @created 2019-04-19 - * @since 1.0 - */ -class EntryLinkTest { - private val entryLink = EntryLink( - "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", - listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") - ) - - @Test - fun testAddDeleteComment() { - var i = 0 - while (i < 5) { - entryLink.addComment("c$i", "u$i") - i++ - } - assertThat(entryLink.comments, "comments").size().isEqualTo(i) - i = 0 - for (comment in entryLink.comments) { - 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, "hasComments()").isEmpty() - entryLink.addComment("nothing", "nobody") - entryLink.setComment(0, "something", "somebody") - val comment = entryLink.getComment(0) - assertThat(comment, "comment[first]").all { - prop(EntryComment::nick).isEqualTo("somebody") - prop(EntryComment::comment).isEqualTo("something") - } - assertThat(entryLink.deleteComment(comment), "deleteComment").isTrue() - assertThat(entryLink.deleteComment(comment), "comment is already deleted").isFalse() - } - - @Test - fun testConstructor() { - val tags = listOf(SyndCategoryImpl().apply { name = "tag1" }, SyndCategoryImpl().apply { name = "tag2" }) - 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") - } - } - - @Test - fun testMatches() { - assertThat(entryLink.matches("mobitopia"), "matches(mobitopia)").isTrue() - assertThat(entryLink.matches("skynx"), "match(nick)").isTrue() - assertThat(entryLink.matches("www.mobitopia.org"), "matches(url)").isTrue() - assertThat(entryLink.matches("foo"), "matches(foo)").isFalse() - assertThat(entryLink.matches(""), "matches(empty)").isFalse() - assertThat(entryLink.matches(null), "matches(null)").isFalse() - } - - - @Test - fun testTags() { - val tags: List = entryLink.tags - for ((i, tag) in tags.withIndex()) { - assertThat(tag.name, "tag.name($i)").isEqualTo("tag${i + 1}") - } - assertThat(entryLink::tags).size().isEqualTo(5) - entryLink.setTags("-tag5, tag4") - entryLink.setTags("+mobitopia") - 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") - val size = entryLink.tags.size - entryLink.setTags("") - assertThat(entryLink.tags, "setTags('')").size().isEqualTo(size) - entryLink.setTags(" ") - assertThat(entryLink.tags, "setTags(' ')").size().isEqualTo(size) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt deleted file mode 100644 index 1611009..0000000 --- a/bin/test/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * FeedMgrTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.entries - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.Utils.today -import org.testng.annotations.BeforeSuite -import kotlin.test.Test -import java.nio.file.Paths -import java.util.* -import kotlin.io.path.deleteIfExists -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(FeedsManager.loadFeed(entries), "loadFeed()").isEqualTo("2021-10-31") - - assertThat(entries.links, "entries.links").size().isEqualTo(2) - entries.links.forEachIndexed { i, entryLink -> - assertThat(entryLink, "entryLink[${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, "nick[first]").isEqualTo("ErikT") - assertThat(date, "date[first]").isEqualTo(Date(1635638400000L)) - assertThat(comments.first(), "comments[first]").all { - prop(EntryComment::comment).endsWith("comment 1.") - prop(EntryComment::nick).isEqualTo("ErikT") - } - assertThat(comments.last(), "comments[last]").all { - prop(EntryComment::comment).endsWith("comment 2.") - prop(EntryComment::nick).isEqualTo("Skynx") - } - } - - assertThat(entries.links, "links").index(1).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 - FeedsManager.saveFeed(entries, currentFile.name) - - assertThat(currentFile, "currentFile").exists() - assertThat(backlogFile, "backlogFile").exists() - - assertThat(currentFile.fileSize(), "currentFile == backlogFile").isEqualTo(backlogFile.fileSize()) - - // Load the test feed - entries.links.clear() - FeedsManager.loadFeed(entries, currentFile.name) - - entries.links.forEachIndexed { i, entryLink -> - assertThat(entryLink.title, "entryLink.title[${i + 1}]").isEqualTo("Example ${i + 1}") - } - - assertThat(currentFile.deleteIfExists(), "currentFile.deleteIfExists()").isTrue() - assertThat(backlogFile.deleteIfExists(), "backlogFile.deleteIfExists()").isTrue() - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt deleted file mode 100644 index 3bd4c0f..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * CalcTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.isEqualTo -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 kotlin.test.Test - -/** - * The `CalcTest` class. - */ -class CalcTest { - @Test - fun testCalculate() { - assertThat(calculate("1 + 1"), "calculate(1+1)").isEqualTo("1+1 = ${2.bold()}") - assertThat(calculate("1 -3"), "calculate(1-3)").isEqualTo("1-3 = ${(-2).bold()}") - assertThat(calculate("pi+π+e+φ"), "calculate(pi+π+e+φ)").isEqualTo("pi+π+e+φ = ${"10.62".bold()}") - assertFailure { calculate("one + one") }.isInstanceOf(UnknownFunctionOrVariableException::class.java) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt deleted file mode 100644 index 085f228..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/ChatGptTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ChatGptTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.hasNoCause -import assertk.assertions.isInstanceOf -import net.thauvin.erik.mobibot.LocalProperties -import kotlin.test.Test - -class ChatGptTest : LocalProperties() { - @Test - fun testApiKey() { - assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } - .isInstanceOf(ModuleException::class.java) - .hasNoCause() - } - - @Test(groups = ["modules", "no-ci"]) - fun testChat() { - val apiKey = getProperty(ChatGpt.API_KEY_PROP) - assertThat( - ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) - ).contains("XMLHttpRequest") - assertThat( - ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) - ).contains("URLEncoder") - - assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) } - .isInstanceOf(ModuleException::class.java) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt deleted file mode 100644 index d0ecbc9..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * CryptoPricesTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.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 net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.getCurrencyName -import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.loadCurrencies -import org.testng.annotations.BeforeClass -import kotlin.test.Test - -/** - * The `CryptoPricesTest` class. - */ -class CryptoPricesTest { - @BeforeClass - @Throws(ModuleException::class) - fun before() { - loadCurrencies() - } - - @Test - @Throws(ModuleException::class) - fun testMarketPrice() { - var price = currentPrice(listOf("BTC")) - assertThat(price, "currentPrice(BTC)").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, "currentPrice(ETH, EUR)").all { - prop(CryptoPrice::base).isEqualTo("ETH") - prop(CryptoPrice::currency).isEqualTo("EUR") - prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0) - } - } - - @Test - fun testGetCurrencyName() { - assertThat(getCurrencyName("USD"), "USD").isEqualTo("United States Dollar") - assertThat(getCurrencyName("EUR"), "EUR").isEqualTo("Euro") - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt deleted file mode 100644 index 8d8c997..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * CurrencyConverterTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isInstanceOf -import assertk.assertions.matches -import assertk.assertions.prop -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.convertCurrency -import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.loadSymbols -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 kotlin.test.Test - - -/** - * The `CurrencyConvertTest` class. - */ -class CurrencyConverterTest : LocalProperties() { - - @BeforeClass - @Throws(ModuleException::class) - fun before() { - val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) - loadSymbols(apiKey) - } - - @Test - fun testConvertCurrency() { - val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) - assertThat( - convertCurrency(apiKey, "100 USD to EUR").msg, - "convertCurrency(100 USD to EUR)" - ).matches("100 United States Dollar = \\d{2,3}\\.\\d{2,3} Euro".toRegex()) - assertThat( - convertCurrency(apiKey, "1 USD to GBP").msg, - "convertCurrency(1 USD to BGP)" - ).matches("1 United States Dollar = 0\\.\\d{2,3} Pound Sterling".toRegex()) - assertThat( - convertCurrency(apiKey, "100,000.00 CAD to USD").msg, - "convertCurrency(100,000.00 GBP to USD)" - ).matches("100,000.00 Canadian Dollar = \\d+\\.\\d{2,3} United States Dollar".toRegex()) - assertThat(convertCurrency(apiKey, "100 USD to USD"), "convertCurrency(100 USD to USD)").all { - prop(Message::msg).contains("You're kidding, right?") - isInstanceOf(PublicMessage::class.java) - } - assertThat(convertCurrency(apiKey, "100 USD"), "convertCurrency(100 USD)").all { - prop(Message::msg).contains("Invalid query.") - isInstanceOf(ErrorMessage::class.java) - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt deleted file mode 100644 index 8bafede..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/DiceTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * DiceTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - - -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.matches -import kotlin.test.Test - -class DiceTest { - @Test - fun testRoll() { - assertThat(Dice.roll(1, 1), "roll(1d1)").isEqualTo("\u00021\u0002") - assertThat(Dice.roll(2, 1), "roll(2d1)") - .isEqualTo("\u00021\u0002 + \u00021\u0002 = \u00022\u0002") - assertThat(Dice.roll(5, 1), "roll(5d1)") - .isEqualTo("\u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 = \u00025\u0002") - assertThat(Dice.roll(2, 6), "roll(2d6)") - .matches("\u0002[1-6]\u0002 \\+ \u0002[1-6]\u0002 = \u0002[1-9][0-2]?\u0002".toRegex()) - assertThat(Dice.roll(3, 7), "roll(3d7)") - .matches("\u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 = \u0002\\d{1,2}\u0002".toRegex()) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt deleted file mode 100644 index 85c990c..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ /dev/null @@ -1,95 +0,0 @@ -/* - * GoogleSearchTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.GoogleSearch.Companion.searchGoogle -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test - -/** - * The `GoogleSearchTest` class. - */ -class GoogleSearchTest : LocalProperties() { - @Test - fun testAPIKeys() { - assertThat( - searchGoogle("", "apikey", "cssKey").first(), - "searchGoogle(empty)" - ).isInstanceOf(ErrorMessage::class.java) - - assertFailure { searchGoogle("test", "", "apiKey") } - .isInstanceOf(ModuleException::class.java).hasNoCause() - - assertFailure { searchGoogle("test", "apiKey", "") } - .isInstanceOf(ModuleException::class.java).hasNoCause() - - assertFailure { searchGoogle("test", "apiKey", "cssKey") } - .isInstanceOf(ModuleException::class.java) - .hasMessage("API key not valid. Please pass a valid API key.") - } - - @Test\n@DisableOnCi - @Throws(ModuleException::class) - fun testSearchGoogle() { - val apiKey = getProperty(GoogleSearch.API_KEY_PROP) - val cseKey = getProperty(GoogleSearch.CSE_KEY_PROP) - - try { - var query = "mobibot" - var messages = searchGoogle(query, apiKey, cseKey) - assertThat(messages, "searchGoogle($query)").all { - isNotEmpty() - index(0).prop(Message::msg).contains(query, true) - } - - query = "adadflkjl" - messages = searchGoogle(query, apiKey, cseKey) - assertThat(messages, "searchGoogle($query)").index(0).all { - isInstanceOf(ErrorMessage::class.java) - prop(Message::msg).isEqualTo("No results found.") - } - } catch (e: ModuleException) { - // Avoid displaying api keys in CI logs - if ("true" == System.getenv("CI")) { - throw e.sanitize(apiKey, cseKey) - } else { - throw e - } - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt deleted file mode 100644 index 0af8e75..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/JokeTest.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * JokeTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.modules.Joke.Companion.randomJoke -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.PublicMessage -import kotlin.test.Test - -/** - * The `JokeTest` class. - */ -class JokeTest { - @Test - @Throws(ModuleException::class) - fun testRandomJoke() { - val joke = randomJoke() - assertThat(joke, "randomJoke()").all { - size().isGreaterThan(0) - each { - it.isInstanceOf(PublicMessage::class.java) - it.prop(Message::msg).doesNotContain("\n") - } - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt deleted file mode 100644 index a3fc226..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/LookupTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * LookupTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.any -import assertk.assertions.contains -import net.thauvin.erik.mobibot.modules.Lookup.Companion.nslookup -import net.thauvin.erik.mobibot.modules.Lookup.Companion.whois -import kotlin.test.Test - -/** - * The `Lookup Test` class. - */ -class LookupTest { - @Test - @Throws(Exception::class) - fun testLookup() { - var result = nslookup("apple.com") - assertThat(result, "lookup(apple.com)").contains("17.253.144.10") - - result = nslookup("204.122.16.136") - assertThat(result, "lookup(204.122.16.136)").contains("nix3.thauvin.us") - } - - @Test - @Throws(Exception::class) - fun testWhois() { - val result = whois("17.178.96.59", Lookup.WHOIS_HOST) - assertThat(result, "whois(17.178.96.59").any { it.contains("Apple Inc.") } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt deleted file mode 100644 index f4b5e99..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * MastodonTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.contains -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.Mastodon.Companion.toot -import kotlin.test.Test - -class MastodonTest : LocalProperties() { - @Test - @Throws(ModuleException::class) - fun testToot() { - val msg = "Testing Mastodon API from ${getHostName()}" - assertThat( - toot( - getProperty(Mastodon.ACCESS_TOKEN_PROP), - getProperty(Mastodon.INSTANCE_PROP), - getProperty(Mastodon.HANDLE_PROP), - msg, - true - ) - ).contains(msg) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt deleted file mode 100644 index 1416eec..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ModuleExceptionTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import org.testng.annotations.DataProvider -import kotlin.test.Test -import java.io.IOException -import java.lang.reflect.Method - -/** - * The `ModuleExceptionTest` class. - */ -class ModuleExceptionTest { - companion object { - const val DEBUG_MESSAGE = "debugMessage" - const val MESSAGE = "message" - } - - @DataProvider(name = "dp") - fun createData(@Suppress("UNUSED_PARAMETER") m: Method?): Array> { - return arrayOf( - arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com"))), - arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com?"))), - arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE)) - ) - } - - @Test(dataProvider = "dp") - fun testGetDebugMessage(e: ModuleException) { - assertThat(e::debugMessage).isEqualTo(DEBUG_MESSAGE) - } - - @Test(dataProvider = "dp") - fun testGetMessage(e: ModuleException) { - assertThat(e).hasMessage(MESSAGE) - } - - @Test - fun testSanitizeMessage() { - val apiKey = "1234567890" - var e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foo.com?apiKey=$apiKey&userID=me")) - assertThat( - e.sanitize(apiKey, "", "me").message, "ModuleException(debugMessage, message, IOException(url))" - ).isNotNull().all { - contains("xxxxxxxxxx", "userID=xx", "java.io.IOException") - doesNotContain(apiKey, "me") - } - - e = ModuleException(DEBUG_MESSAGE, MESSAGE, null) - assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, null)").hasMessage(MESSAGE) - - e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException()) - assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, IOException())").hasMessage(MESSAGE) - - e = ModuleException(DEBUG_MESSAGE, apiKey) - assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, apiKey)").isNotNull() - .doesNotContain(apiKey) - - val msg: String? = null - e = ModuleException(DEBUG_MESSAGE, msg, IOException(msg)) - assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, msg, IOException(msg))").isNull() - - e = ModuleException(DEBUG_MESSAGE, msg, IOException("foo is $apiKey")) - assertThat( - e.sanitize(" ", apiKey, "foo").message, - "ModuleException(debugMessage, msg, IOException(foo is $apiKey))" - ).isNotNull().all { - doesNotContain(apiKey) - endsWith("xxx is xxxxxxxxxx") - } - assertThat(e.sanitize(), "exception should be unchanged").isEqualTo(e) - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt deleted file mode 100644 index d1399e0..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/PingTest.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * PingTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isNotEmpty -import net.thauvin.erik.mobibot.modules.Ping.Companion.randomPing -import kotlin.test.Test - -/** - * The `PingTest` class. - */ -class PingTest { - @Test - fun testPingsArray() { - assertThat(Ping.PINGS, "Ping.PINGS").isNotEmpty() - } - - @Test - fun testRandomPing() { - for (i in 0..9) { - assertThat(Ping.PINGS, "Ping.PINGS[$i]").contains(randomPing()) - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt deleted file mode 100644 index f836b0e..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * RockPaperScissorsTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.isEqualTo -import net.thauvin.erik.mobibot.modules.RockPaperScissors.Companion.winLoseOrDraw -import kotlin.test.Test - -class RockPaperScissorsTest { - @Test - fun testWinLoseOrDraw() { - assertThat(winLoseOrDraw("scissors", "paper"), "scissors vs. paper").isEqualTo("win") - assertThat(winLoseOrDraw("paper", "rock"), "paper vs. rock").isEqualTo("win") - assertThat(winLoseOrDraw("rock", "scissors"), "rock vs. scissors").isEqualTo("win") - assertThat(winLoseOrDraw("paper", "scissors"), "paper vs. scissors").isEqualTo("lose") - assertThat(winLoseOrDraw("rock", "paper"), "rock vs. paper").isEqualTo("lose") - assertThat(winLoseOrDraw("scissors", "rock"), "scissors vs. rock").isEqualTo("lose") - assertThat(winLoseOrDraw("scissors", "scissors"), "scissors vs. scissors").isEqualTo("draw") - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt deleted file mode 100644 index d96812b..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * StockQuoteTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.StockQuote.Companion.getQuote -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test - -/** - * The `StockQuoteTest` class. - */ -class StockQuoteTest : LocalProperties() { - private fun buildMatch(label: String): String { - return "${label}:[ ]+[0-9.]+".prependIndent() - } - - @Test - @Throws(ModuleException::class) - fun testGetQuote() { - val apiKey = getProperty(StockQuote.API_KEY_PROP) - try { - var symbol = "apple inc" - val messages = getQuote(symbol, apiKey) - assertThat(messages, "response not empty").isNotEmpty() - assertThat(messages, "getQuote($symbol)").index(0).prop(Message::msg).matches("Symbol: AAPL .*".toRegex()) - assertThat(messages, "getQuote($symbol)").index(1).prop(Message::msg).matches(buildMatch("Price").toRegex()) - assertThat(messages, "getQuote($symbol)").index(2).prop(Message::msg) - .matches(buildMatch("Previous").toRegex()) - assertThat(messages, "getQuote($symbol)").index(3).prop(Message::msg).matches(buildMatch("Open").toRegex()) - - symbol = "blahfoo" - assertThat(getQuote(symbol, apiKey).first(), "getQuote($symbol)").all { - isInstanceOf(ErrorMessage::class.java) - prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) - } - assertThat(getQuote("", "apikey").first(), "getQuote(empty)").all { - isInstanceOf(ErrorMessage::class.java) - prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) - } - assertFailure { getQuote("test", "") }.isInstanceOf(ModuleException::class.java).hasNoCause() - } catch (e: ModuleException) { - // Avoid displaying api keys in CI logs - if ("true" == System.getenv("CI")) { - throw e.sanitize(apiKey) - } else { - throw e - } - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt deleted file mode 100644 index 66f4d22..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Weather2Test.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import net.aksingh.owmjapis.api.APIException -import net.aksingh.owmjapis.core.OWM -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.Weather2.Companion.API_KEY_PROP -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 net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test - -/** - * The `Weather2Test` class. - */ -class Weather2Test : LocalProperties() { - @Test - fun testFtoC() { - val t = ftoC(32.0) - assertThat(t.second, "32 °F is 0 °C").isEqualTo(0) - } - - @Test - fun testGetCountry() { - assertThat(getCountry("foo"), "foo is not a valid country").isEqualTo(OWM.Country.UNITED_STATES) - assertThat(getCountry("fr"), "country should France").isEqualTo(OWM.Country.FRANCE) - - val country = OWM.Country.entries.toTypedArray() - repeat(3) { - val rand = country[(country.indices).random()] - assertThat(getCountry(rand.value), rand.name).isEqualTo(rand) - } - } - - @Test - fun testMphToKmh() { - val w = mphToKmh(0.62) - assertThat(w.second, "0.62 mph is 1 km/h").isEqualTo(1) - } - - @Test - @Throws(ModuleException::class) - fun testWeather() { - var query = "98204" - var messages = getWeather(query, getProperty(API_KEY_PROP)) - assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { - contains("Everett, United States") - contains("US") - } - assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("98204%2CUS") - - query = "San Francisco" - messages = getWeather(query, getProperty(API_KEY_PROP)) - assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { - contains("San Francisco") - contains("US") - } - assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("5391959") - - query = "London, GB" - messages = getWeather(query, getProperty(API_KEY_PROP)) - assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { - contains("London, United Kingdom") - contains("GB") - } - assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("2643743") - - try { - query = "Foo, US" - getWeather(query, getProperty(API_KEY_PROP)) - } catch (e: ModuleException) { - assertThat(e.cause, "getWeather($query)").isNotNull().isInstanceOf(APIException::class.java) - } - - query = "test" - assertFailure { getWeather(query, "") }.isInstanceOf(ModuleException::class.java).hasNoCause() - assertFailure { getWeather(query, null) }.isInstanceOf(ModuleException::class.java).hasNoCause() - - messages = getWeather("", "apikey") - assertThat(messages, "getWeather(empty)").index(0).prop(Message::isError).isTrue() - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt deleted file mode 100644 index 855522c..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * WolframAlphaTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.modules - -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.hasMessage -import assertk.assertions.isInstanceOf -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.WolframAlpha.Companion.queryWolfram -import kotlin.test.Test - -class WolframAlphaTest : LocalProperties() { - @Test - fun testAppId() { - assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") } - .isInstanceOf(ModuleException::class.java) - .hasMessage("Error 1: Invalid appid") - - assertFailure { queryWolfram("1 gallon to liter", appId = "") } - .isInstanceOf(ModuleException::class.java) - } - - @Test(groups = ["modules", "no-ci"]) - @Throws(ModuleException::class) - fun queryWolframTest() { - val apiKey = getProperty(WolframAlpha.APPID_KEY_PROP) - try { - var query = "SFO to SEA" - assertThat(queryWolfram(query, appId = apiKey), "queryWolfram($query)").contains("miles") - - query = "SFO to LAX" - assertThat( - queryWolfram(query, WolframAlpha.METRIC, apiKey), - "queryWolfram($query)" - ).contains("kilometers") - } catch (e: ModuleException) { - // Avoid displaying api key in CI logs - if ("true" == System.getenv("CI")) { - throw e.sanitize(apiKey) - } else { - throw e - } - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt deleted file mode 100644 index 7931f33..0000000 --- a/bin/test/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * WordTimeTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.thauvin.erik.mobibot.modules - -import assertk.assertThat -import assertk.assertions.endsWith -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.pircbotx.Colors -import kotlin.test.Test -import java.time.ZoneId - -/** - * The `WordTimeTest` class. - */ -class WordTimeTest { - @Test - fun testTime() { - assertThat(time(), "time()").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(""), "time()").endsWith("Los Angeles".bold()) - assertThat(time("PST"), "time(PST)").endsWith("Los Angeles".bold()) - assertThat(time("GB"), "time(GB)").endsWith("London".bold()) - assertThat(time("FR"), "time(FR)").endsWith("Paris".bold()) - assertThat(time("BLAH"), "time(BLAH)").startsWith("Unsupported") - assertThat(time("BEAT"), "time($BEATS_KEYWORD)").matches("[\\w ]+ .?@\\d{3}+.? .beats".toRegex()) - } - - @Test - fun testZones() { - COUNTRIES_MAP.filter { it.value != BEATS_KEYWORD }.forEach { - assertThat(ZoneId.of(it.value)) - } - } -} diff --git a/bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt b/bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt deleted file mode 100644 index 32a0495..0000000 --- a/bin/test/net/thauvin/erik/mobibot/msg/MessageTest.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * MessageTest.kt - * - * Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.msg - -import assertk.all -import assertk.assertThat -import assertk.assertions.isFalse -import assertk.assertions.isTrue -import assertk.assertions.prop -import kotlin.test.Test - -class MessageTest { - @Test - fun testConstructor() { - var msg = Message("foo") - - msg.isError = true - assertThat(msg.isNotice, "message is notice").isTrue() - - msg = Message("foo", isError = true) - assertThat(msg.isNotice, "message is notice too").isTrue() - } - - @Test - fun testErrorMessage() { - val msg = ErrorMessage("foo") - assertThat(msg).all { - prop(Message::isError).isTrue() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - } - - @Test - fun testIsError() { - val msg = Message("foo") - msg.isError = true - assertThat(msg).all { - prop(Message::isError).isTrue() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - msg.isError = false - assertThat(msg).all { - prop(Message::isError).isFalse() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - } - - @Test - fun testNoticeMessage() { - val msg = NoticeMessage("food") - assertThat(msg).all { - prop(Message::isError).isFalse() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - } - - @Test - fun testPrivateMessage() { - val msg = PrivateMessage("foo") - assertThat(msg).all { - prop(Message::isPrivate).isTrue() - prop(Message::isError).isFalse() - prop(Message::isNotice).isFalse() - } - } - - @Test - fun testPublicMessage() { - val msg = PublicMessage("foo") - assertThat(msg).all { - prop(Message::isError).isFalse() - prop(Message::isNotice).isFalse() - prop(Message::isPrivate).isFalse() - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index 88634ae..01f14f3 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,11 +14,11 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20231110234054" + const val VERSION = "0.8.0-rc+20231111131146" @JvmField val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1699688454937L), ZoneId.systemDefault() + Instant.ofEpochMilli(1699737106723L), ZoneId.systemDefault() ) const val WEBSITE = "https://www.mobitopia.org/mobibot/" diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml deleted file mode 100644 index 16644cc..0000000 --- a/src/main/resources/log4j2.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -