Move post list query method to Post class.

Change-Id: I8dbb664d2522a3012a477b850b67cb642bae9aa8
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/Bookmark.java b/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/Bookmark.java
index 3f0afbb..f7dc9c0 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/Bookmark.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/Bookmark.java
@@ -1,8 +1,11 @@
 package eu.mulk.mulkcms2.benki.bookmarks;
 
 import eu.mulk.mulkcms2.benki.generic.Post;
+import eu.mulk.mulkcms2.benki.users.User;
 import eu.mulk.mulkcms2.common.markdown.MarkdownConverter;
+import io.quarkus.security.identity.SecurityIdentity;
 import java.util.Set;
+import javax.annotation.CheckForNull;
 import javax.persistence.CollectionTable;
 import javax.persistence.Column;
 import javax.persistence.ElementCollection;
@@ -11,6 +14,8 @@
 import javax.persistence.JoinColumn;
 import javax.persistence.Table;
 import javax.persistence.Transient;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
 
 @Entity
 @Table(name = "bookmarks", schema = "benki")
@@ -37,4 +42,13 @@
   public String getDescriptionHtml() {
     return new MarkdownConverter().htmlify(description);
   }
+
+  public static CriteriaQuery<Bookmark> findViewable(
+      SecurityIdentity readerIdentity,
+      @CheckForNull User owner,
+      @CheckForNull Integer cursor,
+      CriteriaBuilder cb,
+      boolean forward) {
+    return Post.findViewable(Bookmark.class, readerIdentity, owner, cursor, cb, forward);
+  }
 }
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 429514b..7dd35d4 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/bookmarks/BookmarkResource.java
@@ -12,11 +12,7 @@
 import com.rometools.rome.io.FeedException;
 import com.rometools.rome.io.WireFeedOutput;
 import eu.mulk.mulkcms2.benki.accesscontrol.Role;
-import eu.mulk.mulkcms2.benki.generic.Post;
-import eu.mulk.mulkcms2.benki.generic.Post_;
-import eu.mulk.mulkcms2.benki.lazychat.LazychatMessage;
 import eu.mulk.mulkcms2.benki.users.User;
-import eu.mulk.mulkcms2.benki.users.User_;
 import io.quarkus.qute.Template;
 import io.quarkus.qute.TemplateExtension;
 import io.quarkus.qute.TemplateInstance;
@@ -32,7 +28,6 @@
 import java.time.format.DateTimeFormatter;
 import java.time.format.FormatStyle;
 import java.time.temporal.TemporalAccessor;
-import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
@@ -46,11 +41,6 @@
 import javax.json.spi.JsonProvider;
 import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
-import javax.persistence.criteria.CriteriaBuilder;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.From;
-import javax.persistence.criteria.JoinType;
-import javax.persistence.criteria.Predicate;
 import javax.transaction.Transactional;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
@@ -331,7 +321,7 @@
 
     var cb = entityManager.unwrap(Session.class).getCriteriaBuilder();
 
-    var forwardCriteria = queryPostList(Bookmark.class, owner, cursor, cb, true);
+    var forwardCriteria = Bookmark.findViewable(identity, owner, cursor, cb, true);
     var forwardQuery = entityManager.createQuery(forwardCriteria);
 
     if (count != null) {
@@ -345,7 +335,7 @@
 
     if (cursor != null) {
       // Look backwards as well so we can find the prevCursor.
-      var backwardCriteria = queryPostList(Bookmark.class, owner, cursor, cb, false);
+      var backwardCriteria = Bookmark.findViewable(identity, owner, cursor, cb, false);
       var backwardQuery = entityManager.createQuery(backwardCriteria);
       backwardQuery.setMaxResults(count);
       var backwardResults = backwardQuery.getResultList();
@@ -364,59 +354,4 @@
 
     return new BookmarkPage(prevCursor, cursor, nextCursor, forwardResults);
   }
-
-  private <T extends Post> CriteriaQuery<T> queryPostList(
-      Class<T> entityClass,
-      @CheckForNull User owner,
-      @CheckForNull Integer cursor,
-      CriteriaBuilder cb,
-      boolean forward) {
-    CriteriaQuery<T> query = cb.createQuery(entityClass);
-
-    var conditions = new ArrayList<Predicate>();
-
-    From<?, T> post;
-    if (identity.isAnonymous()) {
-      post = query.from(entityClass);
-      var target = post.join(Post_.targets);
-      conditions.add(cb.equal(target, Role.getWorld()));
-    } else {
-      var userName = identity.getPrincipal().getName();
-      var user = User.findByNickname(userName);
-
-      var root = query.from(User.class);
-      conditions.add(cb.equal(root, user));
-      if (entityClass.isAssignableFrom(Bookmark.class)) {
-        post = (From<?, T>) root.join(User_.visibleBookmarks);
-      } else {
-        assert entityClass.isAssignableFrom(LazychatMessage.class) : entityClass;
-        post = (From<?, T>) root.join(User_.visibleLazychatMessages);
-      }
-    }
-
-    query.select(post);
-    post.fetch(Post_.owner, JoinType.LEFT);
-
-    if (owner != null) {
-      conditions.add(cb.equal(post.get(Post_.owner), owner));
-    }
-
-    if (forward) {
-      query.orderBy(cb.desc(post.get(Post_.id)));
-    } else {
-      query.orderBy(cb.asc(post.get(Post_.id)));
-    }
-
-    if (cursor != null) {
-      if (forward) {
-        conditions.add(cb.le(post.get(Post_.id), cursor));
-      } else {
-        conditions.add(cb.gt(post.get(Post_.id), cursor));
-      }
-    }
-
-    query.where(conditions.toArray(new Predicate[0]));
-
-    return query;
-  }
 }
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/generic/Post.java b/src/main/java/eu/mulk/mulkcms2/benki/generic/Post.java
index b4b4222..502cb0d 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/generic/Post.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/generic/Post.java
@@ -1,10 +1,16 @@
 package eu.mulk.mulkcms2.benki.generic;
 
 import eu.mulk.mulkcms2.benki.accesscontrol.Role;
