Added Addons to handle adding commands & modules and related properties.

Commands now have their own properties and are initialized with the bot instance.
This commit is contained in:
Erik C. Thauvin 2020-04-28 21:01:18 -07:00
parent e2faa55c9f
commit 5c3b2074ba
52 changed files with 669 additions and 570 deletions

View file

@ -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(1587078052972L), ZoneId.systemDefault());
LocalDateTime.ofInstant(Instant.ofEpochMilli(1588132687770L), ZoneId.systemDefault());
public static final int MAJOR = 0;
public static final int MINOR = 8;
public static final int PATCH = 0;
public static final String PRERELEASE = "alpha";
public static final String BUILDMETA = "294";
public static final String VERSION = "0.8.0-alpha+294";
public static final String BUILDMETA = "348";
public static final String VERSION = "0.8.0-alpha+348";
/**
* Disables the default constructor.

View file

@ -0,0 +1,99 @@
/*
* Addons.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 net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.modules.AbstractModule
import java.util.*
import kotlin.collections.ArrayList
/**
* Modules and Commands addons.
*/
class Addons {
val commands: MutableList<AbstractCommand> = ArrayList()
val modules: MutableList<AbstractModule> = ArrayList()
val modulesNames: MutableList<String> = ArrayList()
val names: MutableList<String> = ArrayList()
val ops: MutableList<String> = ArrayList()
/**
* Add a module with properties.
*/
fun add(module: AbstractModule, props: Properties) {
with(module) {
if (hasProperties()) {
propertyKeys.forEach {
setProperty(it, props.getProperty(it, ""))
}
}
if (isEnabled) {
modules.add(this)
modulesNames.add(this.javaClass.simpleName)
names.addAll(this.commands)
}
}
}
/**
* Add a command with properties.
*/
fun add(command: AbstractCommand, props: Properties) {
with(command) {
if (hasProperties()) {
getPropertyKeys().forEach {
setProperty(it, props.getProperty(it, ""))
}
}
if (isEnabled()) {
commands.add(this)
if (isVisible) {
if (isOp) {
ops.add(name)
} else {
names.add(name)
}
}
}
}
}
/**
* Sort commands and modules names.
*/
fun sort() {
names.sort()
ops.sort()
modulesNames.sort()
}
}

View file

