Skip to content

Commit 835a951

Browse files
nateweiszchristolisbowbahdoeTaz03
authored
Java RSS Feed (#1037)
* wip: initial commit * style(spotlessApply): run uncalled task * fix: register routine in features list * feat: update config.json.template * wip(rss-config): change config design * feat: make targetChannelPattern into a Map * refactor: don't hardcode number * feat: improve constructEmbedMessage * feat: improve the description constructing * feat: increase MAX_CONTENTS to 300 * wip: changes * feat(rss-feed): convert polling interval to be configurable * feat: improve date parsing Co-authored-by: Ethan McCue <5004262+bowbahdoe@users.noreply.github.com> * feat: update config.json.template * feat: improve date handling and add embed timestamp * fix: malformed `config.json.template` * fix: now correctly finds the latest date * feat: improve date handling and add embed timestamp * fix: now correctly finds the latest date * feat: you can now optionally declare a specific channel for a feed to go to * finished javadoc todos * improved embed * feat(rss-routine): working version - Added JavaDocs on most parts - Simplified the code and cleaned up unused stuff * feat(rss-routine): increase MAX_CONTENTS to 1000 * refactor(rss-routine): rename to RSSHandlerRoutine While the original idea was to add a Java news and changes RSS feed, this was expanded to all types of RSS feeds, so a more appropriate name makes things more clear. * docs(rss-routine): add JavaDocs for constructor and class * feat: add @NotNull annotation * Update RSSHandlerRoutine.java * fix: reverse feed so it posts in correct order * refactor: use variable types instead of var * feat: use fetchAny() instead of fetch() * fix(rss-handler): remove redundant empty check Co-authored-by: Ethan McCue <5004262+bowbahdoe@users.noreply.github.com> * refactor(rss-handler): remove AtomicReference usage Co-authored-by: Ethan McCue <5004262+bowbahdoe@users.noreply.github.com> * resolve a couple issues * refactor(rss): switch to using a record for the config * feat: rename to fallbackChannelPattern * refactor: remove unnecessary throws exception in method signature * docs: add a few missing parameters and fix typos * refactor: reduce try-catch scope and added clarifying comment * perf: use Stream instead of StringBuilder * refactor: put fallback case into an else statement * refactor: switch to Map#containsKey() for targetChannelPatterns * feat: modularize sendRss() method and improve variable names This also changes the functionality of how new RSS feeds get dealt with for the first time. Before this commit, all items would get posted as embeds on Discord, and as a result, that would bombard the target channel with RSS posts once the routine executes. This commit changes this behavior by assuming that all RSS posts have been posted and it should only consider posting posts newer than the registered date. * refactor: remove star import * fix: add Objects#requireNonNull() on rssConfig * changes * feat: improvements from code reviews Co-authored-by: Nathan Weisz <151496498+nateweisz@users.noreply.github.com> * feat: add DateTimeParseException in signature * refactor: use .orElseThrow() instead of .get() * fixed missing coma after rss configuration Co-authored-by: Tanish <tanishazad03@gmail.com> * fix(rss): feeds support multiple channels fix(rss): polling interval is now clear on unit of time fix(rss): posting messages now uses forEachOrdered * Optional<List<TextChannel>> -> List<TextChannel> * extract item post predicate to seperate function * various changes from null to optional --------- Co-authored-by: christolis <work@chris-sdogkos.com> Co-authored-by: Ethan McCue <5004262+bowbahdoe@users.noreply.github.com> Co-authored-by: Tanish <tanishazad03@gmail.com>
1 parent 7490beb commit 835a951

File tree

9 files changed

+524
-2
lines changed

9 files changed

+524
-2
lines changed

application/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ dependencies {
7777

7878
implementation 'org.kohsuke:github-api:1.321'
7979

80+
implementation 'org.apache.commons:commons-text:1.11.0'
81+
implementation 'com.apptasticsoftware:rssreader:3.6.0'
82+
8083
testImplementation 'org.mockito:mockito-core:5.11.0'
8184
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'
8285
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.0'

application/config.json.template

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,17 @@
103103
"special": [
104104
]
105105
},
106-
"memberCountCategoryPattern": "Info",
107-
"selectRolesChannelPattern": "select-your-roles"
106+
"selectRolesChannelPattern": "select-your-roles",
107+
"rssConfig": {
108+
"feeds": [
109+
{
110+
"url": "<rss_feed_url>",
111+
"targetChannelPattern": "<target_channel_pattern>",
112+
"dateFormatterPattern": "EEE, dd MMM yyyy HH:mm:ss zzz"
113+
}
114+
],
115+
"fallbackChannelPattern": "<fallback_channel_pattern>",
116+
"pollIntervalInMinutes": 10
117+
},
118+
"memberCountCategoryPattern": "Info"
108119
}

application/src/main/java/org/togetherjava/tjbot/config/Config.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.List;
1212
import java.util.Objects;
1313