+import eu.mulk.mulkcms2.benki.bookmarks.Bookmark;
+import eu.mulk.mulkcms2.benki.lazychat.LazychatMessage;
 import eu.mulk.mulkcms2.benki.users.User;
+import eu.mulk.mulkcms2.benki.users.User_;
 import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
+import io.quarkus.security.identity.SecurityIdentity;
 import java.time.OffsetDateTime;
+import java.util.ArrayList;
 import java.util.Set;
+import javax.annotation.CheckForNull;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
@@ -19,6 +25,11 @@
 import javax.persistence.ManyToOne;
 import javax.persistence.SequenceGenerator;
 import javax.persistence.Table;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.From;
+import javax.persistence.criteria.JoinType;
+import javax.persistence.criteria.Predicate;
 
 @Entity
 @Table(name = "posts", schema = "benki")
@@ -57,4 +68,60 @@
       joinColumns = @JoinColumn(name = "message"),
       inverseJoinColumns = @JoinColumn(name = "target"))
   public Set<Role> targets;
+
+  public static <T extends Post> CriteriaQuery<T> findViewable(
+      Class<T> entityClass,
+      SecurityIdentity readerIdentity,
+      @CheckForNull User owner,
+      @CheckForNull Integer cursor,
+      CriteriaBuilder cb,
+      boolean forward) {
+    CriteriaQuery<T> query = cb.createQuery(entityClass);
+
+    var conditions = new ArrayList<Predicate>();
+
+    From<?, T> post;
+    if (readerIdentity.isAnonymous()) {
+      post = query.from(entityClass);
+      var target = post.join(Post_.targets);
+      conditions.add(cb.equal(target, Role.getWorld()));
+    } else {
+      var userName = readerIdentity.getPrincipal().getName();
+      var user = User.findByNickname(userName);
+
+      var root = query.from(User.class);
+      conditions.add(cb.equal(root, user));
+      if (entityClass.isAssignableFrom(Bookmark.class)) {
+        post = (From<?, T>) root.join(User_.visibleBookmarks);
+      } else {
+        assert entityClass.isAssignableFrom(LazychatMessage.class) : entityClass;
+        post = (From<?, T>) root.join(User_.visibleLazychatMessages);
+      }
+    }
+
+    query.select(post);
+    post.fetch(Post_.owner, JoinType.LEFT);
+
+    if (owner != null) {
+      conditions.add(cb.equal(post.get(Post_.owner), owner));
+    }
+
+    if (forward) {
+      query.orderBy(cb.desc(post.get(Post_.id)));
+    } else {
+      query.orderBy(cb.asc(post.get(Post_.id)));
+    }
+
+    if (cursor != null) {
+      if (forward) {
+        conditions.add(cb.le(post.get(Post_.id), cursor));
+      } else {
+        conditions.add(cb.gt(post.get(Post_.id), cursor));
+      }
+    }
+
+    query.where(conditions.toArray(new Predicate[0]));
+
+    return query;
+  }
 }
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/lazychat/LazychatMessage.java b/src/main/java/eu/mulk/mulkcms2/benki/lazychat/LazychatMessage.java
index 31a5df5..504dd10 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/lazychat/LazychatMessage.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/lazychat/LazychatMessage.java
@@ -1,14 +1,19 @@
 package eu.mulk.mulkcms2.benki.lazychat;
 
 import eu.mulk.mulkcms2.benki.generic.Post;
+import eu.mulk.mulkcms2.benki.users.User;
 import eu.mulk.mulkcms2.common.markdown.MarkdownConverter;
+import io.quarkus.security.identity.SecurityIdentity;
 import java.util.Collection;
+import javax.annotation.CheckForNull;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.persistence.Transient;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
 
 @Entity
 @Table(name = "lazychat_messages", schema = "benki")
@@ -27,4 +32,13 @@
   public String getContentHtml() {
     return new MarkdownConverter().htmlify(content);
   }
+
+  public static CriteriaQuery<LazychatMessage> findViewable(
+      SecurityIdentity readerIdentity,
+      @CheckForNull User owner,
+      @CheckForNull Integer cursor,
+      CriteriaBuilder cb,
+      boolean forward) {
+    return Post.findViewable(LazychatMessage.class, readerIdentity, owner, cursor, cb, forward);
+  }
 }