From e80c2d890f96dd5e599a5a82d612c8b1ecff9ab9 Mon Sep 17 00:00:00 2001 From: Marc Wrobel Date: Wed, 10 May 2023 22:52:40 +0200 Subject: [PATCH] =?UTF-8?q?Adapt=20to=20the=20new=20conferences=20=C3=A0ll?= =?UTF-8?q?-events.json=20format=20(closes=20#139)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Declare new fields in conferences JSON parsing. - Fix handling of conferences JSON dates: - the epoch timestamp is now expressed in milliseconds, - end date is now optional. --- CHANGELOG.md | 2 + .../bot/conferences/Conference.java | 42 ++++++++++++------- .../bot/conferences/ConferenceTest.java | 6 +-- .../bot/conferences/ConferencesTest.java | 12 +++--- 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7f689c..b5e4066 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Fixed +- Adapt to the new conferences `àll-events.json` format (#139). + ### Deprecated ### Removed diff --git a/src/main/java/com/lescastcodeurs/bot/conferences/Conference.java b/src/main/java/com/lescastcodeurs/bot/conferences/Conference.java index c8b321a..d487f52 100644 --- a/src/main/java/com/lescastcodeurs/bot/conferences/Conference.java +++ b/src/main/java/com/lescastcodeurs/bot/conferences/Conference.java @@ -1,23 +1,26 @@ package com.lescastcodeurs.bot.conferences; -import static com.lescastcodeurs.bot.internal.StringUtils.isNotBlank; +import static com.lescastcodeurs.bot.internal.StringUtils.isBlank; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.lescastcodeurs.bot.MarkdownSerializable; import java.time.Instant; import java.time.LocalDate; -import java.time.LocalTime; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Locale; +// Those fields are not used (but we still want this object to exactly reflect the expected JSON +// structure). +@JsonIgnoreProperties({"cfp", "status"}) @SuppressWarnings("java:S6218") // don't care public record Conference(String name, String hyperlink, String location, long[] date, String misc) implements MarkdownSerializable { - public static final long MIN_TIMESTAMP = Instant.MIN.getEpochSecond(); - public static final long MAX_TIMESTAMP = Instant.MAX.getEpochSecond(); + public static final long MIN_TIMESTAMP = Instant.EPOCH.toEpochMilli(); + public static final long MAX_TIMESTAMP = Long.MAX_VALUE - 1; private static final DateTimeFormatter FORMAT = DateTimeFormatter.ofPattern("d MMMM uuuu"); public boolean isValidCandidate(List selectionCriteria, LocalDate date) { @@ -28,22 +31,29 @@ public boolean isValidCandidate(List selectionCriteria, LocalDate date) } public boolean hasValidData() { - return date != null - && date.length == 2 - && date[0] >= MIN_TIMESTAMP - && date[1] <= MAX_TIMESTAMP - && date[0] <= date[1] - && isNotBlank(name) - && isNotBlank(hyperlink) - && isNotBlank(location); + if (date == null || isBlank(name) || isBlank(hyperlink) || isBlank(location)) { + return false; + } + + if (date.length == 2) { + return date[0] >= MIN_TIMESTAMP && date[1] <= MAX_TIMESTAMP && date[0] <= date[1]; + } else if (date.length == 1) { + return date[0] >= MIN_TIMESTAMP && date[0] <= MAX_TIMESTAMP; + } + + return false; } public boolean isOnOrAfter(LocalDate d) { - long end = date[1]; - long now = d.toEpochSecond(LocalTime.MIDNIGHT, ZoneOffset.UTC); + long end = endDate(); + long now = d.atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli(); return end >= now; } + private long endDate() { + return date.length == 1 ? date[0] : date[1]; + } + public boolean matchesAnyOf(List criteria) { for (String criterion : criteria) { if (name.contains(criterion) || location.contains(criterion)) { @@ -57,7 +67,7 @@ public boolean matchesAnyOf(List criteria) { @Override public String markdown(Locale locale) { LocalDate start = timestampToDate(date[0]); - LocalDate end = timestampToDate(date[1]); + LocalDate end = timestampToDate(endDate()); DateTimeFormatter formatter = FORMAT.withLocale(locale); String date; @@ -73,7 +83,7 @@ public String markdown(Locale locale) { } private static LocalDate timestampToDate(long timestamp) { - Instant instant = Instant.ofEpochSecond(timestamp); + Instant instant = Instant.ofEpochMilli(timestamp); ZonedDateTime dateTime = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC); return dateTime.toLocalDate(); } diff --git a/src/test/java/com/lescastcodeurs/bot/conferences/ConferenceTest.java b/src/test/java/com/lescastcodeurs/bot/conferences/ConferenceTest.java index f3c133c..a14b5ed 100644 --- a/src/test/java/com/lescastcodeurs/bot/conferences/ConferenceTest.java +++ b/src/test/java/com/lescastcodeurs/bot/conferences/ConferenceTest.java @@ -2,7 +2,6 @@ import static com.lescastcodeurs.bot.conferences.Conference.MAX_TIMESTAMP; import static com.lescastcodeurs.bot.conferences.Conference.MIN_TIMESTAMP; -import static java.time.LocalTime.MIDNIGHT; import static java.time.ZoneOffset.UTC; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -24,9 +23,9 @@ class ConferenceTest { private static final String MISC = "CFP ends on 2023-01-01"; private static final LocalDate START = LocalDate.of(2023, 4, 12); - private static final long START_STAMP = START.toEpochSecond(MIDNIGHT, UTC); + private static final long START_STAMP = START.atStartOfDay().toInstant(UTC).toEpochMilli(); private static final LocalDate END = LocalDate.of(2023, 4, 14); - private static final long END_STAMP = END.toEpochSecond(MIDNIGHT, UTC); + private static final long END_STAMP = END.atStartOfDay().toInstant(UTC).toEpochMilli(); private static final long[] DATES = new long[] {START_STAMP, END_STAMP}; @Test @@ -53,7 +52,6 @@ void datesMustBeValid(long[] invalidDates) { private static Stream invalidDates() { return Stream.of( of((Object) new long[] {}), - of((Object) new long[] {MIN_TIMESTAMP}), of((Object) new long[] {MIN_TIMESTAMP, MAX_TIMESTAMP, MAX_TIMESTAMP}), // Disabled: https://github.com/scraly/developers-conferences-agenda/issues/319 of((Object) new long[] {MAX_TIMESTAMP, MIN_TIMESTAMP}), diff --git a/src/test/java/com/lescastcodeurs/bot/conferences/ConferencesTest.java b/src/test/java/com/lescastcodeurs/bot/conferences/ConferencesTest.java index a313139..133cbdd 100644 --- a/src/test/java/com/lescastcodeurs/bot/conferences/ConferencesTest.java +++ b/src/test/java/com/lescastcodeurs/bot/conferences/ConferencesTest.java @@ -37,8 +37,8 @@ void withCorrectJson() { { "name": "Devoxx France", "date": [ - 2147483647, - 2147483647 + 9223372036854775007, + 9223372036854775007 ], "hyperlink": "https://devoxx.fr/", "location": "France (Paris)", @@ -47,8 +47,8 @@ void withCorrectJson() { { "name": "Monitorama", "date": [ - 2147483647, - 2147483647 + 9223372036854775007, + 9223372036854775007 ], "hyperlink": "http://monitorama.com/", "location": "USA", @@ -57,8 +57,8 @@ void withCorrectJson() { { "name": "Best Of Web", "date": [ - -2147483648, - -2147483648 + 0, + 0 ], "hyperlink": "http://bestofweb.paris/", "location": "France",