@ -94,14 +94,7 @@ public final class Constants {
* The timer delay in minutes.
*/
public static final long TIMER_DELAY = 10L;
/**
* The twitter post flag property key.
*/
public static final String TWITTER_AUTOPOST_PROP = "twitter-auto-post";
/**
* The Twitter handle property key.
*/
public static final String TWITTER_HANDLE_PROP = "twitter-handle";
/**
* Properties version line argument.
*/

View file

@ -62,7 +62,6 @@ import net.thauvin.erik.mobibot.modules.Dice;
import net.thauvin.erik.mobibot.modules.GoogleSearch;
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;
@ -94,12 +93,8 @@ import java.io.InputStream;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.Timer;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -116,7 +111,9 @@ import static org.apache.commons.lang3.StringUtils.lowerCase;
@Version(properties = "version.properties",
className = "ReleaseInfo")
public class Mobibot extends PircBot {
// Info strings
/**
* Info Strings.
*/
@SuppressWarnings("indentation")
public static final List<String> INFO =
List.of(
@ -129,16 +126,8 @@ public class Mobibot extends PircBot {
private static final int MAX_RECONNECT = 10;
// Timer
private static final Timer TIMER = new Timer(true);
// Ignore command
public final Ignore ignoreCommand;
// Automatically post links to Twitter
public final boolean isTwitterAutoPost;
// Tell object
public final Tell tell;
// Commands
private final List<AbstractCommand> commands = new ArrayList<>(20);
// Commands Names
private final List<String> commandsNames = new ArrayList<>();
// Commands and Modules
private final Addons addons = new Addons();
// Main channel
private final String ircChannel;
// IRC port
@ -149,20 +138,12 @@ public class Mobibot extends PircBot {
private final Level loggerLevel;
// Log directory
private final String logsDir;
// Modules
private final List<AbstractModule> modules = new ArrayList<>(0);
// Modules
private final List<String> modulesNames = new ArrayList<>(0);
// Operators commands names
private final List<String> opsCommandsNames = new ArrayList<>();
// Tell command
private final Tell tell;
// Today's date
private final String today = Utils.today();
// Twitter auto-posts.
private final Set<Integer> twitterEntries = new HashSet<>();
// Twitter handle for channel join notifications
private final String twitterHandle;
// Twitter module
private final Twitter twitterModule;
private final Twitter twitter;
// Backlogs URL
private String backLogsUrl = "";
// Ident message
@ -176,7 +157,6 @@ public class Mobibot extends PircBot {
// Weblog URL
private String weblogUrl = "";
/**
* Creates a new {@link Mobibot} instance.
*
@ -226,71 +206,51 @@ public class Mobibot extends PircBot {
setPinboardAuth(p.getProperty("pinboard-api-token"));
// Load the commands
addCommand(new AddLog());
addCommand(new ChannelFeed(getChannelName(), p.getProperty("feed", "")));
addCommand(new Cycle());
addCommand(new Info());
addCommand(new Me());
addCommand(new Modules());
addCommand(new Msg());
addCommand(new Nick());
addCommand(new Recap());
addCommand(new Say());
addCommand(new Users());
addCommand(new Versions());
// Ignore command
ignoreCommand = new Ignore(p.getProperty("ignore", ""));
addCommand(ignoreCommand);
addons.add(new AddLog(this), p);
addons.add(new ChannelFeed(this, getChannelName()), p);
addons.add(new Cycle(this), p);
addons.add(new Ignore(this), p);
addons.add(new Info(this), p);
addons.add(new Me(this), p);
addons.add(new Modules(this), p);
addons.add(new Msg(this), p);
addons.add(new Nick(this), p);
addons.add(new Recap(this), p);
addons.add(new Say(this), p);
addons.add(new Users(this), p);
addons.add(new Versions(this), p);
// Tell command
tell = new Tell(this, p.getProperty("tell-max-days"), p.getProperty("tell-max-size"));
if (tell.isEnabled()) {
addCommand(tell);
}
tell = new Tell(this);
addons.add(tell, p);
// Load the links commands
addCommand(new Comment());
addCommand(new Posting());
addCommand(new Tags());
addCommand(new UrlMgr(p.getProperty("tags", ""), p.getProperty("tags-keywords", "")));
addCommand(new View());
addons.add(new Comment(this), p);
addons.add(new Posting(this), p);
addons.add(new Tags(this), p);
addons.add(new UrlMgr(this), p);
addons.add(new View(this), p);
// Load the modules
addModule(new Calc());
addModule(new CurrencyConverter());
addModule(new Dice());
addModule(new GoogleSearch());
addModule(new Joke());
addModule(new Lookup());
addModule(new Ping());
addModule(new RockPaperScissors());
addModule(new StockQuote());
addModule(new War());
addModule(new Weather2());
addModule(new WorldTime());
addons.add(new Calc(this), p);
addons.add(new CurrencyConverter(this), p);
addons.add(new Dice(this), p);
addons.add(new GoogleSearch(this), p);
addons.add(new Joke(this), p);
addons.add(new Lookup(this), p);
addons.add(new Ping(this), p);
addons.add(new RockPaperScissors(this), p);
addons.add(new StockQuote(this), p);
addons.add(new War(this), p);
addons.add(new Weather2(this), p);
addons.add(new WorldTime(this), p);
// Twitter module
twitterModule = new Twitter();
addModule(twitterModule);
twitter = new Twitter(this);
addons.add(twitter, p);
// Load the modules properties
modules.stream().filter(AbstractModule::hasProperties).forEach(module -> {
for (final String s : module.getPropertyKeys()) {
module.setProperty(s, p.getProperty(s, ""));
}
});
// Twitter extra properties
twitterHandle = p.getProperty(Constants.TWITTER_HANDLE_PROP, "");
isTwitterAutoPost =
Boolean.parseBoolean(p.getProperty(Constants.TWITTER_AUTOPOST_PROP, "false"))
&& twitterModule.isEnabled();
// Sort the command & module names
Collections.sort(commandsNames);
Collections.sort(opsCommandsNames);
Collections.sort(modulesNames);
// Sort the addons
addons.sort();
// Save the entries
UrlMgr.saveEntries(this, true);
@ -415,33 +375,6 @@ public class Mobibot extends PircBot {
}
}
/**
* Adds a command.
*
* @param command The command to add.
*/
private void addCommand(final AbstractCommand command) {
commands.add(command);
if (command.isVisible()) {
if (command.isOp()) {
opsCommandsNames.add(command.getCommand());
} else {
commandsNames.add(command.getCommand());
}
}
}
/**
* Adds a module.
*
* @param module The module to add.
*/
private void addModule(final AbstractModule module) {
modules.add(module);
modulesNames.add(module.getClass().getSimpleName());
commandsNames.addAll(module.getCommands());
}
/**
* Adds pin on pinboard.
*
@ -487,10 +420,13 @@ public class Mobibot extends PircBot {
*
* @param entry The entry to delete.
*/
public final void deletePin(final EntryLink entry) {
public final void deletePin(final int index, final EntryLink entry) {
if (pinboard != null) {
pinboard.deletePost(entry);
}
if (twitter.isAutoPost()) {
twitter.removeEntry(index);
}
}
/**
@ -554,7 +490,7 @@ public class Mobibot extends PircBot {
* @return The modules names.
*/
public final List<String> getModulesNames() {
return modulesNames;
return addons.getModulesNames();
}
/**
@ -577,6 +513,15 @@ public class Mobibot extends PircBot {
return buff.toString();
}
/**
* Returns the Tell command.
*
* @return The tell command.
*/
public final Tell getTell() {
return tell;
}
/**
* Returns the bot's timer.
*
@ -595,6 +540,15 @@ public class Mobibot extends PircBot {
return today;
}
/**
* Returns the Twitter command.
*
* @return The Twitter command.
*/
public final Twitter getTwitter() {
return twitter;
}
/**
* Returns the weblog URL.
*
@ -613,9 +567,9 @@ public class Mobibot extends PircBot {
* @return {@code true} if the topic was found, {@code false} otherwise.
*/
private boolean helpCommands(final String sender, final String topic, final boolean isPrivate) {
for (final AbstractCommand command : commands) {
if (command.isVisible() && command.getCommand().startsWith(topic)) {
return command.helpResponse(this, topic, sender, isOp(sender), isPrivate);
for (final AbstractCommand command : addons.getCommands()) {
if (command.isVisible() && command.getName().startsWith(topic)) {
return command.helpResponse(topic, sender, isOp(sender), isPrivate);
}
}
return false;
@ -635,10 +589,10 @@ public class Mobibot extends PircBot {
Utils.helpIndent(Utils.helpFormat("%c " + Constants.HELP_CMD + " <command>", getNick(), isPrivate)),
isPrivate);
send(sender, "The commands are:", isPrivate);
sendList(sender, commandsNames, 8, isPrivate, true);
sendList(sender, addons.getNames(), 8, isPrivate, true);
if (isOp) {
send(sender, "The op commands are:", isPrivate);
sendList(sender, opsCommandsNames, 8, isPrivate, true);
sendList(sender, addons.getOps(), 8, isPrivate, true);
}
}
@ -651,13 +605,11 @@ public class Mobibot extends PircBot {
* @return {@code true} if the topic was found, {@code false} otherwise.
*/
private boolean helpModules(final String sender, final String topic, final boolean isPrivate) {
for (final AbstractModule module : modules) {
if (module.isEnabled()) {
for (final String cmd : module.getCommands()) {
if (topic.equals(cmd)) {
module.helpResponse(this, sender, isPrivate);
return true;
}
for (final AbstractModule module : addons.getModules()) {
for (final String cmd : module.getCommands()) {
if (topic.equals(cmd)) {
module.helpResponse(sender, isPrivate);
return true;
}
}
}
@ -721,7 +673,7 @@ public class Mobibot extends PircBot {
*/
public final void joinChannel() {
joinChannel(ircChannel);
twitterNotification("has joined " + ircChannel);
twitter.notification("%1$s %2$s has joined %3$s");
}
/**
@ -746,9 +698,7 @@ public class Mobibot extends PircBot {
final String message) {
LOGGER.debug(">>> {} : {}", sender, message);
if (tell.isEnabled()) {
tell.send(sender, true);
}
tell.send(sender, true);
if (message.matches(getNickPattern() + ":.*")) { // mobibot: <command>
final String[] cmds = message.substring(message.indexOf(':') + 1).trim().split(" ", 2);
@ -764,17 +714,17 @@ public class Mobibot extends PircBot {
helpResponse(sender, args, false);
} else {
// Commands
for (final AbstractCommand command : commands) {
if (command.isPublic() && command.getCommand().startsWith(cmd)) {
command.commandResponse(this, sender, login, args, isOp(sender), false);
for (final AbstractCommand command : addons.getCommands()) {
if (command.isPublic() && command.getName().startsWith(cmd)) {
command.commandResponse(sender, login, args, isOp(sender), false);
return;
}
}
// Modules
for (final AbstractModule module : modules) { // modules
for (final AbstractModule module : addons.getModules()) { // modules
for (final String c : module.getCommands()) {
if (cmd.startsWith(c)) {
module.commandResponse(this, sender, cmd, args, false);
module.commandResponse(sender, cmd, args, false);
return;
}
}
@ -782,9 +732,9 @@ public class Mobibot extends PircBot {
}
} else {
// Commands, e.g.: https://www.example.com/
for (final AbstractCommand command : commands) {
for (final AbstractCommand command : addons.getCommands()) {
if (command.matches(message)) {
command.commandResponse(this, sender, login, message, isOp(sender), false);
command.commandResponse(sender, login, message, isOp(sender), false);
return;
}
}
@ -816,6 +766,7 @@ public class Mobibot extends PircBot {
if (cmd.startsWith(Constants.HELP_CMD)) { // help
helpResponse(sender, args, true);
} else if (isOp && "kill".equals(cmd)) { // kill
twitter.notification("%1$s killed by " + sender + "on %3$s");
sendRawLine("QUIT : Poof!");
System.exit(0);
} else if (isOp && Constants.DEBUG_CMD.equals(cmd)) { // debug
@ -828,23 +779,23 @@ public class Mobibot extends PircBot {
} else if (isOp && Constants.DIE_CMD.equals(cmd)) { // die
send(sender + " has just signed my death sentence.");
TIMER.cancel();
twitterShutdown();
twitterNotification("killed by " + sender + " on " + ircChannel);
twitter.shutdown();
twitter.notification("%1$s stopped by " + sender + "on %3$s");
sleep(3);
quitServer("The Bot Is Out There!");
System.exit(0);
} else {
for (final AbstractCommand command : commands) {
if (command.getCommand().startsWith(cmd)) {
command.commandResponse(this, sender, login, args, isOp, true);
for (final AbstractCommand command : addons.getCommands()) {
if (command.getName().startsWith(cmd)) {
command.commandResponse(sender, login, args, isOp, true);
return;
}
}
for (final AbstractModule module : modules) {
for (final AbstractModule module : addons.getModules()) {
if (module.isPrivateMsgEnabled()) {
for (final String c : module.getCommands()) {
if (cmd.equals(c)) {
module.commandResponse(this, sender, cmd, args, true);
module.commandResponse(sender, cmd, args, true);
return;
}
}
@ -870,9 +821,7 @@ public class Mobibot extends PircBot {
*/
@Override
protected void onJoin(final String channel, final String sender, final String login, final String hostname) {
if (tell.isEnabled()) {
tell.send(sender);
}
tell.send(sender);
}
/**
@ -880,9 +829,7 @@ public class Mobibot extends PircBot {
*/
@Override
protected void onNickChange(final String oldNick, final String login, final String hostname, final String newNick) {
if (tell.isEnabled()) {
tell.send(newNick);
}
tell.send(newNick);
}
/**
@ -1012,91 +959,6 @@ public class Mobibot extends PircBot {
}
}
/**
* Add an entry to be posted on Twitter.
*
* @param index The entry index.
*/
public void twitterAddEntry(final int index) {
twitterEntries.add(index);
}
/**
* Post an entry to twitter.
*
* @param index The post entry index.
*/
@SuppressFBWarnings("SUI_CONTAINS_BEFORE_REMOVE")
public final void twitterEntryPost(final int index) {
if (isTwitterAutoPost && twitterEntries.contains(index) && UrlMgr.getEntriesCount() >= index) {
final EntryLink entry = UrlMgr.getEntry(index);
final String msg =
entry.getTitle() + ' ' + entry.getLink() + " via " + entry.getNick() + " on " + getChannel();
new Thread(() -> {
try {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Posting {}{} to Twitter.", Constants.LINK_CMD, index + 1);
}
twitterModule.post(twitterHandle, msg, false);
} catch (ModuleException e) {
LOGGER.warn("Failed to post entry on Twitter.", e);
}
}).start();
twitterEntries.remove(index);
}
}
/**
* Return the total count of links to be posted to twitter.
*
* @return The count of twitter links.
*/
public final int twitterLinksCount() {
return twitterEntries.size();
}
/**
* Send a notification to the registered Twitter handle.
*
* @param msg The twitter message.
*/
final void twitterNotification(final String msg) {
if (twitterModule.isEnabled() && isNotBlank(twitterHandle)) {
new Thread(() -> {
try {
twitterModule.post(
twitterHandle,
getName() + ' ' + ReleaseInfo.VERSION + " " + msg,
true);
} catch (ModuleException e) {
LOGGER.warn("Failed to notify @{}: {}", twitterHandle, msg, e);
}
}).start();
}
}
/**
* Removes entry from Twitter auto-post.
*
* @param index The entry's index.
*/
public final void twitterRemoveEntry(final int index) {
twitterEntries.remove(index);
}
/**
* Post all the links on twitter on shutdown.
*/
final void twitterShutdown() {
if (twitterModule.isEnabled() && isNotBlank(twitterHandle)) {
LOGGER.debug("Twitter shutdown.");
for (final int i : twitterEntries) {
twitterEntryPost(i);
}
}
}
/**
* Updates pin on pinboard.
*

View file

@ -36,6 +36,6 @@ import java.util.*
class TwitterTimer(var bot: Mobibot, private var index: Int) : TimerTask() {
override fun run() {
bot.twitterEntryPost(index)
bot.twitter.postEntry(index)
}
}

View file

@ -34,16 +34,18 @@ package net.thauvin.erik.mobibot.commands
import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils
import java.util.concurrent.ConcurrentHashMap
abstract class AbstractCommand {
abstract val command: String
abstract class AbstractCommand(val bot: Mobibot) {
abstract val name: String
abstract val help: List<String>
abstract val isOp: Boolean
abstract val isPublic: Boolean
abstract val isVisible: Boolean
private val properties: MutableMap<String, String> = ConcurrentHashMap()
abstract fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,
@ -51,7 +53,7 @@ abstract class AbstractCommand {
isPrivate: Boolean
)
open fun helpResponse(bot: Mobibot, command: String, sender: String, isOp: Boolean, isPrivate: Boolean): Boolean {
open fun helpResponse(command: String, sender: String, isOp: Boolean, isPrivate: Boolean): Boolean {
if (!this.isOp || this.isOp == isOp) {
for (h in help) {
bot.send(sender, Utils.helpFormat(h, bot.nick, isPrivate), isPrivate)
@ -61,7 +63,32 @@ abstract class AbstractCommand {
return false
}
open fun getProperty(key: String) : String? {
return properties[key]
}
open fun getPropertyKeys(): Set<String> {
return properties.keys
}
open fun hasProperties(): Boolean {
return properties.isNotEmpty()
}
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
}
}

View file

@ -38,15 +38,14 @@ import net.thauvin.erik.mobibot.commands.links.UrlMgr.Companion.getHistory
import net.thauvin.erik.mobibot.entries.EntriesMgr
import java.io.File
class AddLog : AbstractCommand() {
override val command = "addlog"
class AddLog(bot: Mobibot) : AbstractCommand(bot) {
override val name = "addlog"
override val help = emptyList<String>()
override val isOp = true
override val isPublic = false
override val isVisible = false
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,

View file

@ -35,10 +35,9 @@ package net.thauvin.erik.mobibot.commands
import net.thauvin.erik.mobibot.FeedReader
import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils
import org.apache.commons.lang3.StringUtils.isNotBlank
class ChannelFeed(channel: String, private val feedUrl: String) : AbstractCommand() {
override val command = channel
class ChannelFeed(bot: Mobibot, channel: String) : AbstractCommand(bot) {
override val name = channel
override val help = listOf(
"To list the last 5 posts from the channel's weblog feed:",
Utils.helpIndent("%c $channel")
@ -47,18 +46,23 @@ class ChannelFeed(channel: String, private val feedUrl: String) : AbstractComman
override val isPublic = true
override val isVisible = true
companion object {
const val FEED_PROP = "feed"
}
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,
isOp: Boolean,
isPrivate: Boolean
) {
if (isNotBlank(feedUrl)) {
Thread(FeedReader(bot, sender, feedUrl)).start()
} else {
bot.send(sender, "There is no feed setup for this channel.", false)
with(getProperty(FEED_PROP)) {
if (!this.isNullOrBlank()) {
Thread(FeedReader(bot, sender, this)).start()
} else {
bot.send(sender, "There is no feed setup for this channel.", false)
}
}
}
}

View file

@ -35,12 +35,12 @@ package net.thauvin.erik.mobibot.commands
import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils
class Cycle : AbstractCommand() {
class Cycle(bot: Mobibot) : AbstractCommand(bot) {
private val wait = 10
override val command = "cycle"
override val name = "cycle"
override val help = listOf(
"To have the bot leave the channel and come back:",
Utils.helpIndent("%c $command")
Utils.helpIndent("%c $name")
)
override val isOp = true
override val isPublic = false
@ -48,7 +48,6 @@ class Cycle : AbstractCommand() {
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,

View file

@ -37,29 +37,27 @@ import net.thauvin.erik.mobibot.Utils
import net.thauvin.erik.mobibot.commands.links.UrlMgr
import java.util.*
class Ignore(defaultIgnore: String) : AbstractCommand() {
class Ignore(bot: Mobibot) : AbstractCommand(bot) {
private val me = "me"
init {
if (defaultIgnore.isNotBlank()) {
ignored.addAll(defaultIgnore.split(UrlMgr.LINK_MATCH.toRegex()))
}
initProperties(IGNORE_PROP)
}
override val command = IGNORE_CMD
override val name = IGNORE_CMD
override val help = listOf(
"To ignore a link posted to the channel:",
Utils.helpIndent("https://www.foo.bar %n"),
"To check your ignore status:",
Utils.helpIndent("%c $command"),
Utils.helpIndent("%c $name"),
"To toggle your ignore status:",
Utils.helpIndent("%c $command $me")
Utils.helpIndent("%c $name $me")
)
private val helpOp = listOf(
"To ignore a link posted to the channel:",
Utils.helpIndent("https://www.foo.bar " + Utils.bold("%n"), false),
"To add/remove nicks from the ignored list:",
Utils.helpIndent("%c $command <nick> [<nick> ...]")
Utils.helpIndent("%c $name <nick> [<nick> ...]")
)
override val isOp = false
@ -68,6 +66,7 @@ class Ignore(defaultIgnore: String) : AbstractCommand() {
companion object {
const val IGNORE_CMD = "ignore"
const val IGNORE_PROP = IGNORE_CMD
private val ignored = TreeSet<String>()
@JvmStatic
@ -77,7 +76,6 @@ class Ignore(defaultIgnore: String) : AbstractCommand() {
}
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,
@ -94,7 +92,6 @@ class Ignore(defaultIgnore: String) : AbstractCommand() {
}
override fun helpResponse(
bot: Mobibot,
command: String,
sender: String,
isOp: Boolean,
@ -106,7 +103,7 @@ class Ignore(defaultIgnore: String) : AbstractCommand() {
}
true
} else {
super.helpResponse(bot, command, sender, isOp, isPrivate)
super.helpResponse(command, sender, isOp, isPrivate)
}
}
@ -149,4 +146,12 @@ class Ignore(defaultIgnore: String) : AbstractCommand() {
bot.send(sender, "No one is currently ${Utils.bold("ignored")}.", isPrivate)
}
}
override fun setProperty(key: String, value: String) {
super.setProperty(key, value)
if (IGNORE_PROP == key) {
ignored.addAll(value.split(UrlMgr.LINK_MATCH.toRegex()))
}
}
}

View file

@ -37,18 +37,17 @@ import net.thauvin.erik.mobibot.Utils
import net.thauvin.erik.mobibot.commands.links.UrlMgr
import java.lang.management.ManagementFactory
class Info : AbstractCommand() {
override val command = "info"
class Info(bot: Mobibot) : AbstractCommand(bot) {
override val name = "info"
override val help = listOf(
"To view information about the bot:",
Utils.helpIndent("%c $command")
Utils.helpIndent("%c $name")
)
override val isOp = false
override val isPublic = true
override val isVisible = true
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,
@ -56,7 +55,7 @@ class Info : AbstractCommand() {
isPrivate: Boolean
) {
for (info in Mobibot.INFO) {
bot.send(sender, info, isPrivate)
bot.send(sender, info, isPrivate)
}
val info = StringBuilder("Uptime: ")
@ -67,13 +66,13 @@ class Info : AbstractCommand() {
append(UrlMgr.entriesCount)
if (isOp) {
if (bot.tell.isEnabled) {
if (bot.tell.isEnabled()) {
append(", Messages: ")
append(bot.tell.size())
}
if (bot.isTwitterAutoPost) {
if (bot.twitter.isAutoPost) {
append(", Twitter: ")
append(bot.twitterLinksCount())
append(bot.twitter.entriesCount())
}
}

View file

@ -35,18 +35,17 @@ package net.thauvin.erik.mobibot.commands
import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils
class Me : AbstractCommand() {
override val command = "me"
class Me(bot: Mobibot) : AbstractCommand(bot) {
override val name = "me"
override val help = listOf(
"To have the bot perform an action:",
Utils.helpIndent("%c $command <action>")
Utils.helpIndent("%c $name <action>")
)
override val isOp = true
override val isPublic = false
override val isVisible = true
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,

View file

@ -35,18 +35,17 @@ package net.thauvin.erik.mobibot.commands
import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils
class Modules : AbstractCommand() {
override val command = "modules"
class Modules(bot: Mobibot) : AbstractCommand(bot) {
override val name = "modules"
override val help = listOf(
"To view a list of enabled modules:",
Utils.helpIndent("%c $command")
Utils.helpIndent("%c $name")
)
override val isOp = true
override val isPublic = false
override val isVisible = true
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,
@ -54,12 +53,13 @@ class Modules : AbstractCommand() {
isPrivate: Boolean
) {
if (isOp) {
val modulesNames = bot.modulesNames
if (modulesNames.isEmpty()) {
bot.send(sender, "There are no enabled modules.", isPrivate)
} else {
bot.send(sender, "The enabled modules are: ", isPrivate)
bot.sendList(sender, modulesNames, 7, isPrivate, false)
with(bot.modulesNames) {
if (isEmpty()) {
bot.send(sender, "There are no enabled modules.", isPrivate)
} else {
bot.send(sender, "The enabled modules are: ", isPrivate)
bot.sendList(sender, this, 7, isPrivate, false)
}
}
} else {
bot.helpDefault(sender, isOp, isPrivate)

View file

@ -35,18 +35,17 @@ package net.thauvin.erik.mobibot.commands
import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils
class Msg : AbstractCommand() {
override val command = "msg"
class Msg(bot: Mobibot) : AbstractCommand(bot) {
override val name = "msg"
override val help = listOf(
"To have the bot send a private message to someone:",
Utils.helpIndent("%c $command <nick> <text>")
Utils.helpIndent("%c $name <nick> <text>")
)
override val isOp = true
override val isPublic = true
override val isVisible = true
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,
@ -58,7 +57,7 @@ class Msg : AbstractCommand() {
if (args.length > 2) {
bot.send(msg[0], msg[1], isPrivate)
} else {
helpResponse(bot, command, sender, isOp, isPrivate)
helpResponse(name, sender, isOp, isPrivate)
}
} else {
bot.helpDefault(sender, isOp, isPrivate)

View file

@ -35,18 +35,17 @@ package net.thauvin.erik.mobibot.commands
import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils
class Nick : AbstractCommand() {
override val command = "nick"
class Nick(bot: Mobibot) : AbstractCommand(bot) {
override val name = "nick"
override val help = listOf(
"To change the bot's nickname:",
Utils.helpIndent("%c $command <nick>")
Utils.helpIndent("%c $name <nick>")
)
override val isOp = true
override val isPublic = true
override val isVisible = true
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,

View file

@ -38,11 +38,11 @@ import java.time.Clock
import java.time.LocalDateTime
import java.util.*
class Recap : AbstractCommand() {
override val command = "recap"
class Recap(bot: Mobibot) : AbstractCommand(bot) {
override val name = "recap"
override val help = listOf(
"To list the last 10 public channel messages:",
Utils.helpIndent("%c $command")
Utils.helpIndent("%c $name")
)
override val isOp = false
override val isPublic = true
@ -76,7 +76,6 @@ class Recap : AbstractCommand() {
}
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,

View file

@ -35,11 +35,11 @@ package net.thauvin.erik.mobibot.commands
import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.Utils
class Say : AbstractCommand() {
override val command = "say"
class Say(bot: Mobibot) : AbstractCommand(bot) {
override val name = "say"
override val help = listOf(
"To have the bot say something on the channel:",
Utils.helpIndent("%c $command <text>")
Utils.helpIndent("%c $name <text>")
)
override val isOp = true
override val isPublic = false
@ -47,7 +47,6 @@ class Say : AbstractCommand() {
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,

View file

@ -37,11 +37,11 @@ import net.thauvin.erik.mobibot.Utils
import org.jibble.pircbot.User
import java.util.*
class Users : AbstractCommand() {
override val command = "users"
class Users(bot: Mobibot) : AbstractCommand(bot) {
override val name = "users"
override val help = listOf(
"To list the users present on the channel:",
Utils.helpIndent("%c $command")
Utils.helpIndent("%c $name")
)
override val isOp = false
override val isPublic = true
@ -49,7 +49,6 @@ class Users : AbstractCommand() {
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,

View file

@ -50,9 +50,13 @@ public class Versions extends AbstractCommand {
+ ", "
+ System.getProperty("java.vm.info") + ')');
public Versions(@NotNull final Mobibot bot) {
super(bot);
}
@NotNull
@Override
public String getCommand() {
public String getName() {
return "versions";
}
@ -61,7 +65,7 @@ public class Versions extends AbstractCommand {
@Override
public List<String> getHelp() {
return List.of("To view the versions data (bot, java, etc.):",
Utils.helpIndent("%s " + getCommand()));
Utils.helpIndent("%s " + getName()));
}
@Override
@ -80,18 +84,17 @@ public class Versions extends AbstractCommand {
}
@Override
public void commandResponse(@NotNull final Mobibot bot,
@NotNull final String sender,
public void commandResponse(@NotNull final String sender,
@NotNull final String login,
@NotNull final String args,
final boolean isOp,
final boolean isPrivate) {
if (isOp) {
for (final String v : versions) {
bot.send(sender, v, isPrivate);
getBot().send(sender, v, isPrivate);
}
} else {
bot.helpDefault(sender, false, isPrivate);
getBot().helpDefault(sender, false, isPrivate);
}
}

View file

@ -39,8 +39,8 @@ import net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.entries.EntriesUtils
import net.thauvin.erik.mobibot.entries.EntryLink
class Comment : AbstractCommand() {
override val command = COMMAND
class Comment(bot: Mobibot) : AbstractCommand(bot) {
override val name = COMMAND
override val help = listOf(
"To add a comment:",
Utils.helpIndent("${Constants.LINK_CMD}1:This is a comment"),
@ -59,7 +59,6 @@ class Comment : AbstractCommand() {
}
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,
@ -89,13 +88,12 @@ class Comment : AbstractCommand() {
}
override fun helpResponse(
bot: Mobibot,
command: String,
sender: String,
isOp: Boolean,
isPrivate: Boolean
): Boolean {
if (super.helpResponse(bot, command, sender, isOp, isPrivate)) {
if (super.helpResponse(command, sender, isOp, isPrivate)) {
if (isOp) {
bot.send(sender, "To change a comment's author:", isPrivate)
bot.send(

View file

@ -39,8 +39,8 @@ import net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.entries.EntriesUtils
import net.thauvin.erik.mobibot.entries.EntryLink
class Posting : AbstractCommand() {
override val command = "posting"
class Posting(bot: Mobibot) : AbstractCommand(bot) {
override val name = "posting"
override val help = listOf(
"Post a URL, by saying it on a line on its own:",
Utils.helpIndent("<url> [<title>] ${Tags.COMMAND}}: <+tag> [...]]"),
@ -58,7 +58,6 @@ class Posting : AbstractCommand() {
override val isVisible = true
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,
@ -70,14 +69,14 @@ class Posting : AbstractCommand() {
if (index < UrlMgr.entriesCount) {
when (val cmd = cmds[1].trim()) {
"" -> showEntry(bot, index)
"-" -> removeEntry(bot, sender, login, isOp, index) // L1:-
"" -> showEntry(index)
"-" -> removeEntry(sender, login, isOp, index) // L1:-
else -> {
when (cmd[0]) {
'|' -> changeTitle(bot, cmd, index) // L1:|<title>
'=' -> changeUrl(bot, cmd, login, isOp, index) // L1:=<url>
'?' -> changeAuthor(bot, cmd, sender, isOp, index) // L1:?<author>
else -> addComment(bot, cmd, sender, index) // L1:<comment>
'|' -> changeTitle(cmd, index) // L1:|<title>
'=' -> changeUrl(cmd, login, isOp, index) // L1:=<url>
'?' -> changeAuthor(cmd, sender, isOp, index) // L1:?<author>
else -> addComment(cmd, sender, index) // L1:<comment>
}
}
}
@ -88,7 +87,7 @@ class Posting : AbstractCommand() {
return message.matches("${Constants.LINK_CMD}[0-9]+:.*".toRegex())
}
private fun addComment(bot: Mobibot, cmd: String, sender: String, index: Int) {
private fun addComment(cmd: String, sender: String, index: Int) {
val entry: EntryLink = UrlMgr.getEntry(index)
val commentIndex = entry.addComment(cmd, sender)
val comment = entry.getComment(commentIndex)
@ -96,7 +95,7 @@ class Posting : AbstractCommand() {
UrlMgr.saveEntries(bot, false)
}
private fun changeTitle(bot: Mobibot, cmd: String, index: Int) {
private fun changeTitle(cmd: String, index: Int) {
if (cmd.length > 1) {
val entry: EntryLink = UrlMgr.getEntry(index)
entry.title = cmd.substring(1).trim()
@ -106,7 +105,7 @@ class Posting : AbstractCommand() {
}
}
private fun changeUrl(bot: Mobibot, cmd: String, login: String, isOp: Boolean, index: Int) {
private fun changeUrl(cmd: String, login: String, isOp: Boolean, index: Int) {
val entry: EntryLink = UrlMgr.getEntry(index)
if (entry.login == login || isOp) {
val link = cmd.substring(1)
@ -120,7 +119,7 @@ class Posting : AbstractCommand() {
}
}
private fun changeAuthor(bot: Mobibot, cmd: String, sender: String, isOp: Boolean, index: Int) {
private fun changeAuthor(cmd: String, sender: String, isOp: Boolean, index: Int) {
if (isOp) {
if (cmd.length > 1) {
val entry: EntryLink = UrlMgr.getEntry(index)
@ -133,13 +132,10 @@ class Posting : AbstractCommand() {
}
}
private fun removeEntry(bot: Mobibot, sender: String, login: String, isOp: Boolean, index: Int) {
private fun removeEntry(sender: String, login: String, isOp: Boolean, index: Int) {
val entry: EntryLink = UrlMgr.getEntry(index)
if (entry.login == login || isOp) {
bot.deletePin(entry)
if (bot.isTwitterAutoPost) {
bot.twitterRemoveEntry(index)
}
bot.deletePin(index, entry)
UrlMgr.removeEntry(index)
bot.send("Entry ${Constants.LINK_CMD}${index + 1} removed.")
UrlMgr.saveEntries(bot, false)
@ -148,7 +144,7 @@ class Posting : AbstractCommand() {
}
}
private fun showEntry(bot: Mobibot, index: Int) {
private fun showEntry(index: Int) {
val entry: EntryLink = UrlMgr.getEntry(index)
bot.send(EntriesUtils.buildLink(index, entry))
if (entry.hasTags()) {

View file

@ -39,8 +39,8 @@ import net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.entries.EntriesUtils
import net.thauvin.erik.mobibot.entries.EntryLink
class Tags : AbstractCommand() {
override val command = COMMAND
class Tags(bot: Mobibot) : AbstractCommand(bot) {
override val name = COMMAND
override val help = listOf(
"To categorize or tag a URL, use its label and a T:",
Utils.helpIndent("${Constants.LINK_CMD}1T:<+tag|-tag> [...]")
@ -54,7 +54,6 @@ class Tags : AbstractCommand() {
}
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,

View file

@ -34,7 +34,6 @@ package net.thauvin.erik.mobibot.commands.links
import net.thauvin.erik.mobibot.Constants
import net.thauvin.erik.mobibot.Mobibot
import net.thauvin.erik.mobibot.TwitterTimer
import net.thauvin.erik.mobibot.Utils
import net.thauvin.erik.mobibot.commands.AbstractCommand
import net.thauvin.erik.mobibot.commands.Ignore
@ -44,22 +43,24 @@ import net.thauvin.erik.mobibot.entries.EntryLink
import org.jsoup.Jsoup
import java.io.IOException
class UrlMgr(defaultTags: String, keywords: String) : AbstractCommand() {
private val keywords: List<String>
private val defaultTags: List<String>
override val command = Constants.LINK_CMD
class UrlMgr(bot: Mobibot) : AbstractCommand(bot) {
private val keywords: MutableList<String> = ArrayList()
private val defaultTags: MutableList<String> = ArrayList()
override val name = Constants.LINK_CMD
override val help = emptyList<String>()
override val isOp = false
override val isPublic = false
override val isVisible = false
init {
this.keywords = keywords.split(TAG_MATCH.toRegex())
this.defaultTags = defaultTags.split(TAG_MATCH.toRegex())
initProperties(TAGS_PROP, KEYWORDS_PROP)
}
companion object {
const val LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*"
const val KEYWORDS_PROP = "tags-keywords"
const val TAGS_PROP = "tags"
const val TAG_MATCH = ", *| +"
// Entries array
@ -118,7 +119,6 @@ class UrlMgr(defaultTags: String, keywords: String) : AbstractCommand() {
}
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,
@ -157,8 +157,8 @@ class UrlMgr(defaultTags: String, keywords: String) : AbstractCommand() {
// Add Entry to pinboard.
bot.addPin(entry)
// Queue link for posting to twitter
twitterPost(bot, index)
// Queue link for posting to Twitter.
bot.twitter.queueEntry(index)
saveEntries(bot, isBackup)
@ -175,7 +175,6 @@ class UrlMgr(defaultTags: String, keywords: String) : AbstractCommand() {
}
override fun helpResponse(
bot: Mobibot,
command: String,
sender: String,
isOp: Boolean,
@ -234,11 +233,12 @@ class UrlMgr(defaultTags: String, keywords: String) : AbstractCommand() {
return false
}
private fun twitterPost(bot: Mobibot, index: Int) {
if (bot.isTwitterAutoPost) {
bot.twitterAddEntry(index)
bot.logger.debug("Scheduling ${Constants.LINK_CMD}${index + 1} for posting on Twitter.")
bot.timer.schedule(TwitterTimer(bot, index), Constants.TIMER_DELAY * 60L * 1000L)
override fun setProperty(key: String, value: String) {
super.setProperty(key, value)
if (KEYWORDS_PROP == key) {
keywords.addAll(value.split(TAG_MATCH.toRegex()))
} else if (KEYWORDS_PROP == key) {
defaultTags.addAll(value.split(TAG_MATCH.toRegex()))
}
}
}

View file

@ -40,12 +40,12 @@ import net.thauvin.erik.mobibot.commands.links.UrlMgr.Companion.getEntry
import net.thauvin.erik.mobibot.entries.EntriesUtils
import net.thauvin.erik.mobibot.entries.EntryLink
class View : AbstractCommand() {
class View(bot: Mobibot) : AbstractCommand(bot) {
private val maxEntries = 8
override val command = VIEW_CMD
override val name = VIEW_CMD
override val help = listOf(
"To list or search the current URL posts:",
Utils.helpIndent("%c $command [<start>] [<query>]")
Utils.helpIndent("%c $name [<start>] [<query>]")
)
override val isOp = false
override val isPublic = true
@ -56,7 +56,6 @@ class View : AbstractCommand() {
}
override fun commandResponse(
bot: Mobibot,
sender: String,
login: String,
args: String,
@ -110,7 +109,7 @@ class View : AbstractCommand() {
i++
if (sent == maxEntries && i < max) {
bot.send(
sender, "To view more, try: " + Utils.bold("${bot.nick}: $command ${i + 1} $lcArgs"), false
sender, "To view more, try: " + Utils.bold("${bot.nick}: $name ${i + 1} $lcArgs"), false
)
}
}

View file

@ -50,45 +50,43 @@ import java.util.concurrent.CopyOnWriteArrayList;
* @since 1.0
*/
public class Tell extends AbstractCommand {
/**
* Max days property.
*/
public static final String MAX_DAYS_PROP = "tell-max-days";
/**
* Max size proeprty.
*/
public static final String MAX_SIZE_PROP = "tell-max-size";
/**
* The tell command.
*/
public static final String TELL_CMD = "tell";
// Arrow
private static final String ARROW = " --> ";
// Default maximum number of days to keep messages
private static final int DEFAULT_TELL_MAX_DAYS = 7;
// Default message max queue size
private static final int DEFAULT_TELL_MAX_SIZE = 50;
// Serialized object file extension
private static final String SER_EXT = ".ser";
// All keyword
private static final String TELL_ALL_KEYWORD = "all";
//T he delete command.
private static final String TELL_DEL_KEYWORD = "del";
// Bot instance
private final Mobibot bot;
// Maximum number of days to keep messages
private final int maxDays;
// Message maximum queue size
private final int maxSize;
// Messages queue
private final List<TellMessage> messages = new CopyOnWriteArrayList<>();
// Serialized object file
private final String serializedObject;
// Maximum number of days to keep messages
private int maxDays = 7;
// Message maximum queue size
private int maxSize = 50;
/**
* Creates a new instance.
*
* @param bot The bot.
* @param maxDays Max days.
* @param maxSize Max size.
* @param bot The bot.
*/
public Tell(final Mobibot bot, final String maxDays, final String maxSize) {
super();
this.bot = bot;
this.maxDays = Utils.getIntProperty(maxDays, DEFAULT_TELL_MAX_DAYS);
this.maxSize = Utils.getIntProperty(maxSize, DEFAULT_TELL_MAX_SIZE);
public Tell(final Mobibot bot) {
super(bot);
initProperties(MAX_DAYS_PROP, MAX_SIZE_PROP);
// Load the message queue
serializedObject = bot.getLogsDir() + bot.getName() + SER_EXT;
@ -106,7 +104,7 @@ public class Tell extends AbstractCommand {
*/
@SuppressWarnings("WeakerAccess")
final boolean clean() {
bot.getLogger().debug("Cleaning the messages.");
getBot().getLogger().debug("Cleaning the messages.");
return TellMessagesMgr.clean(messages, maxDays);
}
@ -128,9 +126,9 @@ public class Tell extends AbstractCommand {
if (deleted) {
save();
bot.send(sender, "Delivered messages have been deleted.", isPrivate);
getBot().send(sender, "Delivered messages have been deleted.", isPrivate);
} else {
bot.send(sender, "No delivered messages were found.", isPrivate);
getBot().send(sender, "No delivered messages were found.", isPrivate);
}
} else {
@ -139,11 +137,11 @@ public class Tell extends AbstractCommand {
for (final TellMessage message : messages) {
found = message.isMatchId(id);
if (found && (message.getSender().equalsIgnoreCase(sender) || bot.isOp(sender))) {
if (found && (message.getSender().equalsIgnoreCase(sender) || getBot().isOp(sender))) {
messages.remove(message);
save();
bot.send(sender, "Your message was deleted from the queue.", isPrivate);
getBot().send(sender, "Your message was deleted from the queue.", isPrivate);
deleted = true;
break;
}
@ -151,20 +149,20 @@ public class Tell extends AbstractCommand {
if (!deleted) {
if (found) {
bot.send(sender, "Only messages that you sent can be deleted.", isPrivate);
getBot().send(sender, "Only messages that you sent can be deleted.", isPrivate);
} else {
bot.send(sender, "The specified message [ID " + id + "] could not be found.", isPrivate);
getBot().send(sender, "The specified message [ID " + id + "] could not be found.", isPrivate);
}
}
}
} else {
helpResponse(bot, args, sender, isOp, isPrivate);
helpResponse(args, sender, isOp, isPrivate);
}
}
@NotNull
@Override
public String getCommand() {
public String getName() {
return TELL_CMD;
}
@ -172,9 +170,9 @@ public class Tell extends AbstractCommand {
@Override
public List<String> getHelp() {
return List.of("To send a message to someone when they join the channel:",
Utils.helpIndent("%s " + TELL_CMD + " <nick> <message>"),
Utils.helpIndent("%c " + TELL_CMD + " <nick> <message>"),
"To view queued and sent messages:",
Utils.helpIndent("%s " + TELL_CMD + ' ' + View.VIEW_CMD),
Utils.helpIndent("%c " + TELL_CMD + ' ' + View.VIEW_CMD),
"Messages are kept for " + Utils.bold(maxDays) + Utils.plural(maxDays, " day.", " days."));
}
@ -194,17 +192,16 @@ public class Tell extends AbstractCommand {
}
@Override
public void commandResponse(@NotNull final Mobibot bot,
@NotNull final String sender,
public void commandResponse(@NotNull final String sender,
@NotNull final String login,
@NotNull final String args,
final boolean isOp,
final boolean isPrivate) {
if (isEnabled()) {
if (StringUtils.isBlank(args)) {
helpResponse(bot, args, sender, isOp, isPrivate);
helpResponse(args, sender, isOp, isPrivate);
} else if (args.startsWith(View.VIEW_CMD)) {
if (bot.isOp(sender) && (View.VIEW_CMD + ' ' + TELL_ALL_KEYWORD).equals(args)) {
if (getBot().isOp(sender) && (View.VIEW_CMD + ' ' + TELL_ALL_KEYWORD).equals(args)) {
viewAll(sender, isPrivate);
} else {
viewMessages(sender, isPrivate);
@ -221,15 +218,21 @@ public class Tell extends AbstractCommand {
}
}
/**
* Returns <code>true</code> if enabled.
*
* @return <code>true</code> or <code>false</code>
*/
@Override
public boolean isEnabled() {
return maxSize > 0 && maxDays > 0;
}
@Override
public void setProperty(@NotNull final String key, @NotNull final String value) {
super.setProperty(key, value);
if (MAX_DAYS_PROP.equals(key)) {
this.maxDays = Utils.getIntProperty(value, maxDays);
} else if (MAX_SIZE_PROP.equals(key)) {
this.maxSize = Utils.getIntProperty(value, maxSize);
}
}
// New message.
private void newMessage(final String sender, final String args, final boolean isOp, final boolean isPrivate) {
final String[] split = args.split(" ", 2);
@ -242,13 +245,13 @@ public class Tell extends AbstractCommand {
save();
bot.send(sender, "Message [ID " + message.getId() + "] was queued for "
+ Utils.bold(message.getRecipient()), isPrivate);
getBot().send(sender, "Message [ID " + message.getId() + "] was queued for "
+ Utils.bold(message.getRecipient()), isPrivate);
} else {
bot.send(sender, "Sorry, the messages queue is currently full.", isPrivate);
getBot().send(sender, "Sorry, the messages queue is currently full.", isPrivate);
}
} else {
helpResponse(bot, args, sender, isOp, isPrivate);
helpResponse(args, sender, isOp, isPrivate);
}
}
@ -257,7 +260,7 @@ public class Tell extends AbstractCommand {
*/
@SuppressWarnings("WeakerAccess")
final void save() {
TellMessagesMgr.save(serializedObject, messages, bot.getLogger());
TellMessagesMgr.save(serializedObject, messages, getBot().getLogger());
}
/**
@ -267,14 +270,14 @@ public class Tell extends AbstractCommand {
* @param isMessage The message flag.
*/
public void send(final String nickname, final boolean isMessage) {
if (!nickname.equals(bot.getNick()) && isEnabled()) {
if (isEnabled() && !nickname.equals(getBot().getNick())) {
messages.stream().filter(message -> message.isMatch(nickname)).forEach(message -> {
if (message.getRecipient().equalsIgnoreCase(nickname) && !message.isReceived()) {
if (message.getSender().equals(nickname)) {
if (!isMessage) {
bot.send(nickname, Utils.bold("You") + " wanted me to remind you: "
+ Utils.reverseColor(message.getMessage()),
true);
getBot().send(nickname, Utils.bold("You") + " wanted me to remind you: "
+ Utils.reverseColor(message.getMessage()),
true);
message.setIsReceived();
message.setIsNotified();
@ -282,9 +285,9 @@ public class Tell extends AbstractCommand {
save();
}
} else {
bot.send(nickname, message.getSender() + " wanted me to tell you: "
+ Utils.reverseColor(message.getMessage()),
true);
getBot().send(nickname, message.getSender() + " wanted me to tell you: "
+ Utils.reverseColor(message.getMessage()),
true);
message.setIsReceived();
@ -292,12 +295,12 @@ public class Tell extends AbstractCommand {
}
} else if (message.getSender().equalsIgnoreCase(nickname) && message.isReceived()
&& !message.isNotified()) {
bot.send(nickname,
"Your message "
+ Utils.reverseColor("[ID " + message.getId() + ']') + " was sent to "
+ Utils.bold(message.getRecipient()) + " on "
+ Utils.utcDateTime(message.getReceived()),
true);
getBot().send(nickname,
"Your message "
+ Utils.reverseColor("[ID " + message.getId() + ']') + " was sent to "
+ Utils.bold(message.getRecipient()) + " on "
+ Utils.utcDateTime(message.getReceived()),
true);
message.setIsNotified();
@ -329,13 +332,13 @@ public class Tell extends AbstractCommand {
private void viewAll(final String sender, final boolean isPrivate) {
if (!messages.isEmpty()) {
for (final TellMessage message : messages) {
bot.send(sender, Utils.bold(message.getSender()) + ARROW + Utils.bold(message.getRecipient())
+ " [ID: " + message.getId() + ", "
+ (message.isReceived() ? "DELIVERED" : "QUEUED") + ']',
isPrivate);
getBot().send(sender, Utils.bold(message.getSender()) + ARROW + Utils.bold(message.getRecipient())
+ " [ID: " + message.getId() + ", "
+ (message.isReceived() ? "DELIVERED" : "QUEUED") + ']',
isPrivate);
}
} else {
bot.send(sender, "There are no messages in the queue.", isPrivate);
getBot().send(sender, "There are no messages in the queue.", isPrivate);
}
}
@ -347,41 +350,41 @@ public class Tell extends AbstractCommand {
if (message.isMatch(sender)) {
if (!hasMessage) {
hasMessage = true;
bot.send(sender, "Here are your messages: ", isPrivate);
getBot().send(sender, "Here are your messages: ", isPrivate);
}
if (message.isReceived()) {
bot.send(sender,
Utils.bold(message.getSender()) + ARROW + Utils.bold(message.getRecipient())
+ " [" + Utils.utcDateTime(message.getReceived()) + ", ID: "
+ Utils.bold(message.getId()) + ", DELIVERED]",
isPrivate);
getBot().send(sender,
Utils.bold(message.getSender()) + ARROW + Utils.bold(message.getRecipient())
+ " [" + Utils.utcDateTime(message.getReceived()) + ", ID: "
+ Utils.bold(message.getId()) + ", DELIVERED]",
isPrivate);
} else {
bot.send(sender,
Utils.bold(message.getSender()) + ARROW + Utils.bold(message.getRecipient())
+ " [" + Utils.utcDateTime(message.getQueued()) + ", ID: "
+ Utils.bold(message.getId()) + ", QUEUED]",
isPrivate);
getBot().send(sender,
Utils.bold(message.getSender()) + ARROW + Utils.bold(message.getRecipient())
+ " [" + Utils.utcDateTime(message.getQueued()) + ", ID: "
+ Utils.bold(message.getId()) + ", QUEUED]",
isPrivate);
}
bot.send(sender, Utils.helpIndent(message.getMessage()), isPrivate);
getBot().send(sender, Utils.helpIndent(message.getMessage()), isPrivate);
}
}
if (!hasMessage) {
bot.send(sender, "You have no messages in the queue.", isPrivate);
getBot().send(sender, "You have no messages in the queue.", isPrivate);
} else {
bot.send(sender, "To delete one or all delivered messages:", isPrivate);
bot.send(sender,
Utils.helpIndent(Utils.helpFormat(
"%c " + TELL_CMD + ' ' + TELL_DEL_KEYWORD + " <id|" + TELL_ALL_KEYWORD + '>',
bot.getNick(),
isPrivate)),
isPrivate);
bot.send(sender,
"Messages are kept for " + Utils.bold(maxDays) + Utils.plural(maxDays, " day.", " days."),
isPrivate);
getBot().send(sender, "To delete one or all delivered messages:", isPrivate);
getBot().send(sender,
Utils.helpIndent(Utils.helpFormat(
"%c " + TELL_CMD + ' ' + TELL_DEL_KEYWORD + " <id|" + TELL_ALL_KEYWORD + '>',
getBot().getNick(),
isPrivate)),
isPrivate);
getBot().send(sender,
"Messages are kept for " + Utils.bold(maxDays) + Utils.plural(maxDays, " day.", " days."),
isPrivate);
}
}
}

View file

@ -50,21 +50,24 @@ import java.util.concurrent.ConcurrentHashMap;
* @since 1.0
*/
public abstract class AbstractModule {
final Mobibot bot;
final List<String> commands = new ArrayList<>();
final List<String> help = new ArrayList<>();
final Map<String, String> properties = new ConcurrentHashMap<>();
AbstractModule(final Mobibot bot) {
this.bot = bot;
}
/**
* Responds to a command.
*
* @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,
public abstract void commandResponse(final String sender,
final String cmd,
final String args,
final boolean isPrivate);
@ -99,16 +102,26 @@ public abstract class AbstractModule {
/**
* Responds with the module's help.
*
* @param bot The bot's instance.
* @param sender The sender.
* @param isPrivate Set to <code>true</code> if the response should be sent as a private message.
*/
public void helpResponse(final Mobibot bot, final String sender, final boolean isPrivate) {
public void helpResponse(final String sender, final boolean isPrivate) {
for (final String h : help) {
bot.send(sender, Utils.helpFormat(h, bot.getNick(), isPrivateMsgEnabled() && isPrivate), isPrivate);
}
}
/**
* Initializes the properties.
*
* @param keys The properties keys to initialize.
*/
public void initProperties(final String... keys) {
for (final String key : keys) {
properties.put(key, "");
}
}
/**
* Returns <code>true</code> if the module is enabled.
*

View file

@ -54,8 +54,8 @@ public class Calc extends AbstractModule {
/**
* The default constructor.
*/
public Calc() {
super();
public Calc(final Mobibot bot) {
super(bot);
commands.add(CALC_CMD);
@ -86,15 +86,14 @@ public class Calc extends AbstractModule {
* {@inheritDoc}
*/
@Override
public void commandResponse(final Mobibot bot,
final String sender,
public void commandResponse(final String sender,
final String cmd,
final String args,
final boolean isPrivate) {
if (StringUtils.isNotBlank(args)) {
bot.send(calc(args));
} else {
helpResponse(bot, sender, isPrivate);
helpResponse(sender, isPrivate);
}
}
}

View file

@ -82,8 +82,8 @@ public final class CurrencyConverter extends ThreadedModule {
/**
* Creates a new {@link CurrencyConverter} instance.
*/
public CurrencyConverter() {
super();
public CurrencyConverter(final Mobibot bot) {
super(bot);
commands.add(CURRENCY_CMD);
}
@ -180,8 +180,7 @@ public final class CurrencyConverter extends ThreadedModule {
* {@inheritDoc}
*/
@Override
public void commandResponse(final Mobibot bot,
final String sender,
public void commandResponse(final String sender,
final String cmd,
final String args,
final boolean isPrivate) {
@ -191,7 +190,7 @@ public final class CurrencyConverter extends ThreadedModule {
}
}
super.commandResponse(bot, sender, cmd, args, isPrivate);
super.commandResponse(sender, cmd, args, isPrivate);
}
/**
@ -199,7 +198,7 @@ public final class CurrencyConverter extends ThreadedModule {
*/
@SuppressFBWarnings("REDOS")
@Override
void run(final Mobibot bot, final String sender, final String cmd, final String query, final boolean isPrivate) {
void run(final String sender, final String cmd, final String query, final boolean isPrivate) {
if (EXCHANGE_RATES.isEmpty()) {
try {
loadRates();
@ -214,13 +213,13 @@ public final class CurrencyConverter extends ThreadedModule {
final Message msg = convertCurrency(query);
bot.send(sender, msg);
if (msg.isError()) {
helpResponse(bot, sender, isPrivate);
helpResponse(sender, isPrivate);
}
} else if (query.contains(CURRENCY_RATES_KEYWORD)) {
bot.send(sender, "The currency rates for " + Utils.bold(pubDate) + " are:", isPrivate);
bot.sendList(sender, currencyRates(), 3, isPrivate, false);
} else {
helpResponse(bot, sender, isPrivate);
helpResponse(sender, isPrivate);
}
}
@ -228,7 +227,7 @@ public final class CurrencyConverter extends ThreadedModule {
* {@inheritDoc}
*/
@Override
public void helpResponse(final Mobibot bot, final String sender, final boolean isPrivate) {
public void helpResponse(final String sender, final boolean isPrivate) {
if (EXCHANGE_RATES.isEmpty()) {
try {
loadRates();
@ -241,14 +240,12 @@ public final class CurrencyConverter extends ThreadedModule {
} else {
bot.send(sender, "To convert from one currency to another:", isPrivate);
bot.send(sender,
Utils.helpIndent(Utils.helpFormat("%c " + CURRENCY_CMD + " 100 USD to EUR",
bot.getNick(),
isPrivate)), isPrivate);
Utils.helpIndent(Utils.helpFormat("%c " + CURRENCY_CMD + " 100 USD to EUR", bot.getNick(), false)),
isPrivate);
bot.send(sender, "For a listing of current rates:", isPrivate);
bot.send(sender,
Utils.helpIndent(Utils.helpFormat("%c " + CURRENCY_CMD + ' ' + CURRENCY_RATES_KEYWORD,
bot.getNick(),
isPrivate)), isPrivate);
bot.getNick(), false)), isPrivate);
bot.send(sender, "The supported currencies are: ", isPrivate);
bot.sendList(sender, new ArrayList<>(EXCHANGE_RATES.keySet()), 11, isPrivate, false);
}

View file

@ -53,8 +53,8 @@ public final class Dice extends AbstractModule {
/**
* The default constructor.
*/
public Dice() {
super();
public Dice(final Mobibot bot) {
super(bot);
commands.add(DICE_CMD);
@ -66,8 +66,7 @@ public final class Dice extends AbstractModule {
* {@inheritDoc}
*/
@Override
public void commandResponse(final Mobibot bot,
final String sender,
public void commandResponse(final String sender,
final String cmd,
final String args,
final boolean isPrivate) {

View file

@ -70,16 +70,15 @@ public final class GoogleSearch extends ThreadedModule {
/**
* Creates a new {@link GoogleSearch} instance.
*/
public GoogleSearch() {
super();
public GoogleSearch(final Mobibot bot) {
super(bot);
commands.add(GOOGLE_CMD);
help.add("To search Google:");
help.add(Utils.helpIndent("%c " + GOOGLE_CMD + " <query>"));
properties.put(GOOGLE_API_KEY_PROP, "");
properties.put(GOOGLE_CSE_KEY_PROP, "");
initProperties(GOOGLE_API_KEY_PROP, GOOGLE_CSE_KEY_PROP);
}
/**
@ -146,7 +145,7 @@ public final class GoogleSearch extends ThreadedModule {
* Searches Google.
*/
@Override
void run(final Mobibot bot, final String sender, final String cmd, final String query, final boolean isPrivate) {
void run(final String sender, final String cmd, final String query, final boolean isPrivate) {
if (StringUtils.isNotBlank(query)) {
try {
final List<Message> results = searchGoogle(query, properties.get(GOOGLE_API_KEY_PROP),
@ -159,7 +158,7 @@ public final class GoogleSearch extends ThreadedModule {
bot.send(sender, e.getMessage(), isPrivate);
}
} else {
helpResponse(bot, sender, isPrivate);
helpResponse(sender, isPrivate);
}
}
}

View file

@ -61,8 +61,8 @@ public final class Joke extends ThreadedModule {
/**
* Creates a new {@link Joke} instance.
*/
public Joke() {
super();
public Joke(final Mobibot bot) {
super(bot);
commands.add(JOKE_CMD);
@ -104,19 +104,18 @@ public final class Joke extends ThreadedModule {
* {@inheritDoc}
*/
@Override
public void commandResponse(final Mobibot bot,
final String sender,
public void commandResponse(final String sender,
final String cmd,
final String args,
final boolean isPrivate) {
new Thread(() -> run(bot, sender, cmd, args, isPrivate)).start();
new Thread(() -> run(sender, cmd, args, isPrivate)).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 cmd, final String arg, final boolean isPrivate) {
void run(final String sender, final String cmd, final String arg, final boolean isPrivate) {
try {
bot.send(Utils.cyan(randomJoke().getText()));
} catch (ModuleException e) {

View file

@ -60,8 +60,8 @@ public final class Lookup extends AbstractModule {
/**
* The default constructor.
*/
public Lookup() {
super();
public Lookup(final Mobibot bot) {
super(bot);
commands.add(LOOKUP_CMD);
@ -151,8 +151,7 @@ public final class Lookup extends AbstractModule {
* {@inheritDoc}
*/
@Override
public void commandResponse(final Mobibot bot,
final String sender,
public void commandResponse(final String sender,
final String cmd,
final String args,
final boolean isPrivate) {
@ -188,7 +187,7 @@ public final class Lookup extends AbstractModule {
}
}
} else {
helpResponse(bot, sender, true);
helpResponse(sender, true);
}
}
}

View file

@ -72,8 +72,8 @@ public class Ping extends AbstractModule {
/**
* The default constructor.
*/
public Ping() {
super();
public Ping(final Mobibot bot) {
super(bot);
commands.add(PING_CMD);
@ -85,8 +85,7 @@ public class Ping extends AbstractModule {
* {@inheritDoc}
*/
@Override
public void commandResponse(final Mobibot bot,
final String sender,
public void commandResponse(final String sender,
final String cmd,
final String args,
final boolean isPrivate) {

View file

@ -43,7 +43,7 @@ import kotlin.random.Random
/**
* Simple module example in Kotlin.
*/
class RockPaperScissors : AbstractModule() {
class RockPaperScissors(bot: Mobibot) : AbstractModule(bot) {
init {
with(commands) {
add(Hands.ROCK.name.toLowerCase())
@ -96,22 +96,21 @@ class RockPaperScissors : AbstractModule() {
}
}
override fun commandResponse(bot: Mobibot, sender: String, cmd: String, args: String?, isPrivate: Boolean) {
override fun commandResponse(sender: String, cmd: String, args: String?, isPrivate: Boolean) {
val hand = Hands.valueOf(cmd.toUpperCase())
val botHand = Hands.values()[Random.nextInt(0, Hands.values().size)]
when {
hand == botHand -> {
bot.action("${green(hand.name)} vs. ${green(botHand.name)} ~ The game is tied ~")
bot.send("${green(hand.name)} vs. ${green(botHand.name)}")
bot.action("tied.")
}
hand.beats(botHand) -> {
bot.action(
"${green(hand.name)} ${bold(hand.action)} ${red(botHand.name)} ~ You win ~"
)
bot.send("${green(hand.name)} ${bold(hand.action)} ${red(botHand.name)}")
bot.action("lost.")
}
else -> {
bot.action(
"${green(botHand.name)} ${bold(botHand.action)} ${red(hand.name)} ~ You lose ~"
)
bot.send("${green(botHand.name)} ${bold(botHand.action)} ${red(hand.name)}")
bot.action("wins.")
}
}
}

View file

@ -76,14 +76,14 @@ public final class StockQuote extends ThreadedModule {
/**
* Creates a new {@link StockQuote} instance.
*/
public StockQuote() {
super();
public StockQuote(final Mobibot bot) {
super(bot);
commands.add(STOCK_CMD);
help.add("To retrieve a stock quote:");
help.add(Utils.helpIndent("%c " + STOCK_CMD + " <symbol|keywords>"));
properties.put(ALPHAVANTAGE_API_KEY_PROP, "");
initProperties(ALPHAVANTAGE_API_KEY_PROP);
}
@SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE",
@ -208,7 +208,7 @@ public final class StockQuote extends ThreadedModule {
* Returns the specified stock quote from Alpha Avantage.
*/
@Override
void run(final Mobibot bot, final String sender, final String cmd, final String symbol, final boolean isPrivate) {
void run(final String sender, final String cmd, final String symbol, final boolean isPrivate) {
if (StringUtils.isNotBlank(symbol)) {
try {
final List<Message> messages = getQuote(symbol, properties.get(ALPHAVANTAGE_API_KEY_PROP));
@ -220,7 +220,7 @@ public final class StockQuote extends ThreadedModule {
bot.send(e.getMessage());
}
} else {
helpResponse(bot, sender, isPrivate);
helpResponse(sender, isPrivate);
}
}
}

View file

@ -42,27 +42,26 @@ import net.thauvin.erik.mobibot.Mobibot;
* @since 1.0
*/
public abstract class ThreadedModule extends AbstractModule {
/**
* {@inheritDoc}
*/
ThreadedModule(final Mobibot bot) {
super(bot);
}
@Override
public void commandResponse(final Mobibot bot,
final String sender,
public void commandResponse(final String sender,
final String cmd,
final String args,
final boolean isPrivate) {
if (isEnabled() && args.length() > 0) {
new Thread(() -> run(bot, sender, cmd, args, isPrivate)).start();
new Thread(() -> run(sender, cmd, args, isPrivate)).start();
} else {
helpResponse(bot, sender, isPrivate);
helpResponse(sender, isPrivate);
}
}
/**
* Runs the thread.
*/
abstract void run(Mobibot bot,
String sender,
abstract void run(String sender,
@SuppressWarnings("unused") String cmd,
String args,
boolean isPrivate);

View file

@ -32,15 +32,27 @@
package net.thauvin.erik.mobibot.modules;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.thauvin.erik.mobibot.Constants;
import net.thauvin.erik.mobibot.Mobibot;
import net.thauvin.erik.mobibot.ReleaseInfo;
import net.thauvin.erik.mobibot.TwitterTimer;
import net.thauvin.erik.mobibot.Utils;
import net.thauvin.erik.mobibot.commands.links.UrlMgr;
import net.thauvin.erik.mobibot.entries.EntryLink;
import net.thauvin.erik.mobibot.msg.Message;
import net.thauvin.erik.mobibot.msg.NoticeMessage;
import org.apache.commons.lang3.StringUtils;
import twitter4j.DirectMessage;
import twitter4j.Status;
import twitter4j.TwitterFactory;
import twitter4j.conf.ConfigurationBuilder;
import java.util.HashSet;
import java.util.Set;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/**
* The Twitter module.
*
@ -50,28 +62,31 @@ import twitter4j.conf.ConfigurationBuilder;
*/
public final class Twitter extends ThreadedModule {
// Property keys
static final String AUTOPOST_PROP = "twitter-auto-post";
static final String CONSUMER_KEY_PROP = "twitter-consumerKey";
static final String CONSUMER_SECRET_PROP = "twitter-consumerSecret";
static final String HANDLE_PROP = "twitter-handle";
static final String TOKEN_PROP = "twitter-token";
static final String TOKEN_SECRET_PROP = "twitter-tokenSecret";
// Twitter command
private static final String TWITTER_CMD = "twitter";
// Twitter auto-posts.
private final Set<Integer> entries = new HashSet<>();
/**
* Creates a new {@link Twitter} instance.
*/
public Twitter() {
super();
public Twitter(final Mobibot bot) {
super(bot);
commands.add(TWITTER_CMD);
help.add("To post to Twitter:");
help.add(Utils.helpIndent("%c " + TWITTER_CMD + " <message>"));
properties.put(CONSUMER_SECRET_PROP, "");
properties.put(CONSUMER_KEY_PROP, "");
properties.put(TOKEN_PROP, "");
properties.put(TOKEN_SECRET_PROP, "");
properties.put(AUTOPOST_PROP, "false");
initProperties(CONSUMER_KEY_PROP,CONSUMER_SECRET_PROP,HANDLE_PROP,TOKEN_PROP,TOKEN_SECRET_PROP);
}
/**
@ -115,6 +130,70 @@ public final class Twitter extends ThreadedModule {
}
}
/**
* Add an entry to be posted on Twitter.
*
* @param index The entry index.
*/
public final void addEntry(final int index) {
entries.add(index);
}
public final int entriesCount() {
return entries.size();
}
public String getHandle() {
return properties.get(HANDLE_PROP);
}
public final boolean hasEntry(final int index) {
return entries.contains(index);
}
public boolean isAutoPost() {
return isEnabled() && Boolean.parseBoolean(properties.get(AUTOPOST_PROP));
}
@Override
boolean isValidProperties() {
for (final String s : getPropertyKeys()) {
if (!AUTOPOST_PROP.equals(s) && !HANDLE_PROP.equals(s) && StringUtils.isBlank(properties.get(s))) {
return false;
}
}
return true;
}
/**
* Send a notification to the registered Twitter handle.
*
* @param msg The twitter message.
*/
public final void notification(final String msg) {
if (isEnabled() && isNotBlank(getHandle())) {
new Thread(() -> {
try {
post(String.format(msg, bot.getName(), ReleaseInfo.VERSION, bot.getChannel()), true);
} catch (ModuleException e) {
bot.getLogger().warn("Failed to notify @{}: {}", getHandle(), msg, e);
}
}).start();
}
}
/**
* Posts on Twitter.
*
* @param message The message to post.
* @param isDm The direct message flag.
* @throws ModuleException If an error occurs while posting.
*/
public void post(final String message, final boolean isDm)
throws ModuleException {
post(properties.get(HANDLE_PROP), message, isDm);
}
/**
* Posts on Twitter.
*
@ -135,11 +214,48 @@ public final class Twitter extends ThreadedModule {
isDm);
}
/**
* Post an entry to twitter.
*
* @param index The post entry index.
*/
@SuppressFBWarnings("SUI_CONTAINS_BEFORE_REMOVE")
public final void postEntry(final int index) {
if (isAutoPost() && hasEntry(index) && UrlMgr.getEntriesCount() >= index) {
final EntryLink entry = UrlMgr.getEntry(index);
final String msg =
entry.getTitle() + ' ' + entry.getLink() + " via " + entry.getNick() + " on " + bot.getChannel();
new Thread(() -> {
try {
if (bot.getLogger().isDebugEnabled()) {
bot.getLogger().debug("Posting {}{} to Twitter.", Constants.LINK_CMD, index + 1);
}
post(msg, false);
} catch (ModuleException e) {
bot.getLogger().warn("Failed to post entry on Twitter.", e);
}
}).start();
removeEntry(index);
}
}
public void queueEntry(final int index) {
if (isAutoPost()) {
addEntry(index);
bot.getLogger().debug("Scheduling ${Constants.LINK_CMD}${index + 1} for posting on Twitter.");
bot.getTimer().schedule(new TwitterTimer(bot, index), Constants.TIMER_DELAY * 60L * 1000L);
}
}
public final void removeEntry(final int index) {
entries.remove(index);
}
/**
* Posts to twitter.
*/
@Override
void run(final Mobibot bot, final String sender, final String cmd, final String message, final boolean isPrivate) {
void run(final String sender, final String cmd, final String message, final boolean isPrivate) {
try {
bot.send(sender,
post(sender, message + " (by " + sender + " on " + bot.getChannel() + ')', false).getText(),
@ -149,4 +265,13 @@ public final class Twitter extends ThreadedModule {
bot.send(sender, e.getMessage(), isPrivate);
}
}
/**
* Post all the entries to Twitter on shutdown.
*/
public final void shutdown() {
for (final int index : entries) {
postEntry(index);
}
}
}

View file

@ -58,8 +58,8 @@ public final class War extends AbstractModule {
/**
* The default constructor.
*/
public War() {
super();
public War(final Mobibot bot) {
super(bot);
commands.add(WAR_CMD);
@ -71,8 +71,7 @@ public final class War extends AbstractModule {
* {@inheritDoc}
*/
@Override
public void commandResponse(final Mobibot bot,
final String sender,
public void commandResponse(final String sender,
final String cmd,
final String args,
final boolean isPrivate) {

View file

@ -73,8 +73,8 @@ public class Weather2 extends ThreadedModule {
/**
* Creates a new {@link Weather2} instance.
*/
public Weather2() {
super();
public Weather2(final Mobibot bot) {
super(bot);
commands.add(WEATHER_CMD);
@ -84,7 +84,7 @@ public class Weather2 extends ThreadedModule {
help.add(Utils.helpIndent("%c " + WEATHER_CMD + " paris, fr"));
help.add("The default ISO 3166 country code is " + bold("US") + ". Zip codes supported in most countries.");
properties.put(OWM_API_KEY_PROP, "");
initProperties(OWM_API_KEY_PROP);
}
private static OWM.Country getCountry(final String countryCode) {
@ -218,12 +218,12 @@ public class Weather2 extends ThreadedModule {
* Fetches the weather data from a specific city.
*/
@Override
void run(final Mobibot bot, final String sender, final String cmd, final String args, final boolean isPrivate) {
void run(final String sender, final String cmd, final String args, final boolean isPrivate) {
if (StringUtils.isNotBlank(args)) {
try {
final List<Message> messages = getWeather(args, properties.get(OWM_API_KEY_PROP));
if (messages.get(0).isError()) {
helpResponse(bot, sender, isPrivate);
helpResponse(sender, isPrivate);
} else {
for (final Message msg : messages) {
bot.send(sender, msg);
@ -234,7 +234,7 @@ public class Weather2 extends ThreadedModule {
bot.send(e.getMessage());
}
} else {
helpResponse(bot, sender, isPrivate);
helpResponse(sender, isPrivate);
}
}
}

View file

@ -63,9 +63,7 @@ public final class WorldTime extends AbstractModule {
// Supported countries
private static final Map<String, String> COUNTRIES_MAP;
/**
* The time command.
*/
// The Time command
private static final String TIME_CMD = "time";
static {
@ -157,8 +155,8 @@ public final class WorldTime extends AbstractModule {
/**
* Creates a new {@link WorldTime} instance.
*/
public WorldTime() {
super();
public WorldTime(final Mobibot bot) {
super(bot);
help.add("To display a country's current date/time:");
help.add(Utils.helpIndent("%c " + TIME_CMD) + " [<country code>]");
@ -218,8 +216,7 @@ public final class WorldTime extends AbstractModule {
* {@inheritDoc}
*/
@Override
public void commandResponse(final Mobibot bot,
final String sender,
public void commandResponse(final String sender,
final String cmd,
final String args,
final boolean isPrivate) {

View file

@ -55,6 +55,6 @@ public class CalcTest {
@Test
public void testCalcImpl() {
AbstractModuleTest.testAbstractModule(new Calc());
AbstractModuleTest.testAbstractModule(new Calc(null));
}
}

View file

@ -68,6 +68,6 @@ public class CurrencyConverterTest {
@Test
public void testCurrencyConvertererImpl() {
AbstractModuleTest.testAbstractModule(new CurrencyConverter());
AbstractModuleTest.testAbstractModule(new CurrencyConverter(null));
}
}

View file

@ -51,7 +51,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class GoogleSearchTest extends LocalProperties {
@Test
public void testGoogleSearchImpl() {
AbstractModuleTest.testAbstractModule(new GoogleSearch());
AbstractModuleTest.testAbstractModule(new GoogleSearch(null));
}
@SuppressFBWarnings("LEST_LOST_EXCEPTION_STACK_TRACE")

View file

@ -46,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class JokeTest {
@Test
public void testJokeImpl() {
AbstractModuleTest.testAbstractModule(new Joke());
AbstractModuleTest.testAbstractModule(new Joke(null));
}
@Test

View file

@ -49,7 +49,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class LookupTest {
@Test
public void testLookupImpl() {
AbstractModuleTest.testAbstractModule(new Lookup());
AbstractModuleTest.testAbstractModule(new Lookup(null));
}
@Test

View file

@ -46,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class PingTest {
@Test
public void testPingImpl() {
AbstractModuleTest.testAbstractModule(new Ping());
AbstractModuleTest.testAbstractModule(new Ping(null));
}
@Test

View file

@ -84,6 +84,6 @@ public class StockQuoteTest extends LocalProperties {
@Test
public void testStockQuoteImpl() {
AbstractModuleTest.testAbstractModule(new StockQuote());
AbstractModuleTest.testAbstractModule(new StockQuote(null));
}
}

View file

@ -33,7 +33,6 @@
package net.thauvin.erik.mobibot.modules;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import net.thauvin.erik.mobibot.Constants;
import org.testng.annotations.Test;
import java.net.InetAddress;
@ -72,7 +71,7 @@ public class TwitterTest extends LocalProperties {
getProperty(Twitter.CONSUMER_SECRET_PROP),
getProperty(Twitter.TOKEN_PROP),
getProperty(Twitter.TOKEN_SECRET_PROP),
getProperty(Constants.TWITTER_HANDLE_PROP),
getProperty(Twitter.HANDLE_PROP),
msg,
true).getText()).as("twitterPost(" + msg + ')').isEqualTo(msg);
}

View file

@ -74,6 +74,6 @@ public class Weather2Test extends LocalProperties {
@Test
public void testWeather2Impl() {
AbstractModuleTest.testAbstractModule(new Weather2());
AbstractModuleTest.testAbstractModule(new Weather2(null));
}
}

View file

@ -54,6 +54,6 @@ public class WordTimeTest {
@Test
public void testWorldTimeImpl() {
AbstractModuleTest.testAbstractModule(new Lookup());
AbstractModuleTest.testAbstractModule(new Lookup(null));
}
}