diff --git a/LICENSE.txt b/LICENSE.txt index 4efe703..37785b0 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) +Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java b/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java index 9836bac..4cf0184 100644 --- a/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java +++ b/src/generated/java/net/thauvin/erik/mobibot/ReleaseInfo.java @@ -14,13 +14,13 @@ import java.time.*; public final class ReleaseInfo { public static final String PROJECT = "mobibot"; public static final LocalDateTime BUILDDATE = - LocalDateTime.ofInstant(Instant.ofEpochMilli(1584572412391L), ZoneId.systemDefault()); + LocalDateTime.ofInstant(Instant.ofEpochMilli(1584966079848L), ZoneId.systemDefault()); public static final int MAJOR = 0; public static final int MINOR = 7; public static final int PATCH = 3; public static final String PRERELEASE = "beta"; - public static final String BUILDMETA = "581"; - public static final String VERSION = "0.7.3-beta+581"; + public static final String BUILDMETA = "682"; + public static final String VERSION = "0.7.3-beta+682"; /** * Disables the default constructor. diff --git a/src/main/java/net/thauvin/erik/mobibot/FeedReader.java b/src/main/java/net/thauvin/erik/mobibot/FeedReader.java index 43621a9..c73a8be 100644 --- a/src/main/java/net/thauvin/erik/mobibot/FeedReader.java +++ b/src/main/java/net/thauvin/erik/mobibot/FeedReader.java @@ -1,7 +1,7 @@ /* * FeedReader.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -88,11 +88,14 @@ class FeedReader implements Runnable { SyndEntry item; final List items = feed.getEntries(); - - for (int i = 0; (i < items.size()) && (i < MAX_ITEMS); i++) { - item = items.get(i); - bot.send(sender, item.getTitle()); - bot.send(sender, TAB_INDENT + Utils.green(item.getLink())); + if (items.isEmpty()) { + bot.send(sender, "There is currently nothing to view. Why don't you post something?"); + } else { + for (int i = 0; (i < items.size()) && (i < MAX_ITEMS); i++) { + item = items.get(i); + bot.send(sender, item.getTitle()); + bot.send(sender, TAB_INDENT + Utils.green(item.getLink())); + } } } catch (MalformedURLException e) { bot.getLogger().debug("Invalid feed URL.", e); diff --git a/src/main/java/net/thauvin/erik/mobibot/Mobibot.java b/src/main/java/net/thauvin/erik/mobibot/Mobibot.java index de9574c..97cf66e 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Mobibot.java +++ b/src/main/java/net/thauvin/erik/mobibot/Mobibot.java @@ -1,7 +1,7 @@ /* * Mobibot.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,6 +47,7 @@ import net.thauvin.erik.mobibot.modules.Joke; import net.thauvin.erik.mobibot.modules.Lookup; import net.thauvin.erik.mobibot.modules.ModuleException; import net.thauvin.erik.mobibot.modules.Ping; +import net.thauvin.erik.mobibot.modules.RockPaperScissors; import net.thauvin.erik.mobibot.modules.StockQuote; import net.thauvin.erik.mobibot.modules.Twitter; import net.thauvin.erik.mobibot.modules.War; @@ -62,7 +63,6 @@ import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; -import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -93,6 +93,9 @@ import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; +import static net.thauvin.erik.mobibot.Utils.bold; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + /** * Implements the #mobitopia bot. * @@ -101,7 +104,8 @@ import java.util.StringTokenizer; * @since 1.0 */ @SuppressWarnings("WeakerAccess") -@Version(properties = "version.properties", className = "ReleaseInfo") +@Version(properties = "version.properties", + className = "ReleaseInfo") public class Mobibot extends PircBot { // The default port. @@ -111,9 +115,10 @@ public class Mobibot extends PircBot { private static final String DEFAULT_SERVER = "irc.freenode.net"; // The info strings. - private static final String[] INFO_STRS = - {ReleaseInfo.PROJECT + " v" + ReleaseInfo.VERSION + " by Erik C. Thauvin (erik@thauvin.net)", - "https://www.mobitopia.org/mobibot/"}; + @SuppressWarnings("indentation") + private static final String[] INFO_STRS = { + ReleaseInfo.PROJECT + " v" + ReleaseInfo.VERSION + " by Erik C. Thauvin (erik@thauvin.net)", + "https://www.mobitopia.org/mobibot/" }; // The link match string. private static final String LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*"; @@ -137,14 +142,15 @@ public class Mobibot extends PircBot { private static final String TAGS_MARKER = "tags:"; /* The version strings.*/ + @SuppressWarnings("indentation") private static final String[] VERSION_STRS = - {"Version: " + ReleaseInfo.VERSION + " (" + Utils.isoLocalDate(ReleaseInfo.BUILDDATE) + ')', - "Platform: " + System.getProperty("os.name") + " (" + System.getProperty("os.version") + ", " + System - .getProperty("os.arch") + ", " + System.getProperty("user.country") + ')', - "Runtime: " + System.getProperty("java.runtime.name") + " (build " + System - .getProperty("java.runtime.version") + ')', - "VM: " + System.getProperty("java.vm.name") + " (build " + System.getProperty("java.vm.version") + ", " - + System.getProperty("java.vm.info") + ')'}; + { "Version: " + ReleaseInfo.VERSION + " (" + Utils.isoLocalDate(ReleaseInfo.BUILDDATE) + ')', + "Platform: " + System.getProperty("os.name") + " (" + System.getProperty("os.version") + ", " + + System.getProperty("os.arch") + ", " + System.getProperty("user.country") + ')', + "Runtime: " + System.getProperty("java.runtime.name") + " (build " + System.getProperty( + "java.runtime.version") + ')', + "VM: " + System.getProperty("java.vm.name") + " (build " + System.getProperty("java.vm.version") + ", " + + System.getProperty("java.vm.info") + ')' }; // The logger. private static final Logger logger = LogManager.getLogger(Mobibot.class); // The commands list. @@ -272,6 +278,7 @@ public class Mobibot extends PircBot { MODULES.add(new Joke()); MODULES.add(new Lookup()); MODULES.add(new Ping()); + MODULES.add(new RockPaperScissors()); MODULES.add(new StockQuote()); twitterModule = new Twitter(); @@ -308,21 +315,29 @@ public class Mobibot extends PircBot { * @param args The command line arguments. */ @SuppressFBWarnings( - { - "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", - "DM_DEFAULT_ENCODING", - "IOI_USE_OF_FILE_STREAM_CONSTRUCTORS" - }) - @SuppressWarnings({"PMD.SystemPrintln", "PMD.AvoidFileStream", "PMD.CloseResource"}) + { + "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", + "DM_DEFAULT_ENCODING", + "IOI_USE_OF_FILE_STREAM_CONSTRUCTORS" + }) + @SuppressWarnings({ "PMD.SystemPrintln", "PMD.AvoidFileStream", "PMD.CloseResource" }) public static void main(final String[] args) { // Setup the command line options final Options options = new Options() - .addOption(Commands.HELP_ARG.substring(0, 1), Commands.HELP_ARG, false, "print this help message") - .addOption(Commands.DEBUG_ARG.substring(0, 1), Commands.DEBUG_ARG, false, - "print debug & logging data directly to the console") - .addOption(Option.builder(Commands.PROPS_ARG.substring(0, 1)).hasArg().argName("file") - .desc("use " + "alternate properties file").longOpt(Commands.PROPS_ARG).build()) - .addOption(Commands.VERSION_ARG.substring(0, 1), Commands.VERSION_ARG, false, "print version info"); + .addOption(Commands.HELP_ARG.substring(0, 1), + Commands.HELP_ARG, + false, + "print this help message") + .addOption(Commands.DEBUG_ARG.substring(0, 1), Commands.DEBUG_ARG, false, + "print debug & logging data directly to the console") + .addOption(Option.builder(Commands.PROPS_ARG.substring(0, 1)).hasArg() + .argName("file") + .desc("use " + "alternate properties file") + .longOpt(Commands.PROPS_ARG).build()) + .addOption(Commands.VERSION_ARG.substring(0, 1), + Commands.VERSION_ARG, + false, + "print version info"); // Parse the command line final CommandLineParser parser = new DefaultParser(); @@ -347,7 +362,7 @@ public class Mobibot extends PircBot { final Properties p = new Properties(); try (final InputStream fis = Files.newInputStream( - Paths.get(line.getOptionValue(Commands.PROPS_ARG.charAt(0), "./mobibot.properties")))) { + Paths.get(line.getOptionValue(Commands.PROPS_ARG.charAt(0), "./mobibot.properties")))) { // Load the properties files p.load(fis); } catch (FileNotFoundException e) { @@ -368,7 +383,7 @@ public class Mobibot extends PircBot { if (!line.hasOption(Commands.DEBUG_ARG.charAt(0))) { try { final PrintStream stdout = new PrintStream( - new FileOutputStream(logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true)); + new FileOutputStream(logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true)); System.setOut(stdout); } catch (IOException e) { System.err.println("Unable to open output (stdout) log file."); @@ -423,7 +438,7 @@ public class Mobibot extends PircBot { * @param action The action. */ private void action(final String channel, final String action) { - if (StringUtils.isNotBlank(channel) && StringUtils.isNotBlank(action)) { + if (isNotBlank(channel) && isNotBlank(action)) { sendAction(channel, action); } } @@ -431,7 +446,7 @@ public class Mobibot extends PircBot { /** * Connects to the server and joins the channel. */ - @SuppressFBWarnings({"DM_EXIT", "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE"}) + @SuppressFBWarnings({ "DM_EXIT", "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE" }) public final void connect() { try { connect(ircServer, ircPort); @@ -447,7 +462,7 @@ public class Mobibot extends PircBot { if (retries == MAX_RECONNECT) { if (logger.isDebugEnabled()) { logger.debug( - "Unable to reconnect to {} after {} retries.", ircServer, MAX_RECONNECT, ex); + "Unable to reconnect to {} after {} retries.", ircServer, MAX_RECONNECT, ex); } e.printStackTrace(System.err); @@ -470,7 +485,7 @@ public class Mobibot extends PircBot { * @param sender The nick of the person who sent the private message. */ private void feedResponse(final String sender) { - if (StringUtils.isNotBlank(feedUrl)) { + if (isNotBlank(feedUrl)) { new Thread(new FeedReader(this, sender, feedUrl)).start(); } else { send(sender, "There is no weblog setup for this channel."); @@ -561,7 +576,7 @@ public class Mobibot extends PircBot { for (final char c : getNick().toCharArray()) { if (Character.isLetter(c)) { buff.append('[').append(String.valueOf(c).toLowerCase(Constants.LOCALE)).append( - String.valueOf(c).toUpperCase(Constants.LOCALE)).append(']'); + String.valueOf(c).toUpperCase(Constants.LOCALE)).append(']'); } else { buff.append(c); } @@ -606,7 +621,7 @@ public class Mobibot extends PircBot { * @return The indented help string. */ public String helpIndent(final String help, final boolean isBold) { - return " " + (isBold ? Utils.bold(help) : help); + return " " + (isBold ? bold(help) : help); } /** @@ -619,21 +634,21 @@ public class Mobibot extends PircBot { final String lcTopic = topic.toLowerCase(Constants.LOCALE).trim(); if (Commands.HELP_POSTING_KEYWORD.equals(lcTopic)) { - send(sender, Utils.bold("Post a URL, by saying it on a line on its own:")); + send(sender, bold("Post a URL, by saying it on a line on its own:")); send(sender, helpIndent(" [] [" + TAGS_MARKER + "<+tag> [...]]")); - send(sender, "I will reply with a label, for example: " + Utils.bold(Commands.LINK_CMD + '1')); + send(sender, "I will reply with a label, for example: " + bold(Commands.LINK_CMD + '1')); send(sender, "To add a title, use a its label and a pipe:"); send(sender, helpIndent(Commands.LINK_CMD + "1:|This is the title")); send(sender, "To add a comment: "); send(sender, helpIndent(Commands.LINK_CMD + "1:This is a comment")); - send(sender, "I will reply with a label, for example: " + Utils.bold(Commands.LINK_CMD + "1.1")); + send(sender, "I will reply with a label, for example: " + bold(Commands.LINK_CMD + "1.1")); send(sender, "To edit a comment, use its label: "); send(sender, helpIndent(Commands.LINK_CMD + "1.1:This is an edited comment")); send(sender, "To delete a comment, use its label and a minus sign: "); send(sender, helpIndent(Commands.LINK_CMD + "1.1:-")); send(sender, "You can also view a posting by saying its label."); } else if (Commands.HELP_TAGS_KEYWORD.equals(lcTopic)) { - send(sender, Utils.bold("To categorize or tag a URL, use its label and a T:")); + send(sender, bold("To categorize or tag a URL, use its label and a T:")); send(sender, helpIndent(Commands.LINK_CMD + "1T:<+tag|-tag> [...]")); } else if (Commands.VIEW_CMD.equals(lcTopic)) { send(sender, "To list or search the current URL posts:"); @@ -685,7 +700,7 @@ public class Mobibot extends PircBot { } } - send(sender, Utils.bold("Type a URL on " + ircChannel + " to post it.")); + send(sender, bold("Type a URL on " + ircChannel + " to post it.")); send(sender, "For more information on a specific command, type:"); send(sender, helpIndent(getNick() + ": " + Commands.HELP_CMD + " <command>")); send(sender, "The commands are:"); @@ -743,12 +758,12 @@ public class Mobibot extends PircBot { */ private void identify() { // Identify with NickServ - if (StringUtils.isNotBlank(identPwd)) { + if (isNotBlank(identPwd)) { identify(identPwd); } // Identify with a specified nick - if (StringUtils.isNotBlank(identNick) && StringUtils.isNotBlank(identMsg)) { + if (isNotBlank(identNick) && isNotBlank(identMsg)) { sendMessage(identNick, identMsg); } } @@ -818,7 +833,7 @@ public class Mobibot extends PircBot { final StringBuilder info = new StringBuilder(29); info.append("Uptime: ").append(Utils.uptime(ManagementFactory.getRuntimeMXBean().getUptime())).append( - " [Entries: ").append(entries.size()); + " [Entries: ").append(entries.size()); if (tell.isEnabled() && isOp(sender)) { info.append(", Messages: ").append(tell.size()); @@ -836,7 +851,7 @@ public class Mobibot extends PircBot { * @return <code>true</code> if the nick should be ignored, <code>false</code> otherwise. */ private boolean isIgnoredNick(final String nick) { - return StringUtils.isNotBlank(nick) && ignoredNicks.contains(nick.toLowerCase(Constants.LOCALE)); + return isNotBlank(nick) && ignoredNicks.contains(nick.toLowerCase(Constants.LOCALE)); } /** @@ -871,7 +886,7 @@ public class Mobibot extends PircBot { */ @Override protected final void onDisconnect() { - if (StringUtils.isNotBlank(weblogUrl)) { + if (isNotBlank(weblogUrl)) { setVersion(weblogUrl); } @@ -883,7 +898,8 @@ public class Mobibot extends PircBot { /** * {@inheritDoc} */ - @SuppressFBWarnings(value = "CC_CYCLOMATIC_COMPLEXITY", justification = "Working on it.") + @SuppressFBWarnings(value = "CC_CYCLOMATIC_COMPLEXITY", + justification = "Working on it.") @Override protected final void onMessage(final String channel, final String sender, final String login, final String hostname, final String message) { @@ -923,7 +939,7 @@ public class Mobibot extends PircBot { if (data.length == 1) { title = data[0].trim(); } else { - if (StringUtils.isNotBlank(data[0])) { + if (isNotBlank(data[0])) { title = data[0].trim(); } @@ -936,7 +952,7 @@ public class Mobibot extends PircBot { final Document html = Jsoup.connect(link).userAgent("Mozilla").get(); final String htmlTitle = html.title(); - if (StringUtils.isNotBlank(htmlTitle)) { + if (isNotBlank(htmlTitle)) { title = htmlTitle; } } catch (IOException ignore) { @@ -962,7 +978,7 @@ public class Mobibot extends PircBot { } } else { final EntryLink entry = entries.get(dupIndex); - send(sender, Utils.bold("Duplicate") + " >> " + EntriesUtils.buildLink(dupIndex, entry)); + send(sender, bold("Duplicate") + " >> " + EntriesUtils.buildLink(dupIndex, entry)); } } } else if (message.matches(getNickPattern() + ":.*")) { // mobibot: <command> @@ -1000,7 +1016,7 @@ public class Mobibot extends PircBot { for (final AbstractModule module : MODULES) { // modules for (final String c : module.getCommands()) { if (cmd.startsWith(c)) { - module.commandResponse(this, sender, args, false); + module.commandResponse(this, sender, cmd, args, false); } } } @@ -1185,7 +1201,8 @@ public class Mobibot extends PircBot { /** * {@inheritDoc} */ - @SuppressFBWarnings(value = {"DM_EXIT", "CC_CYCLOMATIC_COMPLEXITY"}, justification = "Yes, we want to bail out.") + @SuppressFBWarnings(value = { "DM_EXIT", "CC_CYCLOMATIC_COMPLEXITY" }, + justification = "Yes, we want to bail out.") @Override protected final void onPrivateMessage(final String sender, final String login, final String hostname, final String message) { @@ -1280,7 +1297,7 @@ public class Mobibot extends PircBot { if (module.isPrivateMsgEnabled()) { for (final String c : module.getCommands()) { if (cmd.equals(c)) { - module.commandResponse(this, sender, args, true); + module.commandResponse(this, sender, cmd, args, true); return; } } @@ -1352,7 +1369,7 @@ public class Mobibot extends PircBot { * sent. */ public final void send(final String sender, final String message, final boolean isPrivate) { - if (StringUtils.isNotBlank(message) && StringUtils.isNotBlank(sender)) { + if (isNotBlank(message) && isNotBlank(sender)) { if (isPrivate) { if (logger.isDebugEnabled()) { logger.debug("Sending message to {} : {}", sender, message); @@ -1460,7 +1477,7 @@ public class Mobibot extends PircBot { * @param nicks The nicks to ignore */ final void setIgnoredNicks(final String nicks) { - if (StringUtils.isNotBlank(nicks)) { + if (isNotBlank(nicks)) { final StringTokenizer st = new StringTokenizer(nicks, ","); while (st.hasMoreTokens()) { @@ -1475,7 +1492,7 @@ public class Mobibot extends PircBot { * @param apiToken The API token */ final void setPinboardAuth(final String apiToken) { - if (StringUtils.isNotBlank(apiToken)) { + if (isNotBlank(apiToken)) { pinboard = new Pinboard(this, apiToken, ircServer); } } @@ -1520,7 +1537,7 @@ public class Mobibot extends PircBot { * @param msg The twitter message. */ final void twitterNotification(final String msg) { - if (twitterModule.isEnabled() && StringUtils.isNotBlank(twitterHandle)) { + if (twitterModule.isEnabled() && isNotBlank(twitterHandle)) { new Thread(() -> { try { twitterModule.post(twitterHandle, getName() + ' ' + ReleaseInfo.VERSION + " " + msg, true); @@ -1629,8 +1646,8 @@ public class Mobibot extends PircBot { || (entry.getNick().toLowerCase(Constants.LOCALE).contains(lcArgs))) { if (sent > MAX_ENTRIES) { send(sender, - "To view more, try: " + Utils - .bold(getNick() + ": " + Commands.VIEW_CMD + ' ' + (i + 1) + ' ' + lcArgs), + "To view more, try: " + + bold(getNick() + ": " + Commands.VIEW_CMD + ' ' + (i + 1) + ' ' + lcArgs), isPrivate); break; @@ -1642,7 +1659,7 @@ public class Mobibot extends PircBot { } else { if (sent > MAX_ENTRIES) { send(sender, - "To view more, try: " + Utils.bold(getNick() + ": " + Commands.VIEW_CMD + ' ' + (i + 1)), + "To view more, try: " + bold(getNick() + ": " + Commands.VIEW_CMD + ' ' + (i + 1)), isPrivate); break; diff --git a/src/main/java/net/thauvin/erik/mobibot/TwitterOAuth.java b/src/main/java/net/thauvin/erik/mobibot/TwitterOAuth.java index dc2f984..7d807d0 100644 --- a/src/main/java/net/thauvin/erik/mobibot/TwitterOAuth.java +++ b/src/main/java/net/thauvin/erik/mobibot/TwitterOAuth.java @@ -1,3 +1,35 @@ +/* + * TwitterOAuth.java + * + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package net.thauvin.erik.mobibot; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; diff --git a/src/main/java/net/thauvin/erik/mobibot/Utils.java b/src/main/java/net/thauvin/erik/mobibot/Utils.java index 5228e93..1049078 100644 --- a/src/main/java/net/thauvin/erik/mobibot/Utils.java +++ b/src/main/java/net/thauvin/erik/mobibot/Utils.java @@ -1,7 +1,7 @@ /* * Utils.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,6 +34,7 @@ package net.thauvin.erik.mobibot; import org.apache.commons.lang3.StringUtils; import org.jibble.pircbot.Colors; +import org.jsoup.Jsoup; import java.io.File; import java.time.LocalDateTime; @@ -233,8 +234,7 @@ public final class Utils { * @return The unescaped string. */ public static String unescapeXml(final String str) { - return str.replace("&", "&").replace("<", "<").replace(">", ">").replace(""", "\"").replace( - "'", "'").replace("'", "'"); + return Jsoup.parse(str).text(); } /** @@ -254,9 +254,9 @@ public final class Utils { final long weeks = days / 7; days %= 7; final long hours = TimeUnit.MILLISECONDS.toHours(uptime) - TimeUnit.DAYS.toHours( - TimeUnit.MILLISECONDS.toDays(uptime)); + TimeUnit.MILLISECONDS.toDays(uptime)); final long minutes = TimeUnit.MILLISECONDS.toMinutes(uptime) - TimeUnit.HOURS.toMinutes( - TimeUnit.MILLISECONDS.toHours(uptime)); + TimeUnit.MILLISECONDS.toHours(uptime)); if (years > 0) { info.append(years).append(plural(years, " year ", " years ")); diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java b/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java index 61e0871..2d5409d 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/AbstractModule.java @@ -1,7 +1,7 @@ /* * AbstractModule.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,11 +57,13 @@ public abstract class AbstractModule { * * @param bot The bot's instance. * @param sender The sender. + * @param cmd The command. * @param args The command arguments. * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. */ public abstract void commandResponse(final Mobibot bot, final String sender, + final String cmd, final String args, final boolean isPrivate); diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Calc.java b/src/main/java/net/thauvin/erik/mobibot/modules/Calc.java index b852614..05fb963 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Calc.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Calc.java @@ -1,7 +1,7 @@ /* * Calc.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -81,7 +81,11 @@ public class Calc extends AbstractModule { * {@inheritDoc} */ @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + public void commandResponse(final Mobibot bot, + final String sender, + final String cmd, + final String args, + final boolean isPrivate) { if (StringUtils.isNotBlank(args)) { bot.send(calc(args)); diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java b/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java index cc35860..a65beaa 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java @@ -1,7 +1,7 @@ /* * CurrencyConverter.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -87,44 +87,6 @@ public final class CurrencyConverter extends ThreadedModule { commands.add(CURRENCY_CMD); } - /** - * {@inheritDoc} - */ - @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { - synchronized (this) { - if (!pubDate.equals(Utils.today())) { - EXCHANGE_RATES.clear(); - } - } - - super.commandResponse(bot, sender, args, isPrivate); - } - - /** - * Converts the specified currencies. - */ - @SuppressFBWarnings("REDOS") - @Override - void run(final Mobibot bot, final String sender, final String query) { - if (StringUtils.isNotBlank(sender) && StringUtils.isNotBlank(query)) { - if (query.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+")) { - try { - final Message msg = convertCurrency(query); - if (msg.isError()) { - helpResponse(bot, sender, CURRENCY_CMD + ' ' + query, false); - } - bot.send(sender, msg); - } catch (ModuleException e) { - bot.getLogger().warn(e.getDebugMessage(), e); - bot.send(sender, e.getMessage()); - } - } else { - helpResponse(bot, sender, CURRENCY_CMD + ' ' + query, true); - } - } - } - /** * Converts from a currency to another. * @@ -157,8 +119,8 @@ public final class CurrencyConverter extends ThreadedModule { for (final Element rawCube : cubes) { cube = rawCube; EXCHANGE_RATES.put( - cube.getAttribute("currency").getValue(), - cube.getAttribute("rate").getValue()); + cube.getAttribute("currency").getValue(), + cube.getAttribute("rate").getValue()); } EXCHANGE_RATES.put("EUR", "1"); @@ -166,7 +128,7 @@ public final class CurrencyConverter extends ThreadedModule { throw new ModuleException(query, "An error has occurred while parsing the exchange rates table.", e); } catch (IOException e) { throw new ModuleException( - query, "An error has occurred while fetching the exchange rates table.", e); + query, "An error has occurred while fetching the exchange rates table.", e); } } @@ -181,23 +143,23 @@ public final class CurrencyConverter extends ThreadedModule { } else { try { final double amt = Double.parseDouble(cmds[0].replace(",", "")); - final double from = Double.parseDouble(EXCHANGE_RATES.get(cmds[1] - .toUpperCase(Constants.LOCALE))); + final double from = + Double.parseDouble(EXCHANGE_RATES.get(cmds[1].toUpperCase(Constants.LOCALE))); final double to = Double.parseDouble(EXCHANGE_RATES.get(cmds[3].toUpperCase(Constants.LOCALE))); return new PublicMessage( - NumberFormat.getCurrencyInstance(Locale.US).format(amt).substring(1) + NumberFormat.getCurrencyInstance(Locale.US).format(amt).substring(1) + ' ' + cmds[1].toUpperCase(Constants.LOCALE) + " = " + NumberFormat.getCurrencyInstance(Locale.US) - .format((amt * to) / from) - .substring(1) + .format((amt * to) / from) + .substring(1) + ' ' + cmds[3].toUpperCase(Constants.LOCALE)); } catch (Exception e) { throw new ModuleException("convertCurrency(" + query + ')', - "The supported currencies are: " + EXCHANGE_RATES.keySet(), e); + "The supported currencies are: " + EXCHANGE_RATES.keySet(), e); } } } else if (CURRENCY_RATES_KEYWORD.equals(query)) { @@ -219,6 +181,48 @@ public final class CurrencyConverter extends ThreadedModule { return new ErrorMessage("The supported currencies are: " + EXCHANGE_RATES.keySet()); } + /** + * {@inheritDoc} + */ + @Override + public void commandResponse(final Mobibot bot, + final String sender, + final String cmd, + final String args, + final boolean isPrivate) { + synchronized (this) { + if (!pubDate.equals(Utils.today())) { + EXCHANGE_RATES.clear(); + } + } + + super.commandResponse(bot, sender, cmd, args, isPrivate); + } + + /** + * Converts the specified currencies. + */ + @SuppressFBWarnings("REDOS") + @Override + void run(final Mobibot bot, final String sender, final String cmd, final String query) { + if (StringUtils.isNotBlank(sender) && StringUtils.isNotBlank(query)) { + if (query.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+")) { + try { + final Message msg = convertCurrency(query); + if (msg.isError()) { + helpResponse(bot, sender, CURRENCY_CMD + ' ' + query, false); + } + bot.send(sender, msg); + } catch (ModuleException e) { + bot.getLogger().warn(e.getDebugMessage(), e); + bot.send(sender, e.getMessage()); + } + } else { + helpResponse(bot, sender, CURRENCY_CMD + ' ' + query, true); + } + } + } + /** * {@inheritDoc} */ diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Dice.java b/src/main/java/net/thauvin/erik/mobibot/modules/Dice.java index 1e69b10..4b66917 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Dice.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Dice.java @@ -1,7 +1,7 @@ /* * Dice.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,15 +57,14 @@ public final class Dice extends AbstractModule { } /** - * Rolls the dice. - * - * @param bot The bot's instance. - * @param sender The sender. - * @param args The command arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + * {@inheritDoc} */ @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + public void commandResponse(final Mobibot bot, + final String sender, + final String cmd, + final String args, + final boolean isPrivate) { final SecureRandom r = new SecureRandom(); int i = r.nextInt(6) + 1; @@ -73,15 +72,15 @@ public final class Dice extends AbstractModule { final int playerTotal = i + y; bot.send(bot.getChannel(), - sender + " rolled two dice: " + Utils.bold(i) + " and " + Utils.bold(y) + " for a total of " - + Utils.bold(playerTotal)); + sender + " rolled two dice: " + Utils.bold(i) + " and " + Utils.bold(y) + " for a total of " + + Utils.bold(playerTotal)); i = r.nextInt(6) + 1; y = r.nextInt(6) + 1; final int total = i + y; bot.action( - "rolled two dice: " + Utils.bold(i) + " and " + Utils.bold(y) + " for a total of " + Utils.bold(total)); + "rolled two dice: " + Utils.bold(i) + " and " + Utils.bold(y) + " for a total of " + Utils.bold(total)); if (playerTotal < total) { bot.action("wins."); diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java b/src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java index 32b685b..34a7918 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/GoogleSearch.java @@ -1,7 +1,7 @@ /* * GoogleSearch.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -96,7 +96,7 @@ public final class GoogleSearch extends ThreadedModule { * Searches Google. */ @Override - void run(final Mobibot bot, final String sender, final String query) { + void run(final Mobibot bot, final String sender, final String cmd, final String query) { if (StringUtils.isNotBlank(query)) { try { final List<Message> results = searchGoogle(query, properties.get(GOOGLE_API_KEY_PROP), diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Joke.java b/src/main/java/net/thauvin/erik/mobibot/modules/Joke.java index 4c4c1ad..fef56c2 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Joke.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Joke.java @@ -1,7 +1,7 @@ /* * Joke.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -56,7 +56,7 @@ public final class Joke extends ThreadedModule { private static final String JOKE_CMD = "joke"; // The ICNDB URL. private static final String JOKE_URL = - "http://api.icndb.com/jokes/random?escape=javascript&exclude=[explicit]&limitTo=[nerdy]"; + "http://api.icndb.com/jokes/random?escape=javascript&exclude=[explicit]&limitTo=[nerdy]"; /** * Creates a new {@link Joke} instance. @@ -79,7 +79,7 @@ public final class Joke extends ThreadedModule { final StringBuilder sb = new StringBuilder(); try (final BufferedReader reader = - new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) { + new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { sb.append(line); @@ -88,8 +88,8 @@ public final class Joke extends ThreadedModule { final JSONObject json = new JSONObject(sb.toString()); return new PublicMessage( - json.getJSONObject("value").get("joke").toString().replace("\\'", "'") - .replace("\\\"", "\"")); + json.getJSONObject("value").get("joke").toString().replace("\\'", "'") + .replace("\\\"", "\"")); } } catch (Exception e) { throw new ModuleException("randomJoke()", "An error has occurred retrieving a random joke.", e); @@ -100,15 +100,19 @@ public final class Joke extends ThreadedModule { * {@inheritDoc} */ @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { - new Thread(() -> run(bot, sender, args)).start(); + public void commandResponse(final Mobibot bot, + final String sender, + final String cmd, + final String args, + final boolean isPrivate) { + new Thread(() -> run(bot, sender, cmd, args)).start(); } /** * Returns a random joke from <a href="http://www.icndb.com/">The Internet Chuck Norris Database</a>. */ @Override - void run(final Mobibot bot, final String sender, final String arg) { + void run(final Mobibot bot, final String sender, final String cmd, final String arg) { try { bot.send(Utils.cyan(randomJoke().getMessage())); } catch (ModuleException e) { diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java b/src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java index cdd8113..8c98c6a 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Lookup.java @@ -1,7 +1,7 @@ /* * Lookup.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -143,15 +143,14 @@ public final class Lookup extends AbstractModule { } /** - * Process a command. - * - * @param bot The bot's instance. - * @param sender The sender. - * @param args The command arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + * {@inheritDoc} */ @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + public void commandResponse(final Mobibot bot, + final String sender, + final String cmd, + final String args, + final boolean isPrivate) { if (args.matches("(\\S.)+(\\S)+")) { try { bot.send(Lookup.lookup(args)); diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Ping.java b/src/main/java/net/thauvin/erik/mobibot/modules/Ping.java index 07254bd..214a1ed 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Ping.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Ping.java @@ -1,7 +1,7 @@ /* * Ping.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,19 +50,19 @@ public class Ping extends AbstractModule { * The ping responses. */ static final List<String> PINGS = - Arrays.asList( - "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!"); + Arrays.asList( + "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!"); /** * The ping command. */ @@ -80,7 +80,11 @@ public class Ping extends AbstractModule { * {@inheritDoc} */ @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + public void commandResponse(final Mobibot bot, + final String sender, + final String cmd, + final String args, + final boolean isPrivate) { final SecureRandom r = new SecureRandom(); bot.action(PINGS.get(r.nextInt(PINGS.size()))); } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/src/main/java/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt new file mode 100644 index 0000000..387bc29 --- /dev/null +++ b/src/main/java/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt @@ -0,0 +1,116 @@ +/* + * RockPaperScissors.kt + * + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.Mobibot +import net.thauvin.erik.mobibot.Utils +import kotlin.random.Random + + + +/** + * Simple module example in Kotlin. + */ +class RockPaperScissors : AbstractModule() { + init { + with(commands) { + add(Shapes.ROCK.value) + add(Shapes.SCISSORS.value) + add(Shapes.PAPER.value) + } + } + + enum class Shapes(val value: String) { + ROCK("rock"), PAPER("paper"), SCISSORS("scissors") + } + + enum class Results { + WIN, LOSE, DRAW + } + + companion object { + /** + * Returns the the randomly picked shape and result. + */ + fun winLoseOrDraw(hand: Shapes): Pair<Shapes, Results> { + val botHand = Shapes.values()[Random.nextInt(0, Shapes.values().size)] + val result: Results + if (botHand == hand) { + result = Results.DRAW + } else { + when (botHand) { + Shapes.ROCK -> { + result = if (hand == Shapes.PAPER) { + Results.WIN + } else { + Results.LOSE + } + } + Shapes.PAPER -> { + result = if (hand == Shapes.ROCK) { + Results.LOSE + } else { + Results.WIN + } + } + Shapes.SCISSORS -> { + result = if (hand == Shapes.ROCK) { + Results.WIN + } else { + Results.LOSE + } + } + } + } + return Pair(botHand, result) + } + } + + override fun commandResponse(bot: Mobibot?, sender: String?, cmd: String?, args: String?, isPrivate: Boolean) { + val result = winLoseOrDraw(Shapes.valueOf(cmd!!.toUpperCase())) + val picked = "picked ${Utils.bold(result.first.value)}." + when (result.second) { + Results.WIN -> bot!!.action("$picked You win.") + Results.LOSE -> bot!!.action("$picked You lose.") + else -> bot!!.action("$picked We have a draw.") + } + } + + override fun helpResponse(bot: Mobibot?, sender: String?, args: String?, isPrivate: Boolean) { + bot!!.send(sender, "To play Rock Paper Scissors:") + bot.send( + sender, + bot.helpIndent("${bot.nick}: ${Shapes.ROCK.value} or ${Shapes.PAPER.value} or ${Shapes.SCISSORS.value}") + ) + } +} diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java b/src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java index d9cc1c6..a7832fd 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/StockQuote.java @@ -1,7 +1,7 @@ /* * StockQuote.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -211,7 +211,7 @@ public final class StockQuote extends ThreadedModule { * Returns the specified stock quote from Alpha Advantage. */ @Override - void run(final Mobibot bot, final String sender, final String symbol) { + void run(final Mobibot bot, final String sender, final String cmd, final String symbol) { if (StringUtils.isNotBlank(symbol)) { try { final List<Message> messages = getQuote(symbol, properties.get(ALPHAVANTAGE_API_KEY_PROP)); diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/ThreadedModule.java b/src/main/java/net/thauvin/erik/mobibot/modules/ThreadedModule.java index 99917f7..7119950 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/ThreadedModule.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/ThreadedModule.java @@ -1,7 +1,7 @@ /* * ThreadedModule.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,9 +46,13 @@ public abstract class ThreadedModule extends AbstractModule { * {@inheritDoc} */ @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + public void commandResponse(final Mobibot bot, + final String sender, + final String cmd, + final String args, + final boolean isPrivate) { if (isEnabled() && args.length() > 0) { - new Thread(() -> run(bot, sender, args)).start(); + new Thread(() -> run(bot, sender, cmd, args)).start(); } else { helpResponse(bot, sender, args, isPrivate); } @@ -57,5 +61,5 @@ public abstract class ThreadedModule extends AbstractModule { /** * Runs the thread. */ - abstract void run(Mobibot bot, String sender, String args); + abstract void run(Mobibot bot, String sender, @SuppressWarnings("unused") String cmd, String args); } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java b/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java index aaf6a1d..9b7d9c6 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.java @@ -1,7 +1,7 @@ /* * Twitter.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -148,7 +148,7 @@ public final class Twitter extends ThreadedModule { * Posts to twitter. */ @Override - void run(final Mobibot bot, final String sender, final String message) { + void run(final Mobibot bot, final String sender, final String cmd, final String message) { try { bot.send(sender, post(sender, message, false).getMessage()); } catch (ModuleException e) { diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/War.java b/src/main/java/net/thauvin/erik/mobibot/modules/War.java index 9267c0f..a438b1e 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/War.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/War.java @@ -1,7 +1,7 @@ /* * War.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,9 +49,9 @@ public final class War extends AbstractModule { private static final String WAR_CMD = "war"; // The deck of card. private static final String[] WAR_DECK = - new String[]{"Ace", "King", "Queen", "Jack", "10", "9", "8", "7", "6", "5", "4", "3", "2"}; + new String[]{ "Ace", "King", "Queen", "Jack", "10", "9", "8", "7", "6", "5", "4", "3", "2" }; // The suits for the deck of card. - private static final String[] WAR_SUITS = new String[]{"Hearts", "Spades", "Diamonds", "Clubs"}; + private static final String[] WAR_SUITS = new String[]{ "Hearts", "Spades", "Diamonds", "Clubs" }; /** * The default constructor. @@ -62,15 +62,14 @@ public final class War extends AbstractModule { } /** - * Plays war. - * - * @param bot The bot's instance. - * @param sender The sender. - * @param args The command arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + * {@inheritDoc} */ @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + public void commandResponse(final Mobibot bot, + final String sender, + final String cmd, + final String args, + final boolean isPrivate) { final SecureRandom r = new SecureRandom(); int i; @@ -81,7 +80,7 @@ public final class War extends AbstractModule { y = r.nextInt(WAR_DECK.length); bot.send(bot.getChannel(), - sender + " drew the " + Utils.bold(WAR_DECK[i]) + " of " + WAR_SUITS[r.nextInt(WAR_SUITS.length)]); + sender + " drew the " + Utils.bold(WAR_DECK[i]) + " of " + WAR_SUITS[r.nextInt(WAR_SUITS.length)]); bot.action("drew the " + Utils.bold(WAR_DECK[y]) + " of " + WAR_SUITS[r.nextInt(WAR_SUITS.length)]); if (i != y) { diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Weather2.java b/src/main/java/net/thauvin/erik/mobibot/modules/Weather2.java index aad3e42..52271ba 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Weather2.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Weather2.java @@ -1,7 +1,7 @@ /* * Weather2.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -217,7 +217,7 @@ public class Weather2 extends ThreadedModule { * Fetches the weather data from a specific city. */ @Override - void run(final Mobibot bot, final String sender, final String args) { + void run(final Mobibot bot, final String sender, final String cmd, final String args) { if (StringUtils.isNotBlank(args)) { try { final List<Message> messages = getWeather(args, properties.get(OWM_API_KEY_PROP)); diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java b/src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java index 6000a91..745c83a 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/WorldTime.java @@ -1,7 +1,7 @@ /* * WorldTime.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -146,9 +146,9 @@ public final class WorldTime extends AbstractModule { countries.put("INTERNET", BEATS_KEYWORD); countries.put("BEATS", BEATS_KEYWORD); - ZoneId.getAvailableZoneIds().stream().filter(tz -> - !tz.contains("/") && tz.length() == 3 && !countries.containsKey(tz)).forEach(tz -> - countries.put(tz, tz)); + ZoneId.getAvailableZoneIds().stream() + .filter(tz -> !tz.contains("/") && tz.length() == 3 && !countries.containsKey(tz)) + .forEach(tz -> countries.put(tz, tz)); COUNTRIES_MAP = Collections.unmodifiableMap(countries); } @@ -162,15 +162,58 @@ public final class WorldTime extends AbstractModule { } /** - * Responds with the current time in the specified timezone/country. + * Returns the current Internet (beat) Time. * - * @param bot The bot's instance. - * @param sender The sender. - * @param args The command arguments. - * @param isPrivate Set to <code>true</code> if the response should be sent as a private message. + * @return The Internet Time string. + */ + private static String internetTime() { + final ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("UTC+01:00")); + final int beats = (int) ((zdt.get(ChronoField.SECOND_OF_MINUTE) + (zdt.get(ChronoField.MINUTE_OF_HOUR) * 60) + + (zdt.get(ChronoField.HOUR_OF_DAY) * 3600)) / 86.4); + return String.format("%c%03d", '@', beats); + } + + /** + * Returns the world time. + * + * <ul> + * <li>PST</li> + * <li>BEATS</li> + * </ul> + * + * @param query The query. + * @return The {@link Message} containing the world time. + */ + @SuppressFBWarnings("STT_STRING_PARSING_A_FIELD") + static Message worldTime(final String query) { + final String tz = (COUNTRIES_MAP.get((query.substring(query.indexOf(' ') + 1).trim() + .toUpperCase(Constants.LOCALE)))); + final String response; + + if (tz != null) { + if (BEATS_KEYWORD.equals(tz)) { + response = ("The current Internet Time is: " + internetTime() + ' ' + BEATS_KEYWORD); + } else { + response = ZonedDateTime.now().withZoneSameInstant(ZoneId.of(tz)).format( + DateTimeFormatter.ofPattern("'The time is 'HH:mm' on 'EEEE, d MMMM yyyy' in '")) + + tz.substring(tz.indexOf('/') + 1).replace('_', ' '); + } + } else { + return new ErrorMessage("The supported countries/zones are: " + COUNTRIES_MAP.keySet()); + } + + return new PublicMessage(response); + } + + /** + * {@inheritDoc} */ @Override - public void commandResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) { + public void commandResponse(final Mobibot bot, + final String sender, + final String cmd, + final String args, + final boolean isPrivate) { final Message msg = worldTime(args); if (isPrivate) { @@ -203,48 +246,4 @@ public final class WorldTime extends AbstractModule { public boolean isPrivateMsgEnabled() { return true; } - - /** - * Returns the current Internet (beat) Time. - * - * @return The Internet Time string. - */ - private static String internetTime() { - final ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("UTC+01:00")); - final int beats = (int) ((zdt.get(ChronoField.SECOND_OF_MINUTE) + (zdt.get(ChronoField.MINUTE_OF_HOUR) * 60) - + (zdt.get(ChronoField.HOUR_OF_DAY) * 3600)) / 86.4); - return String.format("%c%03d", '@', beats); - } - - /** - * Returns the world time. - * - * <ul> - * <li>PST</li> - * <li>BEATS</li> - * </ul> - * - * @param query The query. - * @return The {@link Message} containing the world time. - */ - @SuppressFBWarnings("STT_STRING_PARSING_A_FIELD") - static Message worldTime(final String query) { - final String tz = (COUNTRIES_MAP.get((query.substring(query.indexOf(' ') + 1).trim() - .toUpperCase(Constants.LOCALE)))); - final String response; - - if (tz != null) { - if (BEATS_KEYWORD.equals(tz)) { - response = ("The current Internet Time is: " + internetTime() + ' ' + BEATS_KEYWORD); - } else { - response = ZonedDateTime.now().withZoneSameInstant(ZoneId.of(tz)).format( - DateTimeFormatter.ofPattern("'The time is 'HH:mm' on 'EEEE, d MMMM yyyy' in '")) - + tz.substring(tz.indexOf('/') + 1).replace('_', ' '); - } - } else { - return new ErrorMessage("The supported countries/zones are: " + COUNTRIES_MAP.keySet()); - } - - return new PublicMessage(response); - } } diff --git a/src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.java b/src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.java index fd0650d..cc4ad92 100644 --- a/src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.java +++ b/src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.java @@ -1,7 +1,7 @@ /* * EntryLinkTest.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/test/java/net/thauvin/erik/mobibot/modules/AbstractModuleTest.java b/src/test/java/net/thauvin/erik/mobibot/modules/AbstractModuleTest.java index fb87f9a..5eab364 100644 --- a/src/test/java/net/thauvin/erik/mobibot/modules/AbstractModuleTest.java +++ b/src/test/java/net/thauvin/erik/mobibot/modules/AbstractModuleTest.java @@ -1,7 +1,7 @@ /* * AbstractModuleTest.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/test/java/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/src/test/java/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt new file mode 100644 index 0000000..1df6908 --- /dev/null +++ b/src/test/java/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt @@ -0,0 +1,67 @@ +/* + * RockPaperScissorsTest.kt + * + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package net.thauvin.erik.mobibot.modules + +import net.thauvin.erik.mobibot.modules.RockPaperScissors.Results +import net.thauvin.erik.mobibot.modules.RockPaperScissors.Shapes +import org.assertj.core.api.Assertions.assertThat +import org.testng.annotations.Test + +class RockPaperScissorsTest { + @Test(invocationCount = 5) + fun testWinLoseOrDraw() { + var play = RockPaperScissors.winLoseOrDraw(Shapes.SCISSORS) + // println("SCISSORS vs ${play.first}: ${play.second}") + when (play.first) { + Shapes.SCISSORS -> assertThat(play.second).`as`("SCISSORS vs ${play.first}").isEqualTo(Results.DRAW) + Shapes.ROCK -> assertThat(play.second).`as`("SCISSORS vs ${play.first}").isEqualTo(Results.LOSE) + else -> assertThat(play.second).`as`("SCISSORS vs ${play.first}").isEqualTo(Results.WIN) + } + + play = RockPaperScissors.winLoseOrDraw(Shapes.ROCK) + // println("ROCK vs ${play.first}: ${play.second}") + when (play.first) { + Shapes.SCISSORS -> assertThat(play.second).`as`("ROCK vs ${play.first}").isEqualTo(Results.WIN) + Shapes.ROCK -> assertThat(play.second).`as`("ROCK vs ${play.first}").isEqualTo(Results.DRAW) + else -> assertThat(play.second).`as`("ROCK vs ${play.first}").isEqualTo(Results.LOSE) + } + + play = RockPaperScissors.winLoseOrDraw(Shapes.PAPER) + // println("PAPER vs ${play.first}: ${play.second}") + when (play.first) { + Shapes.SCISSORS -> assertThat(play.second).`as`("PAPER vs ${play.first}").isEqualTo(Results.LOSE) + Shapes.ROCK -> assertThat(play.second).`as`("PAPER vs ${play.first}").isEqualTo(Results.WIN) + else -> assertThat(play.second).`as`("PAPER vs ${play.first}").isEqualTo(Results.DRAW) + } + } +} diff --git a/src/test/java/net/thauvin/erik/mobibot/tell/TellMessageTest.java b/src/test/java/net/thauvin/erik/mobibot/tell/TellMessageTest.java index 28f0fec..04927a8 100644 --- a/src/test/java/net/thauvin/erik/mobibot/tell/TellMessageTest.java +++ b/src/test/java/net/thauvin/erik/mobibot/tell/TellMessageTest.java @@ -1,7 +1,7 @@ /* * TellMessageTest.java * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/version.properties b/version.properties index adae677..0f65d20 100644 --- a/version.properties +++ b/version.properties @@ -1,9 +1,9 @@ #Generated by the Semver Plugin for Gradle -#Wed Mar 18 16:00:11 PDT 2020 -version.buildmeta=581 +#Mon Mar 23 05:21:18 PDT 2020 +version.buildmeta=682 version.major=0 version.minor=7 version.patch=3 version.prerelease=beta version.project=mobibot -version.semver=0.7.3-beta+581 +version.semver=0.7.3-beta+682