From 04a50e6aaf2ca436b42387e423a1c414ecf6cce6 Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Sun, 16 Feb 2020 19:08:38 +0100 Subject: Bookmarks: Add Atom feed. Change-Id: I902473b6bffa10afa0cb2295d365d50335de9021 --- .../mulkcms2/benki/bookmarks/BookmarkResource.java | 135 +++++++++++++++++---- .../java/eu/mulk/mulkcms2/benki/users/User.java | 6 + src/main/resources/application.properties | 2 + .../templates/benki/bookmarks/bookmarkList.html | 4 +- 4 files changed, 124 insertions(+), 23 deletions(-) (limited to 'src/main') diff --git a/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java b/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java index 00e2824..3219f57 100644 --- a/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java +++ b/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java @@ -1,10 +1,19 @@ package eu.mulk.mulkcms2.benki.bookmarks; +import static javax.ws.rs.core.MediaType.APPLICATION_ATOM_XML; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static javax.ws.rs.core.MediaType.TEXT_HTML; +import com.rometools.rome.feed.atom.Content; +import com.rometools.rome.feed.atom.Entry; +import com.rometools.rome.feed.atom.Feed; +import com.rometools.rome.feed.atom.Link; +import com.rometools.rome.feed.synd.SyndPersonImpl; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.WireFeedOutput; import eu.mulk.mulkcms2.benki.accesscontrol.Role; import eu.mulk.mulkcms2.benki.users.User; +import io.quarkus.hibernate.orm.panache.PanacheQuery; import io.quarkus.panache.common.Sort; import io.quarkus.qute.Template; import io.quarkus.qute.TemplateExtension; @@ -15,14 +24,18 @@ import io.quarkus.security.identity.SecurityIdentity; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.time.Instant; import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; import java.time.temporal.TemporalAccessor; +import java.util.Comparator; +import java.util.Date; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.CheckForNull; -import javax.annotation.Nullable; import javax.inject.Inject; import javax.json.JsonObject; import javax.json.spi.JsonProvider; @@ -37,7 +50,10 @@ import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import org.eclipse.microprofile.config.inject.ConfigProperty; import org.jboss.logging.Logger; import org.jsoup.Jsoup; @@ -63,30 +79,87 @@ public class BookmarkResource { @Inject SecurityIdentity identity; + @Context UriInfo uri; + + @Inject + @ConfigProperty(name = "mulkcms.tag-base") + String tagBase; + @GET @Produces(TEXT_HTML) public TemplateInstance getIndex() { - List bookmarks; - if (identity.isAnonymous()) { - Role world = Role.find("from Role r join r.tags tag where tag = 'world'").singleResult(); - bookmarks = - Bookmark.find( - "select bm from Bookmark bm join bm.targets target left join fetch bm.owner where target = ?1", - Sort.by("date").descending(), - world) - .list(); - } else { - var userName = identity.getPrincipal().getName(); - User user = - User.find("from BenkiUser u join u.nicknames n where ?1 = n", userName).singleResult(); - bookmarks = - Bookmark.find( - "select bm from BenkiUser u inner join u.visibleBookmarks bm left join fetch bm.owner where u.id = ?1", - Sort.by("date").descending(), - user.id) - .list(); - } - return bookmarkList.data("bookmarks", bookmarks).data("authenticated", !identity.isAnonymous()); + var bookmarkQuery = bookmarkQuery(); + return bookmarkList + .data("bookmarks", bookmarkQuery.list()) + .data("authenticated", !identity.isAnonymous()); + } + + @GET + @Path("feed") + @Produces(APPLICATION_ATOM_XML) + public String getFeed() throws FeedException { + var bookmarks = bookmarkQuery().list(); + var feed = new Feed("atom_1.0"); + + feed.setTitle("Book Marx"); + feed.setId( + String.format( + "tag:%s,2019:marx:%s", + tagBase, identity.isAnonymous() ? "world" : identity.getPrincipal().getName())); + feed.setUpdated( + Date.from( + bookmarks.stream() + .map(x -> x.date) + .max(Comparator.comparing(x -> x)) + .orElse(OffsetDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC)) + .toInstant())); + + var selfLink = new Link(); + selfLink.setHref(uri.getRequestUri().toString()); + selfLink.setRel("self"); + feed.setOtherLinks(List.of(selfLink)); + + var htmlAltLink = new Link(); + htmlAltLink.setHref(uri.resolve(URI.create("/bookmarks")).toString()); + htmlAltLink.setRel("alternate"); + htmlAltLink.setType("text/html"); + feed.setAlternateLinks(List.of(htmlAltLink)); + + feed.setEntries( + bookmarks.stream() + .map( + bookmark -> { + var entry = new Entry(); + + entry.setId(String.format("tag:%s,2012:/marx/%d", tagBase, bookmark.id)); + entry.setPublished(Date.from(bookmark.date.toInstant())); + entry.setUpdated(Date.from(bookmark.date.toInstant())); + + var author = new SyndPersonImpl(); + author.setName(bookmark.owner.getFirstAndLastName()); + entry.setAuthors(List.of(author)); + + var title = new Content(); + title.setType("text"); + title.setValue(bookmark.title); + entry.setTitleEx(title); + + var summary = new Content(); + summary.setType("html"); + summary.setValue(bookmark.getDescriptionHtml()); + entry.setSummary(summary); + + var link = new Link(); + link.setHref(bookmark.uri); + link.setRel("alternate"); + entry.setAlternateLinks(List.of(link)); + + return entry; + }) + .collect(Collectors.toUnmodifiableList())); + + var wireFeedOutput = new WireFeedOutput(); + return wireFeedOutput.outputString(feed); } @GET @@ -155,4 +228,22 @@ public class BookmarkResource { static String htmlDateTime(TemporalAccessor x) { return htmlDateFormatter.format(x); } + + private PanacheQuery bookmarkQuery() { + if (identity.isAnonymous()) { + Role world = Role.find("from Role r join r.tags tag where tag = 'world'").singleResult(); + return Bookmark.find( + "select bm from Bookmark bm join bm.targets target left join fetch bm.owner where target = ?1", + Sort.by("date").descending(), + world); + } else { + var userName = identity.getPrincipal().getName(); + User user = + User.find("from BenkiUser u join u.nicknames n where ?1 = n", userName).singleResult(); + return Bookmark.find( + "select bm from BenkiUser u inner join u.visibleBookmarks bm left join fetch bm.owner where u.id = ?1", + Sort.by("date").descending(), + user.id); + } + } } diff --git a/src/main/java/eu/mulk/mulkcms2/benki/users/User.java b/src/main/java/eu/mulk/mulkcms2/benki/users/User.java index 1a0dae6..71f6c43 100644 --- a/src/main/java/eu/mulk/mulkcms2/benki/users/User.java +++ b/src/main/java/eu/mulk/mulkcms2/benki/users/User.java @@ -23,6 +23,7 @@ import javax.persistence.ManyToMany; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table; +import javax.persistence.Transient; @Entity(name = "BenkiUser") @Table(name = "users", schema = "benki") @@ -131,4 +132,9 @@ public class User extends PanacheEntityBase { joinColumns = @JoinColumn(name = "user"), inverseJoinColumns = @JoinColumn(name = "role")) public Set effectiveRoles; + + @Transient + public String getFirstAndLastName() { + return String.format("%s %s", firstName, lastName); + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 886db80..4237503 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -7,6 +7,8 @@ quarkus.log.level = INFO #quarkus.log.category."io.vertx.ext.auth.oauth2".level = FINEST #quarkus.log.category."io.vertx.ext.jwt".level = FINEST +mulkcms.tag-base = hub.benkard.de + quarkus.datasource.driver = org.postgresql.Driver quarkus.datasource.max-size = 8 quarkus.datasource.min-size = 0 diff --git a/src/main/resources/templates/benki/bookmarks/bookmarkList.html b/src/main/resources/templates/benki/bookmarks/bookmarkList.html index a53abdd..7d23d45 100644 --- a/src/main/resources/templates/benki/bookmarks/bookmarkList.html +++ b/src/main/resources/templates/benki/bookmarks/bookmarkList.html @@ -7,7 +7,9 @@ {#siteSection}Bookmarks{/siteSection} {#bookmarksClass}this-page{/bookmarksClass} -{#head}{/head} +{#head} + +{/head} {#body} -- cgit v1.2.3