14+
1415
/**
1516
* Configuration of the application. Create instances using {@link #load(Path)}.
1617
*/
@@ -42,6 +43,7 @@ public final class Config {
4243
private final String sourceCodeBaseUrl;
4344
private final JShellConfig jshell;
4445
private final FeatureBlacklistConfig featureBlacklistConfig;
46+
private final RSSFeedsConfig rssFeedsConfig;
4547
private final String selectRolesChannelPattern;
4648
private final String memberCountCategoryPattern;
4749

@@ -90,6 +92,7 @@ private Config(@JsonProperty(value = "token", required = true) String token,
9092
required = true) String memberCountCategoryPattern,
9193
@JsonProperty(value = "featureBlacklist",
9294
required = true) FeatureBlacklistConfig featureBlacklistConfig,
95+
@JsonProperty(value = "rssConfig", required = true) RSSFeedsConfig rssFeedsConfig,
9396
@JsonProperty(value = "selectRolesChannelPattern",
9497
required = true) String selectRolesChannelPattern) {
9598
this.token = Objects.requireNonNull(token);
@@ -122,6 +125,7 @@ private Config(@JsonProperty(value = "token", required = true) String token,
122125
this.sourceCodeBaseUrl = Objects.requireNonNull(sourceCodeBaseUrl);
123126
this.jshell = Objects.requireNonNull(jshell);
124127
this.featureBlacklistConfig = Objects.requireNonNull(featureBlacklistConfig);
128+
this.rssFeedsConfig = Objects.requireNonNull(rssFeedsConfig);
125129
this.selectRolesChannelPattern = Objects.requireNonNull(selectRolesChannelPattern);
126130
}
127131

@@ -405,4 +409,13 @@ public String getSelectRolesChannelPattern() {
405409
public String getMemberCountCategoryPattern() {
406410
return memberCountCategoryPattern;
407411
}
412+
413+
/**
414+
* Gets the RSS feeds configuration.
415+
*
416+
* @return the RSS feeds configuration
417+
*/
418+
public RSSFeedsConfig getRSSFeedsConfig() {
419+
return rssFeedsConfig;
420+
}
408421
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.togetherjava.tjbot.config;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
5+
import javax.annotation.Nullable;
6+
7+
import java.util.Objects;
8+
9+
/**
10+
* Represents an RSS feed configuration.
11+
*/
12+
public record RSSFeed(@JsonProperty(value = "url", required = true) String url,
13+
@JsonProperty(value = "targetChannelPattern") @Nullable String targetChannelPattern,
14+
@JsonProperty(value = "dateFormatterPattern",
15+
required = true) String dateFormatterPattern) {
16+
17+
/**
18+
* Constructs an RSSFeed object.
19+
*
20+
* @param url the URL of the RSS feed
21+
* @param targetChannelPattern the target channel pattern
22+
* @param dateFormatterPattern the date formatter pattern
23+
* @throws NullPointerException if any of the parameters are null
24+
*/
25+
public RSSFeed {
26+
Objects.requireNonNull(url);
27+
Objects.requireNonNull(targetChannelPattern);
28+
Objects.requireNonNull(dateFormatterPattern);
29+
}
30+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.togetherjava.tjbot.config;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
5+
import java.util.List;
6+
import java.util.Objects;
7+
8+
/**
9+
* Represents the configuration for an RSS feed, which includes the list of feeds to subscribe to, a
10+
* pattern for identifying Java news channels, and the interval (in minutes) for polling the feeds.
11+
*
12+
* @param feeds The list of RSS feeds to subscribe to.
13+
* @param fallbackChannelPattern The pattern used to identify the fallback text channel to use.
14+
* @param pollIntervalInMinutes The interval (in minutes) for polling the RSS feeds for updates.
15+
*/
16+
public record RSSFeedsConfig(@JsonProperty(value = "feeds", required = true) List<RSSFeed> feeds,
17+
@JsonProperty(value = "fallbackChannelPattern",
18+
required = true) String fallbackChannelPattern,
19+
@JsonProperty(value = "pollIntervalInMinutes", required = true) int pollIntervalInMinutes) {
20+
21+
/**
22+
* Constructs a new {@link RSSFeedsConfig}.
23+
*
24+
* @param feeds The list of RSS feeds to subscribe to.
25+
* @param fallbackChannelPattern The pattern used to identify the fallback text channel to use.
26+
* @param pollIntervalInMinutes The interval (in minutes) for polling the RSS feeds for updates.
27+
* @throws NullPointerException if any of the parameters (feeds or fallbackChannelPattern) are
28+
* null
29+
*/
30+
public RSSFeedsConfig {
31+
Objects.requireNonNull(feeds);
32+
Objects.requireNonNull(fallbackChannelPattern);
33+
}
34+
}

application/src/main/java/org/togetherjava/tjbot/features/Features.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.togetherjava.tjbot.features.github.GitHubCommand;
2525
import org.togetherjava.tjbot.features.github.GitHubReference;
2626
import org.togetherjava.tjbot.features.help.*;
27+
import org.togetherjava.tjbot.features.javamail.RSSHandlerRoutine;
2728
import org.togetherjava.tjbot.features.jshell.JShellCommand;
2829
import org.togetherjava.tjbot.features.jshell.JShellEval;
2930
import org.togetherjava.tjbot.features.mathcommands.TeXCommand;
@@ -109,6 +110,7 @@ public static Collection<Feature> createFeatures(JDA jda, Database database, Con
109110
features.add(new HelpThreadAutoArchiver(helpSystemHelper));
110111
features.add(new LeftoverBookmarksCleanupRoutine(bookmarksSystem));
111112
features.add(new MemberCountDisplayRoutine(config));
113+
features.add(new RSSHandlerRoutine(config, database));
112114

113115
// Message receivers
114116
features.add(new TopHelpersMessageListener(database, config));

0 commit comments

Comments
 (0)