Lazychat: Add paging.

Change-Id: I1db0b0733397d5e7a77b925ba185a39a72041f3e
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 2272db2..1f57c74 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java
@@ -105,7 +105,7 @@
     var q = Bookmark.findViewable(session, identity, null, cursor, maxResults);
 
     return bookmarkList
-        .data("bookmarks", q.posts)
+        .data("posts", q.posts)
         .data("feedUri", "/bookmarks/feed")
         .data("authenticated", !identity.isAnonymous())
         .data("hasPreviousPage", q.prevCursor != null)
@@ -130,7 +130,7 @@
     var q = Bookmark.findViewable(session, identity, owner, cursor, maxResults);
 
     return bookmarkList
-        .data("bookmarks", q.posts)
+        .data("posts", q.posts)
         .data("feedUri", String.format("/bookmarks/~%s/feed", ownerName))
         .data("authenticated", !identity.isAnonymous())
         .data("hasPreviousPage", q.prevCursor != null)
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/lazychat/LazychatResource.java b/src/main/java/eu/mulk/mulkcms2/benki/lazychat/LazychatResource.java
index fb46217..4284d96 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/lazychat/LazychatResource.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/lazychat/LazychatResource.java
@@ -2,10 +2,7 @@
 
 import static javax.ws.rs.core.MediaType.TEXT_HTML;
 
-import eu.mulk.mulkcms2.benki.accesscontrol.Role;
-import eu.mulk.mulkcms2.benki.bookmarks.Bookmark;
 import eu.mulk.mulkcms2.benki.users.User;
-import io.quarkus.panache.common.Sort;
 import io.quarkus.qute.Template;
 import io.quarkus.qute.TemplateExtension;
 import io.quarkus.qute.TemplateInstance;
@@ -14,12 +11,18 @@
 import java.time.format.DateTimeFormatter;
 import java.time.format.FormatStyle;
 import java.time.temporal.TemporalAccessor;
-import java.util.List;
+import javax.annotation.CheckForNull;
 import javax.inject.Inject;
 import javax.json.spi.JsonProvider;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.hibernate.Session;
 import org.jboss.logging.Logger;
 
 @Path("/lazychat")
@@ -34,36 +37,60 @@
 
   private static JsonProvider jsonProvider = JsonProvider.provider();
 
+  @ConfigProperty(name = "mulkcms.lazychat.default-max-results")
+  int defaultMaxResults;
+
   @ResourcePath("benki/lazychat/lazychatList.html")
   @Inject
   Template lazychatList;
 
   @Inject SecurityIdentity identity;
 
+  @PersistenceContext EntityManager entityManager;
+
   @GET
   @Produces(TEXT_HTML)
