Converter Entry Links manipulation classes to Kotlin.
This commit is contained in:
parent
310ffb91da
commit
7759e278e8
22 changed files with 818 additions and 1213 deletions
|
@ -2,7 +2,9 @@
|
||||||
<SmellBaseline>
|
<SmellBaseline>
|
||||||
<ManuallySuppressedIssues></ManuallySuppressedIssues>
|
<ManuallySuppressedIssues></ManuallySuppressedIssues>
|
||||||
<CurrentIssues>
|
<CurrentIssues>
|
||||||
|
<ID>ComplexMethod:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )</ID>
|
||||||
<ID>ComplexMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
<ID>ComplexMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
||||||
|
<ID>LongMethod:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )</ID>
|
||||||
<ID>LongMethod:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
<ID>LongMethod:StockQuote.kt$StockQuote.Companion$ @JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>LongMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
<ID>LongMethod:Weather2.kt$Weather2.Companion$ @JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message></ID>
|
||||||
<ID>LongParameterList:Comment.kt$Comment$( bot: Mobibot, cmd: String, sender: String, isOp: Boolean, entry: EntryLink, index: Int, commentIndex: Int )</ID>
|
<ID>LongParameterList:Comment.kt$Comment$( bot: Mobibot, cmd: String, sender: String, isOp: Boolean, entry: EntryLink, index: Int, commentIndex: Int )</ID>
|
||||||
|
@ -43,6 +45,9 @@
|
||||||
<ID>NestedBlockDepth:Addons.kt$Addons$ fun add(command: AbstractCommand, props: Properties)</ID>
|
<ID>NestedBlockDepth:Addons.kt$Addons$ fun add(command: AbstractCommand, props: Properties)</ID>
|
||||||
<ID>NestedBlockDepth:Comment.kt$Comment$override fun commandResponse( sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean )</ID>
|
<ID>NestedBlockDepth:Comment.kt$Comment$override fun commandResponse( sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean )</ID>
|
||||||
<ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$ @JvmStatic fun convertCurrency(query: String): Message</ID>
|
<ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$ @JvmStatic fun convertCurrency(query: String): Message</ID>
|
||||||
|
<ID>NestedBlockDepth:EntriesMgr.kt$EntriesMgr.Companion$ @Throws(IOException::class, FeedException::class) fun loadEntries(file: String, channel: String, entries: ArrayList<EntryLink>): String</ID>
|
||||||
|
<ID>NestedBlockDepth:EntriesMgr.kt$EntriesMgr.Companion$ fun saveEntries( bot: Mobibot, entries: List<EntryLink>, history: MutableList<String>, isDayBackup: Boolean )</ID>
|
||||||
|
<ID>NestedBlockDepth:EntryLink.kt$EntryLink$ fun setTags(tags: List<String?>)</ID>
|
||||||
<ID>NestedBlockDepth:FeedReader.kt$FeedReader$ override fun run()</ID>
|
<ID>NestedBlockDepth:FeedReader.kt$FeedReader$ override fun run()</ID>
|
||||||
<ID>NestedBlockDepth:GoogleSearch.kt$GoogleSearch$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)</ID>
|
<ID>NestedBlockDepth:GoogleSearch.kt$GoogleSearch$ override fun run(sender: String, cmd: String, args: String, isPrivate: Boolean)</ID>
|
||||||
<ID>NestedBlockDepth:LinksMgr.kt$LinksMgr$override fun commandResponse( sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean )</ID>
|
<ID>NestedBlockDepth:LinksMgr.kt$LinksMgr$override fun commandResponse( sender: String, login: String, args: String, isOp: Boolean, isPrivate: Boolean )</ID>
|
||||||
|
|
|
@ -44,17 +44,10 @@ import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class to handle posts to pinboard.in.
|
* 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 {
|
object PinboardUtils {
|
||||||
/**
|
/**
|
||||||
* Adds a pin.
|
* Adds a pin.
|
||||||
*
|
|
||||||
* @param poster The PinboardPoster instance.
|
|
||||||
* @param entry The entry to add.
|
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun addPin(poster: PinboardPoster, ircServer: String, entry: EntryLink) = runBlocking {
|
fun addPin(poster: PinboardPoster, ircServer: String, entry: EntryLink) = runBlocking {
|
||||||
|
@ -72,9 +65,6 @@ object PinboardUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a pin.
|
* Deletes a pin.
|
||||||
*
|
|
||||||
* @param poster The PinboardPoster instance.
|
|
||||||
* @param entry The entry to delete.
|
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun deletePin(poster: PinboardPoster, entry: EntryLink) = runBlocking {
|
fun deletePin(poster: PinboardPoster, entry: EntryLink) = runBlocking {
|
||||||
|
@ -86,33 +76,31 @@ object PinboardUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a pin.
|
* Updates a pin.
|
||||||
*
|
|
||||||
* @param poster The PinboardPoster instance.
|
|
||||||
* @param oldUrl The old post URL.
|
|
||||||
* @param entry The entry to add.
|
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun updatePin(poster: PinboardPoster, ircServer: String, oldUrl: String, entry: EntryLink) = runBlocking {
|
fun updatePin(poster: PinboardPoster, ircServer: String, oldUrl: String, entry: EntryLink) = runBlocking {
|
||||||
val update = GlobalScope.async {
|
val update = GlobalScope.async {
|
||||||
if (oldUrl != entry.link) {
|
with(entry) {
|
||||||
poster.deletePin(oldUrl)
|
if (oldUrl != link) {
|
||||||
poster.addPin(
|
poster.deletePin(oldUrl)
|
||||||
entry.link,
|
poster.addPin(
|
||||||
entry.title,
|
link,
|
||||||
postedBy(entry, ircServer),
|
title,
|
||||||
entry.pinboardTags,
|
postedBy(entry, ircServer),
|
||||||
formatDate(entry.date)
|
pinboardTags,
|
||||||
)
|
formatDate(date)
|
||||||
} else {
|
)
|
||||||
poster.addPin(
|
} else {
|
||||||
entry.link,
|
poster.addPin(
|
||||||
entry.title,
|
link,
|
||||||
postedBy(entry, ircServer),
|
title,
|
||||||
entry.pinboardTags,
|
postedBy(entry, ircServer),
|
||||||
formatDate(entry.date),
|
pinboardTags,
|
||||||
replace = true,
|
formatDate(date),
|
||||||
shared = true
|
replace = true,
|
||||||
)
|
shared = true
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update.await()
|
update.await()
|
||||||
|
@ -120,19 +108,13 @@ object PinboardUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format a date to a UTC timestamp.
|
* 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 {
|
private fun formatDate(date: Date): String {
|
||||||
return ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).format(DateTimeFormatter.ISO_INSTANT)
|
return ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).format(DateTimeFormatter.ISO_INSTANT)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns he pinboard.in extended attribution line.
|
* Returns the pinboard.in extended attribution line.
|
||||||
*
|
|
||||||
* @param entry The entry.
|
|
||||||
* @return The extended attribution line.
|
|
||||||
*/
|
*/
|
||||||
private fun postedBy(entry: EntryLink, ircServer: String): String {
|
private fun postedBy(entry: EntryLink, ircServer: String): String {
|
||||||
return "Posted by ${entry.nick} on ${entry.channel} ( $ircServer )"
|
return "Posted by ${entry.nick} on ${entry.channel} ( $ircServer )"
|
||||||
|
|
|
@ -51,14 +51,16 @@ class Cycle(bot: Mobibot) : AbstractCommand(bot) {
|
||||||
isOp: Boolean,
|
isOp: Boolean,
|
||||||
isPrivate: Boolean
|
isPrivate: Boolean
|
||||||
) {
|
) {
|
||||||
if (isOp) {
|
with(bot) {
|
||||||
bot.send("$sender has just asked me to leave. I'll be back!")
|
if (isOp) {
|
||||||
bot.sleep(wait)
|
send("$sender has just asked me to leave. I'll be back!")
|
||||||
bot.partChannel(bot.channel)
|
sleep(wait)
|
||||||
bot.sleep(wait)
|
partChannel(channel)
|
||||||
bot.joinChannel(bot.channel)
|
sleep(wait)
|
||||||
} else {
|
joinChannel(channel)
|
||||||
bot.helpDefault(sender, isOp, isPrivate)
|
} else {
|
||||||
|
helpDefault(sender, isOp, isPrivate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,17 +52,17 @@ class Modules(bot: Mobibot) : AbstractCommand(bot) {
|
||||||
isOp: Boolean,
|
isOp: Boolean,
|
||||||
isPrivate: Boolean
|
isPrivate: Boolean
|
||||||
) {
|
) {
|
||||||
if (isOp) {
|
with(bot) {
|
||||||
with(bot.modulesNames) {
|
if (isOp) {
|
||||||
if (isEmpty()) {
|
if (modulesNames.isEmpty()) {
|
||||||
bot.send(sender, "There are no enabled modules.", isPrivate)
|
send(sender, "There are no enabled modules.", isPrivate)
|
||||||
} else {
|
} else {
|
||||||
bot.send(sender, "The enabled modules are: ", isPrivate)
|
send(sender, "The enabled modules are: ", isPrivate)
|
||||||
bot.sendList(sender, this, 7, isPrivate, false)
|
sendList(sender, modulesNames, 7, isPrivate, false)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
helpDefault(sender, isOp, isPrivate)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
bot.helpDefault(sender, isOp, isPrivate)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Comment(bot: Mobibot) : AbstractCommand(bot) {
|
||||||
if (index < LinksMgr.entriesCount) {
|
if (index < LinksMgr.entriesCount) {
|
||||||
val entry: EntryLink = LinksMgr.getEntry(index)
|
val entry: EntryLink = LinksMgr.getEntry(index)
|
||||||
val commentIndex = cmds[1].toInt() - 1
|
val commentIndex = cmds[1].toInt() - 1
|
||||||
if (commentIndex < entry.commentsCount) {
|
if (commentIndex < entry.comments.size) {
|
||||||
when (val cmd = cmds[2].trim()) {
|
when (val cmd = cmds[2].trim()) {
|
||||||
"" -> showComment(bot, entry, index, commentIndex) // L1.1:
|
"" -> showComment(bot, entry, index, commentIndex) // L1.1:
|
||||||
"-" -> deleteComment(bot, sender, isOp, entry, index, commentIndex) // L11:-
|
"-" -> 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) {
|
if (isOp || sender == entry.getComment(commentIndex).nick) {
|
||||||
entry.deleteComment(commentIndex)
|
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)
|
LinksMgr.saveEntries(bot, false)
|
||||||
} else {
|
} else {
|
||||||
bot.send(sender, "Please ask a channel op to delete this comment for you.", false)
|
bot.send(sender, "Please ask a channel op to delete this comment for you.", false)
|
||||||
|
|
|
@ -40,6 +40,7 @@ import net.thauvin.erik.mobibot.commands.Ignore
|
||||||
import net.thauvin.erik.mobibot.entries.EntriesMgr
|
import net.thauvin.erik.mobibot.entries.EntriesMgr
|
||||||
import net.thauvin.erik.mobibot.entries.EntriesUtils
|
import net.thauvin.erik.mobibot.entries.EntriesUtils
|
||||||
import net.thauvin.erik.mobibot.entries.EntryLink
|
import net.thauvin.erik.mobibot.entries.EntryLink
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import java.io.IOException
|
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, "Please specify a title, by typing:", isPrivate)
|
||||||
bot.send(
|
bot.send(
|
||||||
sender,
|
sender,
|
||||||
Utils.helpIndent(Constants.LINK_CMD + (index + 1) + ":|This is the title"),
|
Utils.helpIndent("${EntriesUtils.buildLinkCmd(index)}:|This is the title"),
|
||||||
isPrivate
|
isPrivate
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ class Posting(bot: Mobibot) : AbstractCommand(bot) {
|
||||||
if (entry.login == login || isOp) {
|
if (entry.login == login || isOp) {
|
||||||
bot.deletePin(index, entry)
|
bot.deletePin(index, entry)
|
||||||
LinksMgr.removeEntry(index)
|
LinksMgr.removeEntry(index)
|
||||||
bot.send("Entry ${Constants.LINK_CMD}${index + 1} removed.")
|
bot.send("Entry ${EntriesUtils.buildLinkCmd(index)} removed.")
|
||||||
LinksMgr.saveEntries(bot, false)
|
LinksMgr.saveEntries(bot, false)
|
||||||
} else {
|
} else {
|
||||||
bot.send(sender, "Please ask a channel op to remove this entry for you.", false)
|
bot.send(sender, "Please ask a channel op to remove this entry for you.", false)
|
||||||
|
|
|
@ -104,7 +104,9 @@ public class Tell extends AbstractCommand {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
final boolean clean() {
|
final boolean clean() {
|
||||||
getBot().getLogger().debug("Cleaning the messages.");
|
if (getBot().getLogger().isDebugEnabled()) {
|
||||||
|
getBot().getLogger().debug("Cleaning the messages.");
|
||||||
|
}
|
||||||
return TellMessagesMgr.clean(messages, maxDays);
|
return TellMessagesMgr.clean(messages, maxDays);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,8 +94,9 @@ final class TellMessagesMgr {
|
||||||
try {
|
try {
|
||||||
try (final ObjectInput input = new ObjectInputStream(
|
try (final ObjectInput input = new ObjectInputStream(
|
||||||
new BufferedInputStream(Files.newInputStream(Paths.get(file))))) {
|
new BufferedInputStream(Files.newInputStream(Paths.get(file))))) {
|
||||||
logger.debug("Loading the messages.");
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Loading the messages.");
|
||||||
|
}
|
||||||
return ((List<TellMessage>) input.readObject());
|
return ((List<TellMessage>) input.readObject());
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException ignore) {
|
} catch (FileNotFoundException ignore) {
|
||||||
|
@ -118,7 +119,9 @@ final class TellMessagesMgr {
|
||||||
try {
|
try {
|
||||||
try (final BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(Paths.get(file)))) {
|
try (final BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(Paths.get(file)))) {
|
||||||
try (final ObjectOutput output = new ObjectOutputStream(bos)) {
|
try (final ObjectOutput output = new ObjectOutputStream(bos)) {
|
||||||
logger.debug("Saving the messages.");
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Saving the messages.");
|
||||||
|
}
|
||||||
output.writeObject(messages);
|
output.writeObject(messages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 <a href="https://erik.thauvin.net" target="_blank">Erik C. Thauvin</a>
|
|
||||||
* @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<String> 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<SyndEntry> 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<EntryLink> 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<SyndEntry> 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("<br/>");
|
|
||||||
|
|
||||||
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<EntryLink> entries,
|
|
||||||
final List<String> 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<SyndEntry> 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 <b>")
|
|
||||||
.append(entry.getNick())
|
|
||||||
.append("</b> on <a href=\"irc://")
|
|
||||||
.append(bot.getIrcServer()).append('/')
|
|
||||||
.append(entry.getChannel())
|
|
||||||
.append("\"><b>")
|
|
||||||
.append(entry.getChannel())
|
|
||||||
.append("</b></a>");
|
|
||||||
|
|
||||||
if (entry.getCommentsCount() > 0) {
|
|
||||||
buff.append(" <br/><br/>");
|
|
||||||
|
|
||||||
final EntryComment[] comments = entry.getComments();
|
|
||||||
|
|
||||||
for (int j = 0; j < comments.length; j++) {
|
|
||||||
comment = comments[j];
|
|
||||||
|
|
||||||
if (j > 0) {
|
|
||||||
buff.append(" <br/>");
|
|
||||||
}
|
|
||||||
|
|
||||||
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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
261
src/main/java/net/thauvin/erik/mobibot/entries/EntriesMgr.kt
Normal file
261
src/main/java/net/thauvin/erik/mobibot/entries/EntriesMgr.kt
Normal file
|
@ -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<String>) {
|
||||||
|
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<EntryLink>): 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<String>
|
||||||
|
for (comment in description.value.split("<br/>")) {
|
||||||
|
split = comment.split(": ".toRegex(), 2)
|
||||||
|
if (split.size == 2) {
|
||||||
|
entry.addComment(comment = split[1].trim(), nick = split[0].trim())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entries.add(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return today
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the entries.
|
||||||
|
*/
|
||||||
|
fun saveEntries(
|
||||||
|
bot: Mobibot,
|
||||||
|
entries: List<EntryLink>,
|
||||||
|
history: MutableList<String>,
|
||||||
|
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<SyndEntry> = 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 <b>")
|
||||||
|
.append(nick)
|
||||||
|
.append("</b> on <a href=\"irc://")
|
||||||
|
.append(bot.ircServer).append('/')
|
||||||
|
.append(channel)
|
||||||
|
.append("\"><b>")
|
||||||
|
.append(channel)
|
||||||
|
.append("</b></a>")
|
||||||
|
if (comments.size > 0) {
|
||||||
|
buff.append(" <br/><br/>")
|
||||||
|
val comments = comments
|
||||||
|
for (j in comments.indices) {
|
||||||
|
comment = comments[j]
|
||||||
|
if (j > 0) {
|
||||||
|
buff.append(" <br/>")
|
||||||
|
}
|
||||||
|
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.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <code>Utils</code> class.
|
|
||||||
*
|
|
||||||
* @author <a href="https://erik.thauvin.net/" target="_blank">Erik C. Thauvin</a>
|
|
||||||
* @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(",", ", "));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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(",", ", ")
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <a href="https://erik.thauvin.net" target="_blank">Erik C. Thauvin</a>
|
|
||||||
* @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 + '\''
|
|
||||||
+ '}';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <a href="https://erik.thauvin.net" target="_blank">Erik C. Thauvin</a>
|
|
||||||
* @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<EntryComment> comments = new CopyOnWriteArrayList<>();
|
|
||||||
|
|
||||||
// Tags/categories
|
|
||||||
private final List<SyndCategory> 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<String> 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<SyndCategory> 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<SyndCategory> 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<String> 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 + '\''
|
|
||||||
+ '}';
|
|
||||||
}
|
|
||||||
}
|
|
223
src/main/java/net/thauvin/erik/mobibot/entries/EntryLink.kt
Normal file
223
src/main/java/net/thauvin/erik/mobibot/entries/EntryLink.kt
Normal file
|
@ -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<EntryComment> = CopyOnWriteArrayList()
|
||||||
|
|
||||||
|
// Tags/categories
|
||||||
|
val tags: MutableList<SyndCategory> = 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<String?>
|
||||||
|
) {
|
||||||
|
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<SyndCategory>
|
||||||
|
) {
|
||||||
|
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<String?>) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ import net.thauvin.erik.mobibot.TwitterTimer
|
||||||
import net.thauvin.erik.mobibot.Utils
|
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.entriesCount
|
||||||
import net.thauvin.erik.mobibot.commands.links.LinksMgr.Companion.getEntry
|
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.Message
|
||||||
import net.thauvin.erik.mobibot.msg.NoticeMessage
|
import net.thauvin.erik.mobibot.msg.NoticeMessage
|
||||||
import org.apache.commons.lang3.StringUtils
|
import org.apache.commons.lang3.StringUtils
|
||||||
|
@ -76,7 +77,7 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
override val isValidProperties: Boolean
|
override val isValidProperties: Boolean
|
||||||
get() {
|
get() {
|
||||||
for (s in propertyKeys) {
|
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
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +131,7 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
Thread {
|
Thread {
|
||||||
try {
|
try {
|
||||||
if (logger.isDebugEnabled) {
|
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)
|
post(message = msg, isDm = false)
|
||||||
} catch (e: ModuleException) {
|
} catch (e: ModuleException) {
|
||||||
|
@ -146,7 +147,7 @@ class Twitter(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
if (isAutoPost) {
|
if (isAutoPost) {
|
||||||
addEntry(index)
|
addEntry(index)
|
||||||
if (bot.logger.isDebugEnabled) {
|
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)
|
bot.timer.schedule(TwitterTimer(bot, index), Constants.TIMER_DELAY * 60L * 1000L)
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,8 +138,8 @@ class Weather2(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
}
|
}
|
||||||
if (cwd.hasWindData()) {
|
if (cwd.hasWindData()) {
|
||||||
with(cwd.windData) {
|
with(cwd.windData) {
|
||||||
if (this != null && hasSpeed()) {
|
if (this != null && hasSpeed() && speed != null) {
|
||||||
messages.add(NoticeMessage("Wind: ${wind(speed)}"))
|
messages.add(NoticeMessage("Wind: ${wind(speed!!)}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,9 @@ class Weather2(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
val list = cwd.weatherList
|
val list = cwd.weatherList
|
||||||
if (list != null) {
|
if (list != null) {
|
||||||
for (w in list) {
|
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()))
|
messages.add(NoticeMessage(condition.toString()))
|
||||||
}
|
}
|
||||||
|
@ -182,9 +184,9 @@ class Weather2(bot: Mobibot) : ThreadedModule(bot) {
|
||||||
return messages
|
return messages
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wind(w: Double?): String {
|
private fun wind(w: Double): String {
|
||||||
val kmh = w!! * 1.60934
|
val kmh = w * 1.60934
|
||||||
return "${Math.round(w)} mph, ${kmh.roundToInt()} km/h"
|
return "${w.roundToInt()} mph, ${kmh.roundToInt()} km/h"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* LocalProperties.java
|
* LocalProperties.kt
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net)
|
* Copyright (c) 2004-2020, Erik C. Thauvin (erik@thauvin.net)
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -29,54 +29,47 @@
|
||||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
* 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.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
package net.thauvin.erik.mobibot
|
||||||
|
|
||||||
package net.thauvin.erik.mobibot;
|
import org.testng.annotations.BeforeSuite
|
||||||
|
import java.io.IOException
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import java.nio.file.Files
|
||||||
import org.testng.annotations.BeforeSuite;
|
import java.nio.file.Paths
|
||||||
|
import java.util.*
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <code>properties</code> class.
|
* Access to `local.properties`.
|
||||||
*
|
|
||||||
* @author <a href="https://erik.thauvin.net/" target="_blank">Erik C. Thauvin</a>
|
|
||||||
* @created 2019-04-08
|
|
||||||
* @since 1.0
|
|
||||||
*/
|
*/
|
||||||
public class LocalProperties {
|
open 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('-', '_'));
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeSuite(alwaysRun = true)
|
@BeforeSuite(alwaysRun = true)
|
||||||
public void loadProperties() {
|
fun loadProperties() {
|
||||||
final Path localPath = Paths.get("local.properties");
|
val localPath = Paths.get("local.properties")
|
||||||
if (Files.exists(localPath)) {
|
if (Files.exists(localPath)) {
|
||||||
try (final InputStream stream = Files.newInputStream(localPath)) {
|
try {
|
||||||
localProps.load(stream);
|
Files.newInputStream(localPath).use { stream -> localProps.load(stream) }
|
||||||
} catch (IOException ignore) {
|
} catch (ignore: IOException) {
|
||||||
// Do nothing
|
// 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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 <code>EntryUtilsTest</code> class.
|
|
||||||
*
|
|
||||||
* @author <a href="https://erik.thauvin.net/" target="_blank">Erik C. Thauvin</a>
|
|
||||||
* @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<SyndCategory> 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");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<SyndCategory> = 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")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue