From 7759e278e89aa879ee8023aa045c8d0d817ce25e Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Wed, 2 Dec 2020 22:57:25 -0800 Subject: [PATCH] Converter Entry Links manipulation classes to Kotlin. --- config/detekt/baseline.xml | 5 + .../net/thauvin/erik/mobibot/PinboardUtils.kt | 62 +-- .../thauvin/erik/mobibot/commands/Cycle.kt | 18 +- .../thauvin/erik/mobibot/commands/Modules.kt | 16 +- .../erik/mobibot/commands/links/Comment.kt | 4 +- .../erik/mobibot/commands/links/LinksMgr.kt | 3 +- .../erik/mobibot/commands/links/Posting.kt | 2 +- .../erik/mobibot/commands/tell/Tell.java | 4 +- .../commands/tell/TellMessagesMgr.java | 9 +- .../erik/mobibot/entries/EntriesMgr.java | 331 -------------- .../erik/mobibot/entries/EntriesMgr.kt | 261 +++++++++++ .../erik/mobibot/entries/EntriesUtils.java | 120 ----- .../erik/mobibot/entries/EntriesUtils.kt | 83 ++++ .../erik/mobibot/entries/EntryComment.java | 130 ------ .../erik/mobibot/entries/EntryComment.kt | 54 +++ .../erik/mobibot/entries/EntryLink.java | 418 ------------------ .../thauvin/erik/mobibot/entries/EntryLink.kt | 223 ++++++++++ .../thauvin/erik/mobibot/modules/Twitter.kt | 7 +- .../thauvin/erik/mobibot/modules/Weather2.kt | 14 +- ...ocalProperties.java => LocalProperties.kt} | 75 ++-- .../erik/mobibot/entries/EntryLinkTest.java | 100 ----- .../erik/mobibot/entries/EntryLinkTest.kt | 92 ++++ 22 files changed, 818 insertions(+), 1213 deletions(-) delete mode 100644 src/main/java/net/thauvin/erik/mobibot/entries/EntriesMgr.java create mode 100644 src/main/java/net/thauvin/erik/mobibot/entries/EntriesMgr.kt delete mode 100644 src/main/java/net/thauvin/erik/mobibot/entries/EntriesUtils.java create mode 100644 src/main/java/net/thauvin/erik/mobibot/entries/EntriesUtils.kt delete mode 100644 src/main/java/net/thauvin/erik/mobibot/entries/EntryComment.java create mode 100644 src/main/java/net/thauvin/erik/mobibot/entries/EntryComment.kt delete mode 100644 src/main/java/net/thauvin/erik/mobibot/entries/EntryLink.java create mode 100644 src/main/java/net/thauvin/erik/mobibot/entries/EntryLink.kt rename src/test/java/net/thauvin/erik/mobibot/{LocalProperties.java => LocalProperties.kt} (57%) delete mode 100644 src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.java create mode 100644 src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index ed4ec34..07b0938 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -2,7 +2,9 @@ + ComplexMethod:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean ) ComplexMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> + LongMethod:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean ) LongMethod:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> LongMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> LongParameterList:Comment.kt$Comment$( bot: Mobibot, cmd: String, sender: String, isOp: Boolean, entry: EntryLink, index: Int, commentIndex: Int ) @@ -43,6 +45,9 @@ NestedBlockDepth:Addons.kt$Addons$ fun add(command: AbstractCommand, props: Properties) NestedBlockDepth:Comment.kt$Comment$override fun commandResponse( sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean ) NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$ @JvmStatic fun convertCurrency(query: String): Message + NestedBlockDepth:EntriesMgr.kt$EntriesMgr.Companion$ @Throws(IOException::class, FeedException::class) fun loadEntries(file: String, channel: String, entries: ArrayList<EntryLink>): String + NestedBlockDepth:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean ) + NestedBlockDepth:EntryLink.kt$EntryLink$ fun setTags(tags: List<String?>) NestedBlockDepth:FeedReader.kt$FeedReader$ override fun run() NestedBlockDepth:GoogleSearch.kt$GoogleSearch$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean) NestedBlockDepth:LinksMgr.kt$LinksMgr$override fun commandResponse( sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean ) diff --git a/src/main/java/net/thauvin/erik/mobibot/PinboardUtils.kt b/src/main/java/net/thauvin/erik/mobibot/PinboardUtils.kt index 3456a8d..1dad880 100644 --- a/src/main/java/net/thauvin/erik/mobibot/PinboardUtils.kt +++ b/src/main/java/net/thauvin/erik/mobibot/PinboardUtils.kt @@ -44,17 +44,10 @@ import java.util.* /** * The class to handle posts to pinboard.in. - * - * @author [Erik C. Thauvin](https://erik.thauvin.net) - * @created 2017-05-17 - * @since 1.0 */ object PinboardUtils { /** * Adds a pin. - * - * @param poster The PinboardPoster instance. - * @param entry The entry to add. */ @JvmStatic fun addPin(poster: PinboardPoster, ircServer: String, entry: EntryLink) = runBlocking { @@ -72,9 +65,6 @@ object PinboardUtils { /** * Deletes a pin. - * - * @param poster The PinboardPoster instance. - * @param entry The entry to delete. */ @JvmStatic fun deletePin(poster: PinboardPoster, entry: EntryLink) = runBlocking { @@ -86,33 +76,31 @@ object PinboardUtils { /** * Updates a pin. - * - * @param poster The PinboardPoster instance. - * @param oldUrl The old post URL. - * @param entry The entry to add. */ @JvmStatic fun updatePin(poster: PinboardPoster, ircServer: String, oldUrl: String, entry: EntryLink) = runBlocking { val update = GlobalScope.async { - if (oldUrl != entry.link) { - poster.deletePin(oldUrl) - poster.addPin( - entry.link, - entry.title, - postedBy(entry, ircServer), - entry.pinboardTags, - formatDate(entry.date) - ) - } else { - poster.addPin( - entry.link, - entry.title, - postedBy(entry, ircServer), - entry.pinboardTags, - formatDate(entry.date), - replace = true, - shared = true - ) + with(entry) { + if (oldUrl != link) { + poster.deletePin(oldUrl) + poster.addPin( + link, + title, + postedBy(entry, ircServer), + pinboardTags, + formatDate(date) + ) + } else { + poster.addPin( + link, + title, + postedBy(entry, ircServer), + pinboardTags, + formatDate(date), + replace = true, + shared = true + ) + } } } update.await() @@ -120,19 +108,13 @@ object PinboardUtils { /** * Format a date to a UTC timestamp. - * - * @param date The date. - * @return The date in [DateTimeFormatter.ISO_INSTANT] format. */ private fun formatDate(date: Date): String { return ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).format(DateTimeFormatter.ISO_INSTANT) } /** - * Returns he pinboard.in extended attribution line. - * - * @param entry The entry. - * @return The extended attribution line. + * Returns the pinboard.in extended attribution line. */ private fun postedBy(entry: EntryLink, ircServer: String): String { return "Posted by ${entry.nick} on ${entry.channel} ( $ircServer )" diff --git a/src/main/java/net/thauvin/erik/mobibot/commands/Cycle.kt b/src/main/java/net/thauvin/erik/mobibot/commands/Cycle.kt index 1ca4ed2..525ad33 100644 --- a/src/main/java/net/thauvin/erik/mobibot/commands/Cycle.kt +++ b/src/main/java/net/thauvin/erik/mobibot/commands/Cycle.kt @@ -51,14 +51,16 @@ class Cycle(bot: Mobibot) : AbstractCommand(bot) { isOp: Boolean, isPrivate: Boolean ) { - if (isOp) { - bot.send("$sender has just asked me to leave. I'll be back!") - bot.sleep(wait) - bot.partChannel(bot.channel) - bot.sleep(wait) - bot.joinChannel(bot.channel) - } else { - bot.helpDefault(sender, isOp, isPrivate) + with(bot) { + if (isOp) { + send("$sender has just asked me to leave. I'll be back!") + sleep(wait) + partChannel(channel) + sleep(wait) + joinChannel(channel) + } else { + helpDefault(sender, isOp, isPrivate) + } } } } diff --git a/src/main/java/net/thauvin/erik/mobibot/commands/Modules.kt b/src/main/java/net/thauvin/erik/mobibot/commands/Modules.kt index af2f629..447552c 100644 --- a/src/main/java/net/thauvin/erik/mobibot/commands/Modules.kt +++ b/src/main/java/net/thauvin/erik/mobibot/commands/Modules.kt @@ -52,17 +52,17 @@ class Modules(bot: Mobibot) : AbstractCommand(bot) { isOp: Boolean, isPrivate: Boolean ) { - if (isOp) { - with(bot.modulesNames) { - if (isEmpty()) { - bot.send(sender, "There are no enabled modules.", isPrivate) + with(bot) { + if (isOp) { + if (modulesNames.isEmpty()) { + send(sender, "There are no enabled modules.", isPrivate) } else { - bot.send(sender, "The enabled modules are: ", isPrivate) - bot.sendList(sender, this, 7, isPrivate, false) + send(sender, "The enabled modules are: ", isPrivate) + sendList(sender, modulesNames, 7, isPrivate, false) } + } else { + helpDefault(sender, isOp, isPrivate) } - } else { - bot.helpDefault(sender, isOp, isPrivate) } } } diff --git a/src/main/java/net/thauvin/erik/mobibot/commands/links/Comment.kt b/src/main/java/net/thauvin/erik/mobibot/commands/links/Comment.kt index 63f5ffa..00b718a 100644 --- a/src/main/java/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ b/src/main/java/net/thauvin/erik/mobibot/commands/links/Comment.kt @@ -71,7 +71,7 @@ class Comment(bot: Mobibot) : AbstractCommand(bot) { if (index < LinksMgr.entriesCount) { val entry: EntryLink = LinksMgr.getEntry(index) val commentIndex = cmds[1].toInt() - 1 - if (commentIndex < entry.commentsCount) { + if (commentIndex < entry.comments.size) { when (val cmd = cmds[2].trim()) { "" -> showComment(bot, entry, index, commentIndex) // L1.1: "-" -> deleteComment(bot, sender, isOp, entry, index, commentIndex) // L11:- @@ -140,7 +140,7 @@ class Comment(bot: Mobibot) : AbstractCommand(bot) { ) { if (isOp || sender == entry.getComment(commentIndex).nick) { entry.deleteComment(commentIndex) - bot.send("Comment ${Constants.LINK_CMD}${index + 1}.${commentIndex + 1} removed.") + bot.send("Comment ${EntriesUtils.buildLinkCmd(index)}.${commentIndex + 1} removed.") LinksMgr.saveEntries(bot, false) } else { bot.send(sender, "Please ask a channel op to delete this comment for you.", false) diff --git a/src/main/java/net/thauvin/erik/mobibot/commands/links/LinksMgr.kt b/src/main/java/net/thauvin/erik/mobibot/commands/links/LinksMgr.kt index 6db470a..ac5257d 100644 --- a/src/main/java/net/thauvin/erik/mobibot/commands/links/LinksMgr.kt +++ b/src/main/java/net/thauvin/erik/mobibot/commands/links/LinksMgr.kt @@ -40,6 +40,7 @@ import net.thauvin.erik.mobibot.commands.Ignore import net.thauvin.erik.mobibot.entries.EntriesMgr import net.thauvin.erik.mobibot.entries.EntriesUtils import net.thauvin.erik.mobibot.entries.EntryLink +import org.apache.logging.log4j.LogManager import org.jsoup.Jsoup import java.io.IOException @@ -166,7 +167,7 @@ class LinksMgr(bot: Mobibot) : AbstractCommand(bot) { bot.send(sender, "Please specify a title, by typing:", isPrivate) bot.send( sender, - Utils.helpIndent(Constants.LINK_CMD + (index + 1) + ":|This is the title"), + Utils.helpIndent("${EntriesUtils.buildLinkCmd(index)}:|This is the title"), isPrivate ) } diff --git a/src/main/java/net/thauvin/erik/mobibot/commands/links/Posting.kt b/src/main/java/net/thauvin/erik/mobibot/commands/links/Posting.kt index 26a74ce..bf275f5 100644 --- a/src/main/java/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ b/src/main/java/net/thauvin/erik/mobibot/commands/links/Posting.kt @@ -137,7 +137,7 @@ class Posting(bot: Mobibot) : AbstractCommand(bot) { if (entry.login == login || isOp) { bot.deletePin(index, entry) LinksMgr.removeEntry(index) - bot.send("Entry ${Constants.LINK_CMD}${index + 1} removed.") + bot.send("Entry ${EntriesUtils.buildLinkCmd(index)} removed.") LinksMgr.saveEntries(bot, false) } else { bot.send(sender, "Please ask a channel op to remove this entry for you.", false) diff --git a/src/main/java/net/thauvin/erik/mobibot/commands/tell/Tell.java b/src/main/java/net/thauvin/erik/mobibot/commands/tell/Tell.java index 8470320..d3fa026 100644 --- a/src/main/java/net/thauvin/erik/mobibot/commands/tell/Tell.java +++ b/src/main/java/net/thauvin/erik/mobibot/commands/tell/Tell.java @@ -104,7 +104,9 @@ public class Tell extends AbstractCommand { */ @SuppressWarnings("WeakerAccess") final boolean clean() { - getBot().getLogger().debug("Cleaning the messages."); + if (getBot().getLogger().isDebugEnabled()) { + getBot().getLogger().debug("Cleaning the messages."); + } return TellMessagesMgr.clean(messages, maxDays); } diff --git a/src/main/java/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgr.java b/src/main/java/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgr.java index 6be49cd..98eed8a 100644 --- a/src/main/java/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgr.java +++ b/src/main/java/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgr.java @@ -94,8 +94,9 @@ final class TellMessagesMgr { try { try (final ObjectInput input = new ObjectInputStream( new BufferedInputStream(Files.newInputStream(Paths.get(file))))) { - logger.debug("Loading the messages."); - + if (logger.isDebugEnabled()) { + logger.debug("Loading the messages."); + } return ((List) input.readObject()); } } catch (FileNotFoundException ignore) { @@ -118,7 +119,9 @@ final class TellMessagesMgr { try { try (final BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(Paths.get(file)))) { try (final ObjectOutput output = new ObjectOutputStream(bos)) { - logger.debug("Saving the messages."); + if (logger.isDebugEnabled()) { + logger.debug("Saving the messages."); + } output.writeObject(messages); } } diff --git a/src/main/java/net/thauvin/erik/mobibot/entries/EntriesMgr.java b/src/main/java/net/thauvin/erik/mobibot/entries/EntriesMgr.java deleted file mode 100644 index 42c1fb9..0000000 --- a/src/main/java/net/thauvin/erik/mobibot/entries/EntriesMgr.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * EntriesMgr.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.entries; - -import com.rometools.rome.feed.synd.SyndContent; -import com.rometools.rome.feed.synd.SyndContentImpl; -import com.rometools.rome.feed.synd.SyndEntry; -import com.rometools.rome.feed.synd.SyndEntryImpl; -import com.rometools.rome.feed.synd.SyndFeed; -import com.rometools.rome.feed.synd.SyndFeedImpl; -import com.rometools.rome.io.FeedException; -import com.rometools.rome.io.SyndFeedInput; -import com.rometools.rome.io.SyndFeedOutput; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import net.thauvin.erik.mobibot.Mobibot; -import net.thauvin.erik.mobibot.Utils; -import org.apache.commons.lang3.StringUtils; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.List; - -/** - * Manages the feed entries. - * - * @author Erik C. Thauvin - * @created 2014-04-28 - * @since 1.0 - */ -public final class EntriesMgr { - /** - * The name of the file containing the current entries. - */ - public static final String CURRENT_XML = "current.xml"; - - /** - * The name of the file containing the backlog entries. - */ - public static final String NAV_XML = "nav.xml"; - - /** - * The .xml extension - */ - public static final String XML_EXT = ".xml"; - - // Maximum number of backlogs to keep - private static final int MAX_BACKLOGS = 10; - - /** - * Disables the default constructor. - * - * @throws UnsupportedOperationException If the constructor is called. - */ - private EntriesMgr() { - throw new UnsupportedOperationException("Illegal constructor call."); - } - - /** - * Loads the backlogs. - * - * @param file The file containing the backlogs. - * @param history The history list. - * @throws IOException If the file was not found or could not be read. - * @throws FeedException If an error occurred while reading the feed. - */ - public static void loadBacklogs(final String file, final Collection history) - throws IOException, FeedException { - history.clear(); - - final SyndFeedInput input = new SyndFeedInput(); - - try (final InputStreamReader reader = - new InputStreamReader(Files.newInputStream(Paths.get(file)), StandardCharsets.UTF_8)) { - - final SyndFeed feed = input.build(reader); - - final List items = feed.getEntries(); - SyndEntry item; - - for (int i = items.size() - 1; i >= 0; i--) { - item = items.get(i); - history.add(item.getTitle()); - } - } - } - - /** - * Loads the current entries. - * - * @param file The file containing the current entries. - * @param channel The channel - * @param entries The entries. - * @return The feed's last published date. - * @throws IOException If the file was not found or could not be read. - * @throws FeedException If an error occurred while reading the feed. - */ - @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") - public static String loadEntries(final String file, final String channel, final Collection entries) - throws IOException, FeedException { - entries.clear(); - - final SyndFeedInput input = new SyndFeedInput(); - - final String today; - - try (final InputStreamReader reader = new InputStreamReader( - Files.newInputStream(Paths.get(file)), StandardCharsets.UTF_8)) { - final SyndFeed feed = input.build(reader); - - today = Utils.isoLocalDate(feed.getPublishedDate()); - - final List items = feed.getEntries(); - SyndEntry item; - SyndContent description; - String[] comments; - String author; - EntryLink entry; - - for (int i = items.size() - 1; i >= 0; i--) { - item = items.get(i); - author = item.getAuthor() - .substring(item.getAuthor().lastIndexOf('(') + 1, item.getAuthor().length() - 1); - entry = new EntryLink(item.getLink(), - item.getTitle(), - author, - channel, - item.getPublishedDate(), - item.getCategories()); - description = item.getDescription(); - comments = description.getValue().split("
"); - - int split; - for (final String comment : comments) { - split = comment.indexOf(": "); - - if (split != -1) { - entry.addComment(comment.substring(split + 2).trim(), comment.substring(0, split).trim()); - } - } - - entries.add(entry); - } - } - - return today; - } - - /** - * Saves the entries. - * - * @param bot The bot object. - * @param entries The entries array. - * @param history The history array. - * @param isDayBackup Set the true if the daily backup file should also be created. - */ - @SuppressFBWarnings(value = { "CE_CLASS_ENVY", "CC_CYCLOMATIC_COMPLEXITY" }, - justification = "Yes, it does.") - @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") - public static void saveEntries(final Mobibot bot, - final List entries, - final List history, - final boolean isDayBackup) { - bot.getLogger().debug("Saving the feeds..."); - - if (StringUtils.isNotBlank(bot.getLogsDir()) && StringUtils.isNotBlank(bot.getWeblogUrl())) { - try { - final SyndFeedOutput output = new SyndFeedOutput(); - SyndFeed rss = new SyndFeedImpl(); - final List items = new ArrayList<>(0); - SyndEntry item; - SyndContent description; - try (final Writer fw = new OutputStreamWriter( - Files.newOutputStream(Paths.get(bot.getLogsDir() + CURRENT_XML)), StandardCharsets.UTF_8)) { - rss.setFeedType("rss_2.0"); - rss.setTitle(bot.getChannel() + " IRC Links"); - rss.setDescription("Links from " + bot.getIrcServer() + " on " + bot.getChannel()); - rss.setLink(bot.getWeblogUrl()); - rss.setPublishedDate(Calendar.getInstance().getTime()); - rss.setLanguage("en"); - - EntryLink entry; - StringBuilder buff; - EntryComment comment; - - for (int i = (entries.size() - 1); i >= 0; --i) { - entry = entries.get(i); - - buff = new StringBuilder() - .append("Posted by ") - .append(entry.getNick()) - .append(" on ") - .append(entry.getChannel()) - .append(""); - - if (entry.getCommentsCount() > 0) { - buff.append("

"); - - final EntryComment[] comments = entry.getComments(); - - for (int j = 0; j < comments.length; j++) { - comment = comments[j]; - - if (j > 0) { - buff.append("
"); - } - - buff.append(comment.getNick()).append(": ").append(comment.getComment()); - } - } - - item = new SyndEntryImpl(); - item.setLink(entry.getLink()); - description = new SyndContentImpl(); - description.setValue(buff.toString()); - item.setDescription(description); - item.setTitle(entry.getTitle()); - item.setPublishedDate(entry.getDate()); - item.setAuthor( - bot.getChannel().substring(1) + '@' + bot.getIrcServer() + " (" + entry.getNick() - + ')'); - item.setCategories(entry.getTags()); - - items.add(item); - } - - rss.setEntries(items); - - bot.getLogger().debug("Writing the entries feed."); - output.output(rss, fw); - } - - try (final Writer fw = new OutputStreamWriter( - Files.newOutputStream(Paths.get( - bot.getLogsDir() + bot.getToday() + XML_EXT)), StandardCharsets.UTF_8)) { - output.output(rss, fw); - } - - if (isDayBackup) { - if (StringUtils.isNotBlank(bot.getBacklogsUrl())) { - if (!history.contains(bot.getToday())) { - history.add(bot.getToday()); - - while (history.size() > MAX_BACKLOGS) { - history.remove(0); - } - } - - try (final Writer fw = new OutputStreamWriter( - Files.newOutputStream(Paths.get(bot.getLogsDir() + NAV_XML)), StandardCharsets.UTF_8)) { - rss = new SyndFeedImpl(); - rss.setFeedType("rss_2.0"); - rss.setTitle(bot.getChannel() + " IRC Links Backlogs"); - rss.setDescription("Backlogs of Links from " + bot.getIrcServer() + " on " - + bot.getChannel()); - rss.setLink(bot.getBacklogsUrl()); - rss.setPublishedDate(Calendar.getInstance().getTime()); - - String date; - items.clear(); - - for (int i = (history.size() - 1); i >= 0; --i) { - date = history.get(i); - - item = new SyndEntryImpl(); - item.setLink(bot.getBacklogsUrl() + date + ".xml"); - item.setTitle(date); - description = new SyndContentImpl(); - description.setValue("Links for " + date); - item.setDescription(description); - - items.add(item); - } - - rss.setEntries(items); - - bot.getLogger().debug("Writing the backlog feed."); - output.output(rss, fw); - } - } else { - bot.getLogger().warn("Unable to generate the backlogs feed. No property configured."); - } - } - } catch (FeedException | IOException e) { - bot.getLogger().warn("Unable to generate the entries feed.", e); - } - } else { - bot.getLogger().warn("Unable to generate the entries feed. A required property is missing."); - } - } -} diff --git a/src/main/java/net/thauvin/erik/mobibot/entries/EntriesMgr.kt b/src/main/java/net/thauvin/erik/mobibot/entries/EntriesMgr.kt new file mode 100644 index 0000000..a526542 --- /dev/null +++ b/src/main/java/net/thauvin/erik/mobibot/entries/EntriesMgr.kt @@ -0,0 +1,261 @@ +/* + * EntriesMgr.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.entries + +import com.rometools.rome.feed.synd.SyndContentImpl +import com.rometools.rome.feed.synd.SyndEntry +import com.rometools.rome.feed.synd.SyndEntryImpl +import com.rometools.rome.feed.synd.SyndFeed +import com.rometools.rome.feed.synd.SyndFeedImpl +import com.rometools.rome.io.FeedException +import com.rometools.rome.io.SyndFeedInput +import com.rometools.rome.io.SyndFeedOutput +import net.thauvin.erik.mobibot.Mobibot +import net.thauvin.erik.mobibot.Utils.Companion.isoLocalDate +import org.apache.commons.lang3.StringUtils +import java.io.IOException +import java.io.InputStreamReader +import java.io.OutputStreamWriter +import java.nio.charset.StandardCharsets +import java.nio.file.Files +import java.nio.file.Paths +import java.util.* +import kotlin.collections.ArrayList + +/** + * Manages the feed entries. + */ +class EntriesMgr private constructor() { + + + companion object { + /** + * The name of the file containing the current entries. + */ + const val CURRENT_XML = "current.xml" + + /** + * The name of the file containing the backlog entries. + */ + const val NAV_XML = "nav.xml" + + /** + * The .xml extension + */ + const val XML_EXT = ".xml" + + // Maximum number of backlogs to keep + private const val MAX_BACKLOGS = 10 + + /** + * Loads the backlogs. + */ + @Throws(IOException::class, FeedException::class) + fun loadBacklogs(file: String, history: ArrayList) { + history.clear() + val input = SyndFeedInput() + InputStreamReader(Files.newInputStream(Paths.get(file)), StandardCharsets.UTF_8).use { reader -> + val feed = input.build(reader) + val items = feed.entries + for (i in items.indices.reversed()) { + history.add(items[i].title) + } + } + } + + /** + * Loads the current entries. + */ + @Throws(IOException::class, FeedException::class) + fun loadEntries(file: String, channel: String, entries: ArrayList): String { + entries.clear() + val input = SyndFeedInput() + var today: String + InputStreamReader( + Files.newInputStream(Paths.get(file)), StandardCharsets.UTF_8 + ).use { reader -> + val feed = input.build(reader) + today = isoLocalDate(feed.publishedDate) + val items = feed.entries + var entry: EntryLink + for (i in items.indices.reversed()) { + with(items[i]) { + entry = EntryLink( + link, + title, + author.substring(author.lastIndexOf('(') + 1, author.length - 1), + channel, + publishedDate, + categories + ) + var split: List + for (comment in description.value.split("
")) { + split = comment.split(": ".toRegex(), 2) + if (split.size == 2) { + entry.addComment(comment = split[1].trim(), nick = split[0].trim()) + } + } + } + entries.add(entry) + } + } + return today + } + + /** + * Saves the entries. + */ + fun saveEntries( + bot: Mobibot, + entries: List, + history: MutableList, + isDayBackup: Boolean + ) { + if (bot.logger.isDebugEnabled) { + bot.logger.debug("Saving the feeds...") + } + if (StringUtils.isNotBlank(bot.logsDir) && StringUtils.isNotBlank(bot.weblogUrl)) { + try { + val output = SyndFeedOutput() + var rss: SyndFeed = SyndFeedImpl() + val items: MutableList = ArrayList(0) + var item: SyndEntry + OutputStreamWriter( + Files.newOutputStream(Paths.get(bot.logsDir + CURRENT_XML)), StandardCharsets.UTF_8 + ).use { fw -> + rss.apply { + feedType = "rss_2.0" + title = bot.channel + " IRC Links" + description = "Links from ${bot.ircServer} on ${bot.channel}" + link = bot.weblogUrl + publishedDate = Calendar.getInstance().time + language = "en" + } + var buff: StringBuilder + var comment: EntryComment + for (i in entries.size - 1 downTo 0) { + with(entries[i]) { + buff = StringBuilder() + .append("Posted by ") + .append(nick) + .append(" on ") + .append(channel) + .append("") + if (comments.size > 0) { + buff.append("

") + val comments = comments + for (j in comments.indices) { + comment = comments[j] + if (j > 0) { + buff.append("
") + } + buff.append(comment.nick).append(": ").append(comment.comment) + } + } + item = SyndEntryImpl() + item.link = link + item.description = SyndContentImpl().apply { value = buff.toString() } + item.title = title + item.publishedDate = date + item.author = "${bot.channel.substring(1)}@${bot.ircServer} ($nick)" + item.categories = tags + items.add(item) + } + } + rss.entries = items + if (bot.logger.isDebugEnabled) { + bot.logger.debug("Writing the entries feed.") + } + output.output(rss, fw) + } + OutputStreamWriter( + Files.newOutputStream( + Paths.get( + bot.logsDir + bot.today + XML_EXT + ) + ), StandardCharsets.UTF_8 + ).use { fw -> output.output(rss, fw) } + if (isDayBackup) { + if (StringUtils.isNotBlank(bot.backlogsUrl)) { + if (!history.contains(bot.today)) { + history.add(bot.today) + while (history.size > MAX_BACKLOGS) { + history.removeAt(0) + } + } + OutputStreamWriter( + Files.newOutputStream(Paths.get(bot.logsDir + NAV_XML)), StandardCharsets.UTF_8 + ).use { fw -> + rss = SyndFeedImpl() + rss.apply { + feedType = "rss_2.0" + title = "${bot.channel} IRC Links Backlogs" + description = "Backlogs of Links from ${bot.ircServer} on ${bot.channel}" + link = bot.backlogsUrl + publishedDate = Calendar.getInstance().time + } + var date: String + items.clear() + for (i in history.size - 1 downTo 0) { + date = history[i] + item = SyndEntryImpl() + item.apply { + link = bot.backlogsUrl + date + ".xml" + title = date + description = SyndContentImpl().apply { value = "Links for $date" } + } + items.add(item) + } + rss.entries = items + if (bot.logger.isDebugEnabled) { + bot.logger.debug("Writing the backlog feed.") + } + output.output(rss, fw) + } + } else { + bot.logger.warn("Unable to generate the backlogs feed. No property configured.") + } + } + } catch (e: FeedException) { + bot.logger.warn("Unable to generate the entries feed.", e) + } catch (e: IOException) { + bot.logger.warn("Unable to generate the entries feed.", e) + } + } else { + bot.logger.warn("Unable to generate the entries feed. A required property is missing.") + } + } + } +} diff --git a/src/main/java/net/thauvin/erik/mobibot/entries/EntriesUtils.java b/src/main/java/net/thauvin/erik/mobibot/entries/EntriesUtils.java deleted file mode 100644 index e114d66..0000000 --- a/src/main/java/net/thauvin/erik/mobibot/entries/EntriesUtils.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * EntriesUtils.java - * - * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of this project nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.thauvin.erik.mobibot.entries; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import net.thauvin.erik.mobibot.Constants; -import net.thauvin.erik.mobibot.Utils; - -/** - * The Utils class. - * - * @author Erik C. Thauvin - * @created 2019-04-19 - * @since 1.0 - */ -public final class EntriesUtils { - /** - * Disables the default constructor. - */ - private EntriesUtils() { - throw new UnsupportedOperationException("Illegal constructor call."); - } - - /** - * Builds an entry's comment for display on the channel. - * - * @param entryIndex The entry's index. - * @param commentIndex The comment's index. - * @param comment The {@link EntryComment comment} object. - * @return The entry's comment. - */ - public static String buildComment(final int entryIndex, final int commentIndex, final EntryComment comment) { - return (Constants.LINK_CMD + (entryIndex + 1) + '.' + (commentIndex + 1) + ": [" + comment.getNick() + "] " - + comment.getComment()); - } - - /** - * Builds an entry's link for display on the channel. - * - * @param index The entry's index. - * @param entry The {@link EntryLink entry} object. - * @return The entry's link. - * @see #buildLink(int, EntryLink, boolean) - */ - public static String buildLink(final int index, final EntryLink entry) { - return buildLink(index, entry, false); - } - - /** - * Builds an entry's link for display on the channel. - * - * @param index The entry's index. - * @param entry The {@link EntryLink entry} object. - * @param isView Set to true to display the number of comments. - * @return The entry's link. - */ - @SuppressFBWarnings(value = "CE_CLASS_ENVY", - justification = "Yes, it does.") - public static String buildLink(final int index, final EntryLink entry, final boolean isView) { - final StringBuilder buff = new StringBuilder().append(Constants.LINK_CMD).append(index + 1) - .append(": ").append('[').append(entry.getNick()).append(']'); - - if (isView && entry.hasComments()) { - buff.append("[+").append(entry.getCommentsCount()).append(']'); - } - - buff.append(' '); - - if (Constants.NO_TITLE.equals(entry.getTitle())) { - buff.append(entry.getTitle()); - } else { - buff.append(Utils.bold(entry.getTitle())); - } - - buff.append(" ( ").append(Utils.green(entry.getLink())).append(" )"); - - return buff.toString(); - } - - /** - * Build an entry's tags/categories for display on the channel. - * - * @param entryIndex The entry's index. - * @param entry The {@link EntryLink entry} object. - * @return The entry's tags. - */ - public static String buildTags(final int entryIndex, final EntryLink entry) { - return (Constants.LINK_CMD + (entryIndex + 1) + "T: " + entry.getPinboardTags().replace(",", ", ")); - } -} diff --git a/src/main/java/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/src/main/java/net/thauvin/erik/mobibot/entries/EntriesUtils.kt new file mode 100644 index 0000000..a96bad0 --- /dev/null +++ b/src/main/java/net/thauvin/erik/mobibot/entries/EntriesUtils.kt @@ -0,0 +1,83 @@ +/* + * EntriesUtils.kt + * + * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.entries + +import net.thauvin.erik.mobibot.Constants +import net.thauvin.erik.mobibot.Utils.Companion.bold +import net.thauvin.erik.mobibot.Utils.Companion.green + +/** + * The `Utils` class. + */ +class EntriesUtils private constructor() { + companion object { + /** + * Build link cmd based on its index. e.g: L1 + */ + fun buildLinkCmd(index: Int): String = Constants.LINK_CMD + (index + 1) + + /** + * Builds an entry's comment for display on the channel. + */ + fun buildComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String = + (buildLinkCmd(entryIndex) + '.' + (commentIndex + 1) + ": [" + comment.nick + "] " + + comment.comment) + + /** + * Builds an entry's link for display on the channel. + */ + @JvmOverloads + fun buildLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String { + val buff = StringBuilder().append(buildLinkCmd(entryIndex)).append(": ") + .append('[').append(entry.nick).append(']') + if (isView && entry.hasComments()) { + buff.append("[+").append(entry.comments.size).append(']') + } + buff.append(' ') + with(entry) { + if (Constants.NO_TITLE == title) { + buff.append(title) + } else { + buff.append(bold(title)) + } + buff.append(" ( ").append(green(link)).append(" )") + } + return buff.toString() + } + + /** + * Build an entry's tags/categories for display on the channel. + */ + fun buildTags(entryIndex: Int, entry: EntryLink): String = + buildLinkCmd(entryIndex) + "T: " + entry.pinboardTags.replace(",", ", ") + } +} diff --git a/src/main/java/net/thauvin/erik/mobibot/entries/EntryComment.java b/src/main/java/net/thauvin/erik/mobibot/entries/EntryComment.java deleted file mode 100644 index 5c51f1a..0000000 --- a/src/main/java/net/thauvin/erik/mobibot/entries/EntryComment.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * EntryComment.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.entries; - -import java.io.Serializable; -import java.time.LocalDateTime; - -/** - * The class used to store comments associated to a specific entry. - * - * @author Erik C. Thauvin - * @created Jan 31, 2004 - * @since 1.0 - */ -@SuppressWarnings({ "PMD.DataClass" }) -public class EntryComment implements Serializable { - // Serial version UID - static final long serialVersionUID = 1L; - - // Creation date - private final LocalDateTime date = LocalDateTime.now(); - - private String comment = ""; - private String nick = ""; - - /** - * Creates a new comment. - * - * @param comment The new comment. - * @param nick The nickname of the comment's author. - */ - public EntryComment(final String comment, final String nick) { - this.comment = comment; - this.nick = nick; - } - - /** - * Creates a new comment. - */ - @SuppressWarnings("UnusedDeclaration") - protected EntryComment() { - // Required for serialization - } - - /** - * Returns the comment. - * - * @return The comment. - */ - public final String getComment() { - return comment; - } - - /** - * Returns the comment's creation date. - * - * @return The date. - */ - @SuppressWarnings("UnusedDeclaration") - public final LocalDateTime getDate() { - return date; - } - - /** - * Returns the nickname of the author of the comment. - * - * @return The nickname. - */ - public final String getNick() { - return nick; - } - - /** - * Sets the comment. - * - * @param comment The actual comment. - */ - @SuppressWarnings("UnusedDeclaration") - public final void setComment(final String comment) { - this.comment = comment; - } - - /** - * Sets the nickname of the author of the comment. - * - * @param nick The new nickname. - */ - public final void setNick(final String nick) { - this.nick = nick; - } - - @Override - public String toString() { - return "EntryComment{" - + "comment='" + comment + '\'' - + ", date=" + date - + ", nick='" + nick + '\'' - + '}'; - } -} diff --git a/src/main/java/net/thauvin/erik/mobibot/entries/EntryComment.kt b/src/main/java/net/thauvin/erik/mobibot/entries/EntryComment.kt new file mode 100644 index 0000000..0052a0f --- /dev/null +++ b/src/main/java/net/thauvin/erik/mobibot/entries/EntryComment.kt @@ -0,0 +1,54 @@ +/* + * EntryComment.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.entries + +import java.io.Serializable +import java.time.LocalDateTime + +/** + * Entry comments data class. + */ +data class EntryComment(var comment: String, var nick: String) : Serializable { + /** + * Creation date. + */ + val date: LocalDateTime = LocalDateTime.now() + + override fun toString(): String { + return ("EntryComment{comment='$comment', date=$date, nick='$nick'}") + } + + companion object { + // Serial version UID + const val serialVersionUID = 1L + } +} diff --git a/src/main/java/net/thauvin/erik/mobibot/entries/EntryLink.java b/src/main/java/net/thauvin/erik/mobibot/entries/EntryLink.java deleted file mode 100644 index ba9a3f5..0000000 --- a/src/main/java/net/thauvin/erik/mobibot/entries/EntryLink.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * EntryLink.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.entries; - -import com.rometools.rome.feed.synd.SyndCategory; -import com.rometools.rome.feed.synd.SyndCategoryImpl; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import net.thauvin.erik.mobibot.commands.links.LinksMgr; -import org.apache.commons.lang3.StringUtils; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * The class used to store link entries. - * - * @author Erik C. Thauvin - * @created Jan 31, 2004 - * @since 1.0 - */ -public class EntryLink implements Serializable { - // Serial version UID - static final long serialVersionUID = 1L; - - // Link's comments - private final List comments = new CopyOnWriteArrayList<>(); - - // Tags/categories - private final List tags = new CopyOnWriteArrayList<>(); - - // Channel - private String channel; - - // Creation date - private Date date = Calendar.getInstance().getTime(); - - // Link's URL - private String link; - - // Author's login - private String login = ""; - - // Author's nickname - private String nick; - - // Link's title - private String title; - - /** - * Creates a new entry. - * - * @param link The new entry's link. - * @param title The new entry's title. - * @param nick The nickname of the author of the link. - * @param login The login of the author of the link. - * @param channel The channel. - * @param tags The entry's tags/categories. - */ - public EntryLink(final String link, - final String title, - final String nick, - final String login, - final String channel, - final List tags) { - this.link = link; - this.title = title; - this.nick = nick; - this.login = login; - this.channel = channel; - - setTags(tags); - } - - /** - * Creates a new entry. - * - * @param link The new entry's link. - * @param title The new entry's title. - * @param nick The nickname of the author of the link. - * @param channel The channel. - * @param date The entry date. - * @param tags The entry's tags/categories. - */ - public EntryLink(final String link, - final String title, - final String nick, - final String channel, - final Date date, - final List tags) { - this.link = link; - this.title = title; - this.nick = nick; - this.channel = channel; - this.date = new Date(date.getTime()); - this.tags.addAll(tags); - } - - /** - * Adds a new comment. - * - * @param comment The actual comment. - * @param nick The nickname of the author of the comment. - * @return The total number of comments for this entry. - */ - public final int addComment(final String comment, final String nick) { - comments.add(new EntryComment(comment, nick)); - - return (comments.size() - 1); - } - - /** - * Deletes a specific comment. - * - * @param index The index of the comment to delete. - */ - public final void deleteComment(final int index) { - if (index < comments.size()) { - comments.remove(index); - } - } - - /** - * Returns the channel the link was posted on. - * - * @return The channel - */ - public final String getChannel() { - return channel; - } - - /** - * Returns a comment. - * - * @param index The comment's index. - * @return The specific comment. - */ - public final EntryComment getComment(final int index) { - return (comments.get(index)); - } - - /** - * Returns all the comments. - * - * @return The comments. - */ - public final EntryComment[] getComments() { - return (comments.toArray(new EntryComment[0])); - } - - /** - * Returns the total number of comments. - * - * @return The count of comments. - */ - public final int getCommentsCount() { - return comments.size(); - } - - /** - * Returns the comment's creation date. - * - * @return The date. - */ - public final Date getDate() { - return new Date(date.getTime()); - } - - /** - * Returns the comment's link. - * - * @return The link. - */ - public final String getLink() { - return link; - } - - /** - * Returns the comment's author login. - * - * @return The login; - */ - public final String getLogin() { - return login; - } - - /** - * Returns the comment's author nickname. - * - * @return The nickname. - */ - public final String getNick() { - return nick; - } - - /** - * Returns the tags formatted for pinboard.in - * - * @return The tags as a comma-delimited string. - */ - public final String getPinboardTags() { - final StringBuilder pinboardTags = new StringBuilder(nick); - - for (final SyndCategory tag : tags) { - pinboardTags.append(','); - pinboardTags.append(tag.getName()); - } - - return pinboardTags.toString(); - } - - /** - * Returns the tags. - * - * @return The tags. - */ - public final List getTags() { - return tags; - } - - /** - * Returns the comment's title. - * - * @return The title. - */ - public final String getTitle() { - return title; - } - - /** - * Returns true if the entry has comments. - * - * @return true if there are comments, false otherwise. - */ - public final boolean hasComments() { - return !comments.isEmpty(); - } - - /** - * Returns true if the entry has tags. - * - * @return true if there are tags, false otherwise. - */ - public final boolean hasTags() { - return !tags.isEmpty(); - } - - /** - * Returns true if a string is contained in the link, title, or nick. - * - * @param match The string to match. - * @return {@code true} if matched, {@code false} otherwise. - */ - public Boolean matches(final String match) { - return (StringUtils.containsIgnoreCase(link, match) - || StringUtils.containsIgnoreCase(title, match) - || StringUtils.containsIgnoreCase(nick, match)); - } - - /** - * Sets the channel. - * - * @param channel The channel. - */ - @SuppressWarnings("UnusedDeclaration") - public final void setChannel(final String channel) { - this.channel = channel; - } - - /** - * /** Sets a comment. - * - * @param index The comment's index. - * @param comment The actual comment. - * @param nick The nickname of the author of the comment. - */ - public final void setComment(final int index, final String comment, final String nick) { - if (index < comments.size()) { - comments.set(index, new EntryComment(comment, nick)); - } - } - - /** - * Sets the comment's link. - * - * @param link The new link. - */ - public final void setLink(final String link) { - this.link = link; - } - - /** - * Sets the comment's author login. - * - * @param login The new login. - */ - @SuppressWarnings("UnusedDeclaration") - public final void setLogin(final String login) { - this.login = login; - } - - /** - * Sets the comment's author nickname. - * - * @param nick The new nickname. - */ - public final void setNick(final String nick) { - this.nick = nick; - } - - /** - * Sets the tags. - * - * @param tags The space-delimited tags. - */ - public final void setTags(final String tags) { - setTags(Arrays.asList(tags.split(LinksMgr.TAG_MATCH))); - } - - /** - * Sets the tags. - * - * @param tags The tags list. - */ - @SuppressFBWarnings("STT_STRING_PARSING_A_FIELD") - @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") - public final void setTags(final List tags) { - if (!tags.isEmpty()) { - SyndCategoryImpl category; - - for (final String tag : tags) { - if (StringUtils.isNoneBlank(tag)) { - final String t = StringUtils.lowerCase(tag); - final char mod = t.charAt(0); - if (mod == '-') { - // Don't remove the channel tag - if (!channel.substring(1).equals(t.substring(1))) { - category = new SyndCategoryImpl(); - category.setName(t.substring(1)); - this.tags.remove(category); - } - } else { - category = new SyndCategoryImpl(); - if (mod == '+') { - category.setName(t.substring(1)); - } else { - category.setName(t); - } - if (!this.tags.contains(category)) { - this.tags.add(category); - } - } - } - } - } - } - - /** - * Sets the comment's title. - * - * @param title The new title. - */ - public final void setTitle(final String title) { - this.title = title; - } - - /** - * Returns a string representation of the object. - * - * @return A string representation of the object. - */ - @Override - public String toString() { - return "EntryLink{" - + "channel='" + channel + '\'' - + ", comments=" + comments - + ", date=" + date - + ", link='" + link + '\'' - + ", login='" + login + '\'' - + ", nick='" + nick + '\'' - + ", tags=" + tags - + ", title='" + title + '\'' - + '}'; - } -} diff --git a/src/main/java/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/java/net/thauvin/erik/mobibot/entries/EntryLink.kt new file mode 100644 index 0000000..9601d17 --- /dev/null +++ b/src/main/java/net/thauvin/erik/mobibot/entries/EntryLink.kt @@ -0,0 +1,223 @@ +/* + * EntryLink.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.entries + +import com.rometools.rome.feed.synd.SyndCategory +import com.rometools.rome.feed.synd.SyndCategoryImpl +import net.thauvin.erik.mobibot.commands.links.LinksMgr +import org.apache.commons.lang3.StringUtils +import java.io.Serializable +import java.util.* +import java.util.concurrent.CopyOnWriteArrayList + +/** + * The class used to store link entries. + */ +class EntryLink : Serializable { + // Link's comments + val comments: MutableList = CopyOnWriteArrayList() + + // Tags/categories + val tags: MutableList = CopyOnWriteArrayList() + + // Channel + var channel: String + + // Creation date + var date = Calendar.getInstance().time + + // Link's URL + var link: String + + // Author's login + var login = "" + + // Author's nickname + var nick: String + + // Link's title + var title: String + + /** + * Creates a new entry. + */ + constructor( + link: String, + title: String, + nick: String, + login: String, + channel: String, + tags: List + ) { + this.link = link + this.title = title + this.nick = nick + this.login = login + this.channel = channel + setTags(tags) + } + + /** + * Creates a new entry. + */ + constructor( + link: String, + title: String, + nick: String, + channel: String, + date: Date, + tags: List + ) { + this.link = link + this.title = title + this.nick = nick + this.channel = channel + this.date = Date(date.time) + this.tags.addAll(tags) + } + + /** + * Adds a new comment. + */ + fun addComment(comment: String?, nick: String?): Int { + comments.add(EntryComment(comment!!, nick!!)) + return comments.size - 1 + } + + /** + * Deletes a specific comment. + */ + fun deleteComment(index: Int) { + if (index < comments.size) { + comments.removeAt(index) + } + } + + /** + * Returns a comment. + */ + fun getComment(index: Int): EntryComment = comments[index] + + /** + * Returns the tags formatted for pinboard.in + */ + val pinboardTags: String + get() { + val pinboardTags = StringBuilder(nick) + for (tag in tags) { + pinboardTags.append(',') + pinboardTags.append(tag.name) + } + return pinboardTags.toString() + } + + /** + * Returns true if the entry has comments. + */ + fun hasComments(): Boolean = comments.isNotEmpty() + + /** + * Returns true if the entry has tags. + */ + fun hasTags(): Boolean = tags.isNotEmpty() + + /** + * Returns true if a string is contained in the link, title, or nick. + */ + fun matches(match: String?): Boolean { + return (StringUtils.containsIgnoreCase(link, match) + || StringUtils.containsIgnoreCase(title, match) + || StringUtils.containsIgnoreCase(nick, match)) + } + + /** + * Sets a comment. + */ + fun setComment(index: Int, comment: String?, nick: String?) { + if (index < comments.size) { + comments[index] = EntryComment(comment!!, nick!!) + } + } + + /** + * Sets the tags. + */ + fun setTags(tags: String) { + setTags(tags.split(LinksMgr.TAG_MATCH).toTypedArray().toList()) + } + + /** + * Sets the tags. + */ + fun setTags(tags: List) { + if (!tags.isEmpty()) { + var category: SyndCategoryImpl + for (tag in tags) { + if (StringUtils.isNoneBlank(tag)) { + val t = StringUtils.lowerCase(tag) + val mod = t[0] + if (mod == '-') { + // Don't remove the channel tag + if (channel.substring(1) != t.substring(1)) { + category = SyndCategoryImpl() + category.name = t.substring(1) + this.tags.remove(category) + } + } else { + category = SyndCategoryImpl() + if (mod == '+') { + category.name = t.substring(1) + } else { + category.name = t + } + if (!this.tags.contains(category)) { + this.tags.add(category) + } + } + } + } + } + } + + /** + * Returns a string representation of the object. + */ + override fun toString(): String { + return ("EntryLink{channel='$channel', comments=$comments, date=$date, link='$link', login='$login'," + + "nick='$nick', tags=$tags, title='$title'}") + } + + companion object { + // Serial version UID + const val serialVersionUID = 1L + } +} diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.kt b/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.kt index 07de9f9..014846f 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.kt +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Twitter.kt @@ -37,6 +37,7 @@ import net.thauvin.erik.mobibot.TwitterTimer import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.commands.links.LinksMgr.Companion.entriesCount import net.thauvin.erik.mobibot.commands.links.LinksMgr.Companion.getEntry +import net.thauvin.erik.mobibot.entries.EntriesUtils import net.thauvin.erik.mobibot.msg.Message import net.thauvin.erik.mobibot.msg.NoticeMessage import org.apache.commons.lang3.StringUtils @@ -76,7 +77,7 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) { override val isValidProperties: Boolean get() { for (s in propertyKeys) { - if (AUTOPOST_PROP != s && HANDLE_PROP != s && properties[s]!!.isBlank()) { + if (AUTOPOST_PROP != s && HANDLE_PROP != s && properties[s].isNullOrBlank()) { return false } } @@ -130,7 +131,7 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) { Thread { try { if (logger.isDebugEnabled) { - logger.debug("Posting {}{} to Twitter.", Constants.LINK_CMD, index + 1) + logger.debug("Posting {} to Twitter.", EntriesUtils.buildLinkCmd(index)) } post(message = msg, isDm = false) } catch (e: ModuleException) { @@ -146,7 +147,7 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) { if (isAutoPost) { addEntry(index) if (bot.logger.isDebugEnabled) { - bot.logger.debug("Scheduling {}{} for posting on Twitter.", Constants.LINK_CMD, index + 1) + bot.logger.debug("Scheduling {} for posting on Twitter.", EntriesUtils.buildLinkCmd(index)) } bot.timer.schedule(TwitterTimer(bot, index), Constants.TIMER_DELAY * 60L * 1000L) } diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/java/net/thauvin/erik/mobibot/modules/Weather2.kt index d1dcf25..9fc9847 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/Weather2.kt +++ b/src/main/java/net/thauvin/erik/mobibot/modules/Weather2.kt @@ -138,8 +138,8 @@ class Weather2(bot: Mobibot) : ThreadedModule(bot) { } if (cwd.hasWindData()) { with(cwd.windData) { - if (this != null && hasSpeed()) { - messages.add(NoticeMessage("Wind: ${wind(speed)}")) + if (this != null && hasSpeed() && speed != null) { + messages.add(NoticeMessage("Wind: ${wind(speed!!)}")) } } } @@ -148,7 +148,9 @@ class Weather2(bot: Mobibot) : ThreadedModule(bot) { val list = cwd.weatherList if (list != null) { for (w in list) { - condition.append(' ').append(w!!.getDescription().capitalize()).append('.') + if (w != null) { + condition.append(' ').append(w.getDescription().capitalize()).append('.') + } } messages.add(NoticeMessage(condition.toString())) } @@ -182,9 +184,9 @@ class Weather2(bot: Mobibot) : ThreadedModule(bot) { return messages } - private fun wind(w: Double?): String { - val kmh = w!! * 1.60934 - return "${Math.round(w)} mph, ${kmh.roundToInt()} km/h" + private fun wind(w: Double): String { + val kmh = w * 1.60934 + return "${w.roundToInt()} mph, ${kmh.roundToInt()} km/h" } } diff --git a/src/test/java/net/thauvin/erik/mobibot/LocalProperties.java b/src/test/java/net/thauvin/erik/mobibot/LocalProperties.kt similarity index 57% rename from src/test/java/net/thauvin/erik/mobibot/LocalProperties.java rename to src/test/java/net/thauvin/erik/mobibot/LocalProperties.kt index 1585681..04490ed 100644 --- a/src/test/java/net/thauvin/erik/mobibot/LocalProperties.java +++ b/src/test/java/net/thauvin/erik/mobibot/LocalProperties.kt @@ -1,5 +1,5 @@ /* - * LocalProperties.java + * LocalProperties.kt * * Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net) * All rights reserved. @@ -29,54 +29,47 @@ * 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 -package net.thauvin.erik.mobibot; - -import org.apache.commons.lang3.StringUtils; -import org.testng.annotations.BeforeSuite; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Properties; +import org.testng.annotations.BeforeSuite +import java.io.IOException +import java.nio.file.Files +import java.nio.file.Paths +import java.util.* /** - * The properties class. - * - * @author Erik C. Thauvin - * @created 2019-04-08 - * @since 1.0 + * Access to `local.properties`. */ -public class LocalProperties { - private static final Properties localProps = new Properties(); - - public static String getProperty(final String key) { - if (localProps.containsKey(key)) { - return localProps.getProperty(key); - } else { - final String env = System.getenv(keyToEnv(key)); - if (env != null) { - localProps.setProperty(key, env); - } - return env; - } - } - - private static String keyToEnv(final String key) { - return StringUtils.upperCase(key.replace('-', '_')); - } - +open class LocalProperties { @BeforeSuite(alwaysRun = true) - public void loadProperties() { - final Path localPath = Paths.get("local.properties"); + fun loadProperties() { + val localPath = Paths.get("local.properties") if (Files.exists(localPath)) { - try (final InputStream stream = Files.newInputStream(localPath)) { - localProps.load(stream); - } catch (IOException ignore) { + try { + Files.newInputStream(localPath).use { stream -> localProps.load(stream) } + } catch (ignore: IOException) { // Do nothing } } } + + companion object { + private val localProps = Properties() + + fun getProperty(key: String): String { + return if (localProps.containsKey(key)) { + localProps.getProperty(key) + } else { + val env = System.getenv(keyToEnv(key)) + if (env != null) { + localProps.setProperty(key, env) + } + env + } + } + + private fun keyToEnv(key: String): String { + return key.replace('-', '_').toUpperCase() + } + } } diff --git a/src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.java b/src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.java deleted file mode 100644 index 68550bc..0000000 --- a/src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * EntryLinkTest.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.entries; - -import com.rometools.rome.feed.synd.SyndCategory; -import org.testng.annotations.Test; - -import java.security.SecureRandom; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * The EntryUtilsTest class. - * - * @author Erik C. Thauvin - * @created 2019-04-19 - * @since 1.0 - */ -public class EntryLinkTest { - private final EntryLink entryLink = new EntryLink("https://www.mobitopia.org/", "Mobitopia", "Skynx", - "JimH", "#mobitopia", List.of("tag1", "tag2", "tag3", "TAG4", "Tag5")); - - - @Test - public void testAddDeleteComment() { - int i = 0; - for (; i < 5; i++) { - entryLink.addComment("c" + i, "u" + i); - } - - i = 0; - for (final EntryComment comment : entryLink.getComments()) { - assertThat(comment.getComment()).as("getComment(" + i + ')').isEqualTo("c" + i); - assertThat(comment.getNick()).as("getNick(" + i + ')').isEqualTo("u" + i); - i++; - } - - final SecureRandom r = new SecureRandom(); - while (entryLink.getCommentsCount() > 0) { - entryLink.deleteComment(r.nextInt(entryLink.getCommentsCount())); - } - assertThat(entryLink.hasComments()).as("hasComments()").isFalse(); - - entryLink.addComment("nothing", "nobody"); - entryLink.setComment(0, "something", "somebody"); - assertThat(entryLink.getComment(0).getNick()).as("getNick(somebody)").isEqualTo("somebody"); - assertThat(entryLink.getComment(0).getComment()).as("getComment(something)").isEqualTo("something"); - - } - - @Test - public void testTags() { - final List tags = entryLink.getTags(); - - int i = 0; - for (final SyndCategory tag : tags) { - assertThat(tag.getName()).as("tag.getName(" + i + ')').isEqualTo("tag" + (i + 1)); - i++; - } - - entryLink.setTags("-tag5"); - entryLink.setTags("+mobitopia"); - entryLink.setTags("tag4"); - entryLink.setTags("-mobitopia"); - - assertThat(entryLink.getPinboardTags()).as("getPinboardTags()") - .isEqualTo(entryLink.getNick() + ",tag1,tag2,tag3,tag4,mobitopia"); - } -} diff --git a/src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt new file mode 100644 index 0000000..d92b58f --- /dev/null +++ b/src/test/java/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt @@ -0,0 +1,92 @@ +/* + * EntryLinkTest.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.entries + +import com.rometools.rome.feed.synd.SyndCategory +import org.assertj.core.api.Assertions +import org.testng.annotations.Test +import java.security.SecureRandom + +/** + * The `EntryUtilsTest` class. + * + * @author [Erik C. Thauvin](https://erik.thauvin.net/) + * @created 2019-04-19 + * @since 1.0 + */ +class EntryLinkTest { + private val entryLink = EntryLink( + "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", + listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") + ) + + @Test + fun testAddDeleteComment() { + var i = 0 + while (i < 5) { + entryLink.addComment("c$i", "u$i") + i++ + } + Assertions.assertThat(entryLink.comments.size).`as`("getComments().size() == 5").isEqualTo(i) + i = 0 + for (comment in entryLink.comments) { + Assertions.assertThat(comment.comment).`as`("getComment($i)").isEqualTo("c$i") + Assertions.assertThat(comment.nick).`as`("getNick($i)").isEqualTo("u$i") + i++ + } + val r = SecureRandom() + while (entryLink.comments.size > 0) { + entryLink.deleteComment(r.nextInt(entryLink.comments.size)) + } + Assertions.assertThat(entryLink.hasComments()).`as`("hasComments()").isFalse + entryLink.addComment("nothing", "nobody") + entryLink.setComment(0, "something", "somebody") + Assertions.assertThat(entryLink.getComment(0).nick).`as`("getNick(somebody)").isEqualTo("somebody") + Assertions.assertThat(entryLink.getComment(0).comment).`as`("getComment(something)").isEqualTo("something") + } + + @Test + fun testTags() { + val tags: List = entryLink.tags + for ((i, tag) in tags.withIndex()) { + Assertions.assertThat(tag.name).`as`("tag.getName($i)").isEqualTo("tag" + (i + 1)) + } + Assertions.assertThat(entryLink.tags.size).`as`("getTags().size() is 5").isEqualTo(5) + Assertions.assertThat(entryLink.hasTags()).`as`("hasTags() is true").isTrue + entryLink.setTags("-tag5") + entryLink.setTags("+mobitopia") + entryLink.setTags("tag4") + entryLink.setTags("-mobitopia") + Assertions.assertThat(entryLink.pinboardTags).`as`("getPinboardTags()") + .isEqualTo(entryLink.nick + ",tag1,tag2,tag3,tag4,mobitopia") + } +}