-  public TemplateInstance getPage() {
-    List<LazychatMessage> lazychatMessages;
-    if (identity.isAnonymous()) {
-      Role world = Role.find("from Role r join r.tags tag where tag = 'world'").singleResult();
-      lazychatMessages =
-          Bookmark.find(
-                  "select lm from LazychatMessage lm join lm.targets target left join fetch lm.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();
-      lazychatMessages =
-          Bookmark.find(
-                  "select lm from BenkiUser u inner join u.visibleLazychatMessages lm left join fetch lm.owner where u.id = ?1",
-                  Sort.by("date").descending(),
-                  user.id)
-              .list();
-    }
-    return lazychatList.data("lazychatMessages", lazychatMessages);
+  public TemplateInstance getIndex(
+      @QueryParam("i") @CheckForNull Integer cursor,
+      @QueryParam("n") @CheckForNull Integer maxResults) {
+
+    maxResults = maxResults == null ? defaultMaxResults : maxResults;
+
+    var session = entityManager.unwrap(Session.class);
+    var q = LazychatMessage.findViewable(session, identity, null, cursor, maxResults);
+
+    return lazychatList
+        .data("posts", q.posts)
+        .data("authenticated", !identity.isAnonymous())
+        .data("hasPreviousPage", q.prevCursor != null)
+        .data("hasNextPage", q.nextCursor != null)
+        .data("previousCursor", q.prevCursor)
+        .data("nextCursor", q.nextCursor)
+        .data("pageSize", maxResults);
+  }
+
+  @GET
+  @Path("~{ownerName}")
+  @Produces(TEXT_HTML)
+  public TemplateInstance getUserIndex(
+      @PathParam("ownerName") String ownerName,
+      @QueryParam("i") @CheckForNull Integer cursor,
+      @QueryParam("n") @CheckForNull Integer maxResults) {
+
+    maxResults = maxResults == null ? defaultMaxResults : maxResults;
+
+    var owner = User.findByNickname(ownerName);
+    var session = entityManager.unwrap(Session.class);
+    var q = LazychatMessage.findViewable(session, identity, owner, cursor, maxResults);
+
+    return lazychatList
+        .data("posts", q.posts)
+        .data("authenticated", !identity.isAnonymous())
+        .data("hasPreviousPage", q.prevCursor != null)
+        .data("hasNextPage", q.nextCursor != null)
+        .data("previousCursor", q.prevCursor)
+        .data("nextCursor", q.nextCursor)
+        .data("pageSize", maxResults);
   }
 
   @TemplateExtension
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index b90cc9e..4d03175 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -9,6 +9,7 @@
 
 mulkcms.tag-base = hub.benkard.de
 mulkcms.bookmarks.default-max-results = 25
+mulkcms.lazychat.default-max-results = 25
 
 quarkus.datasource.driver = org.postgresql.Driver
 quarkus.datasource.max-size = 8
diff --git a/src/main/resources/templates/benki/bookmarks/bookmarkList.html b/src/main/resources/templates/benki/bookmarks/bookmarkList.html
index 290cb26..8c87a55 100644
--- a/src/main/resources/templates/benki/bookmarks/bookmarkList.html
+++ b/src/main/resources/templates/benki/bookmarks/bookmarkList.html
@@ -1,4 +1,4 @@
-{@java.util.List<eu.mulk.mulkcms2.benki.bookmarks.Bookmark> bookmarks}
+{@java.util.List<eu.mulk.mulkcms2.benki.bookmarks.Bookmark> posts}
 {@java.lang.Boolean authenticated}
 {@java.lang.Boolean hasPreviousPage}
 {@java.lang.Boolean hasNextPage}
@@ -38,8 +38,8 @@
 </div>
 
 <section id="main-content">
-  {#for bookmark in bookmarks}
-    {#with bookmark}
+  {#for post in posts}
+    {#with post}
       <article class="bookmark">
         <header>
           <a href="{uri}"><h1 class="bookmark-title">{title}</h1></a>
diff --git a/src/main/resources/templates/benki/lazychat/lazychatList.html b/src/main/resources/templates/benki/lazychat/lazychatList.html
index ecac7a7..b644662 100644
--- a/src/main/resources/templates/benki/lazychat/lazychatList.html
+++ b/src/main/resources/templates/benki/lazychat/lazychatList.html
@@ -1,4 +1,10 @@
-{@java.util.List<eu.mulk.mulkcms2.benki.lazychat.LazychatMessage> lazychatMessages}
+{@java.util.List<eu.mulk.mulkcms2.benki.lazychat.LazychatMessage> posts}
+{@java.lang.Boolean authenticated}
+{@java.lang.Boolean hasPreviousPage}
+{@java.lang.Boolean hasNextPage}
+{@java.lang.Integer previousCursor}
+{@java.lang.Integer nextCursor}
+{@java.lang.Integer pageSize}
 
 {#include base.html}
 
@@ -10,22 +16,36 @@
 
 {#body}
 
-{#for lazychatMessage in lazychatMessages}
-  {#with lazychatMessage}
-    <article class="lazychat-message">
-      <header>
-        <div class="lazychat-message-info">
-          <time datetime="{date.htmlDateTime}">{date.humanDateTime}</time>
-          <span class="lazychat-message-owner">{owner.firstName} {owner.lastName}</span>
-        </div>
-      </header>
+<div class="paging">
+  {#if hasPreviousPage}<a href="?i={previousCursor}&n={pageSize}" class="pure-button">⇠ previous page</a>{/if}
+  <span class="filler"></span>
+  {#if hasNextPage}<a href="?i={nextCursor}&n={pageSize}" class="pure-button">next page ⇢</a>{/if}
+</div>
 
-      <section class="lazychat-message-content">
-        {contentHtml.raw}
-      </section>
-    </article>
-  {/with}
-{/for}
+<section id="main-content">
+  {#for post in posts}
+    {#with post}
+      <article class="lazychat-message">
+        <header>
+          <div class="lazychat-message-info">
+            <time datetime="{date.htmlDateTime}">{date.humanDateTime}</time>
+            <span class="lazychat-message-owner">{owner.firstName} {owner.lastName}</span>
+          </div>
+        </header>
+
+        <section class="lazychat-message-content">
+          {contentHtml.raw}
+        </section>
+      </article>
+    {/with}
+  {/for}
+</section>
+
+<div class="paging">
+  {#if hasPreviousPage}<a href="?i={previousCursor}&n={pageSize}" class="pure-button">⇠ previous page</a>{/if}
+  <span class="filler"></span>
+  {#if hasNextPage}<a href="?i={nextCursor}&n={pageSize}" class="pure-button">next page ⇢</a>{/if}
+</div>
 
 {/body}