From 1937e6a72594f98d1fa031d8220f10ccc798c2be Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Sat, 4 Jun 2022 09:06:31 +0200 Subject: KB66 Add comment notification email. Change-Id: I27feecfe2d4309397b116552856227eacb7e9600 --- .../eu/mulk/mulkcms2/benki/posts/PostResource.java | 25 +++- .../java/eu/mulk/mulkcms2/benki/users/User.java | 6 + .../PostResource/commentNotificationMail.txt | 9 ++ .../resources/templates/PostResource/postList.html | 137 +++++++++++++++++++++ .../resources/templates/benki/posts/postList.html | 137 --------------------- 5 files changed, 175 insertions(+), 139 deletions(-) create mode 100644 src/main/resources/templates/PostResource/commentNotificationMail.txt create mode 100644 src/main/resources/templates/PostResource/postList.html delete mode 100644 src/main/resources/templates/benki/posts/postList.html diff --git a/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java b/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java index 5a38262..d1e5775 100644 --- a/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java +++ b/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java @@ -21,6 +21,7 @@ import eu.mulk.mulkcms2.benki.login.LoginRoles; import eu.mulk.mulkcms2.benki.posts.Post.PostPage; import eu.mulk.mulkcms2.benki.posts.Post.Scope; import eu.mulk.mulkcms2.benki.users.User; +import io.quarkus.mailer.MailTemplate.MailTemplateInstance; import io.quarkus.qute.CheckedTemplate; import io.quarkus.qute.TemplateExtension; import io.quarkus.qute.TemplateInstance; @@ -45,6 +46,9 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; import javax.annotation.CheckForNull; import javax.annotation.Nullable; @@ -96,7 +100,10 @@ public abstract class PostResource { @ConfigProperty(name = "mulkcms.posts.default-max-results") int defaultMaxResults; - @CheckedTemplate(basePath = "benki/posts") + @ConfigProperty(name = "quarkus.mailer.from") + String mailSenderAddress; + + @CheckedTemplate static class Templates { public static native TemplateInstance postList( @@ -112,6 +119,9 @@ public abstract class PostResource { @CheckForNull Integer nextCursor, @CheckForNull Integer pageSize, @CheckForNull String searchQuery); + + public static native MailTemplateInstance commentNotificationMail( + int postId, LazychatMessage comment); } @Inject protected SecurityIdentity identity; @@ -303,7 +313,7 @@ public abstract class PostResource { @PathParam("id") int postId, @FormParam("message") @NotEmpty String message, @FormParam("hashcash-salt") long hashcashSalt) - throws NoSuchAlgorithmException { + throws NoSuchAlgorithmException, ExecutionException, InterruptedException, TimeoutException { var hashcashDigest = MessageDigest.getInstance(hashcashDigestAlgorithm); hashcashDigest.update("Hashcash-Salt: ".getBytes(UTF_8)); hashcashDigest.update(String.valueOf(hashcashSalt).getBytes(UTF_8)); @@ -334,6 +344,17 @@ public abstract class PostResource { assignPostTargets(post.getVisibility(), post.owner, comment); comment.persist(); + var admins = User.findAdmins(); + + var mailText = Templates.commentNotificationMail(postId, comment); + var sendJob = + mailText + .subject(String.format("MulkCMS comment #%d", comment.id)) + .to(mailSenderAddress) + .bcc(admins.stream().map(x -> x.email).toArray(String[]::new)) + .send(); + sendJob.subscribe().asCompletionStage().get(10000, TimeUnit.SECONDS); + return Response.seeOther(UriBuilder.fromUri("/posts/{id}").build(postId)).build(); } 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 04a5cd4..99ab91f 100644 --- a/src/main/java/eu/mulk/mulkcms2/benki/users/User.java +++ b/src/main/java/eu/mulk/mulkcms2/benki/users/User.java @@ -8,6 +8,7 @@ import eu.mulk.mulkcms2.benki.posts.Post; import eu.mulk.mulkcms2.benki.wiki.WikiPageRevision; import io.quarkus.hibernate.orm.panache.PanacheEntityBase; import java.util.Collection; +import java.util.List; import java.util.Objects; import java.util.Set; import javax.annotation.CheckForNull; @@ -162,6 +163,11 @@ public class User extends PanacheEntityBase { .singleResult(); } + public static List findAdmins() { + return find("select distinct u from BenkiUser u left join u.effectiveRoles r left join r.tags t where t = 'admin' or u.status = 'admin'") + .list(); + } + public final boolean canSee(Post message) { return message.isVisibleTo(this); } diff --git a/src/main/resources/templates/PostResource/commentNotificationMail.txt b/src/main/resources/templates/PostResource/commentNotificationMail.txt new file mode 100644 index 0000000..a226106 --- /dev/null +++ b/src/main/resources/templates/PostResource/commentNotificationMail.txt @@ -0,0 +1,9 @@ +{@int postId} +{@eu.mulk.mulkcms2.benki.lazychat.LazychatMessage comment} +New Comment +=========== + +Link: +{#if comment.owner != null}Author: {comment.owner.firstName}{/if} + +{comment.text.content} diff --git a/src/main/resources/templates/PostResource/postList.html b/src/main/resources/templates/PostResource/postList.html new file mode 100644 index 0000000..2f932ec --- /dev/null +++ b/src/main/resources/templates/PostResource/postList.html @@ -0,0 +1,137 @@ +{#include base.html} + +{#title}Benki {pageTitle}{/title} +{#siteSection}{pageTitle}{/siteSection} + +{#nav}{#navbar siteSection=pageTitle /} + +{#head} + + + {#if showBookmarkForm || showLazychatForm} + + {/if} +{/head} + +{#body} + +{#if showBookmarkForm} + +

+
+ +
+
+{/if} + +{#if showLazychatForm} + +

+
+ +
+
+{/if} + +
+
+ + +
+ {#if hasPreviousPage}⇠ previous page{/if} + {#if hasNextPage}next page ⇢{/if} +
+ +
+ {#for day in postDays} +
+
+ +
+ + {#for post in day.posts} + {#if post.isBookmark} +
+
+ {#if showBookmarkForm} + + + + {/if} +
+ +
+
+ {post.owner.firstName} + + # + + + +

🔖 {post.title}

. +
+
+
+ +
+ {#if showBookmarkForm} + + {/if} +
+ +
+ {post.descriptionHtml.raw} +
+ + {#if showCommentBox} + {#commentBox postId=post.id comments=post.comments /} + {/if} +
+ {#else} +
+
+ {#if showLazychatForm} + + + + {/if} +
+ +
+
+ {post.owner.firstName} + + # + +
+
+ +
+ {#if showLazychatForm} + + {/if} +
+ +
+ {post.descriptionHtml.raw} +
+ + {#if showCommentBox} + {#commentBox postId=post.id comments=post.comments /} + {/if} +
+ {/if} + {/for} +
+ {/for} +
+ +
+ {#if hasPreviousPage}⇠ previous page{/if} + + {#if hasNextPage}next page ⇢{/if} +
+ +{/body} + +{/include} diff --git a/src/main/resources/templates/benki/posts/postList.html b/src/main/resources/templates/benki/posts/postList.html deleted file mode 100644 index 2f932ec..0000000 --- a/src/main/resources/templates/benki/posts/postList.html +++ /dev/null @@ -1,137 +0,0 @@ -{#include base.html} - -{#title}Benki {pageTitle}{/title} -{#siteSection}{pageTitle}{/siteSection} - -{#nav}{#navbar siteSection=pageTitle /} - -{#head} - - - {#if showBookmarkForm || showLazychatForm} - - {/if} -{/head} - -{#body} - -{#if showBookmarkForm} - -

-
- -
-
-{/if} - -{#if showLazychatForm} - -

-
- -
-
-{/if} - -
-
- - -
- {#if hasPreviousPage}⇠ previous page{/if} - {#if hasNextPage}next page ⇢{/if} -
- -
- {#for day in postDays} -
-
- -
- - {#for post in day.posts} - {#if post.isBookmark} -
-
- {#if showBookmarkForm} - - - - {/if} -
- -
-
- {post.owner.firstName} - - # - - - -

🔖 {post.title}

. -
-
-
- -
- {#if showBookmarkForm} - - {/if} -
- -
- {post.descriptionHtml.raw} -
- - {#if showCommentBox} - {#commentBox postId=post.id comments=post.comments /} - {/if} -
- {#else} -
-
- {#if showLazychatForm} - - - - {/if} -
- -
-
- {post.owner.firstName} - - # - -
-
- -
- {#if showLazychatForm} - - {/if} -
- -
- {post.descriptionHtml.raw} -
- - {#if showCommentBox} - {#commentBox postId=post.id comments=post.comments /} - {/if} -
- {/if} - {/for} -
- {/for} -
- -
- {#if hasPreviousPage}⇠ previous page{/if} - - {#if hasNextPage}next page ⇢{/if} -
- -{/body} - -{/include} -- cgit v1.2.3