From 8d9f18ad6233388b4b1beb4e457ad211015b90a4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sun, 5 Jan 2020 22:31:54 +0100 Subject: [PATCH] =?utf8?q?=E2=99=BB=EF=B8=8F=20Use=20handler=20for=20sone-?= =?utf8?q?mentioned=20notifications?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../net/pterodactylus/sone/web/WebInterface.java | 80 -------------------- .../sone/web/notification/NotificationHandler.kt | 3 +- .../web/notification/NotificationHandlerModule.kt | 7 ++ .../sone/web/notification/SoneMentionedHandler.kt | 47 ++++++++++++ .../notification/NotificationHandlerModuleTest.kt | 28 +++++++ .../web/notification/SoneMentionedHandlerTest.kt | 87 ++++++++++++++++++++++ 6 files changed, 171 insertions(+), 81 deletions(-) create mode 100644 src/main/kotlin/net/pterodactylus/sone/web/notification/SoneMentionedHandler.kt create mode 100644 src/test/kotlin/net/pterodactylus/sone/web/notification/SoneMentionedHandlerTest.kt diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index 50c63ee..5bb4e3a 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -22,7 +22,6 @@ import static java.util.logging.Logger.getLogger; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TimeZone; @@ -53,9 +52,6 @@ import net.pterodactylus.sone.template.LinkedElementRenderFilter; import net.pterodactylus.sone.template.ParserFilter; import net.pterodactylus.sone.template.RenderFilter; import net.pterodactylus.sone.template.ShortenFilter; -import net.pterodactylus.sone.text.Part; -import net.pterodactylus.sone.text.SonePart; -import net.pterodactylus.sone.text.SoneTextParser; import net.pterodactylus.sone.text.TimeTextConverter; import net.pterodactylus.sone.web.ajax.BookmarkAjaxPage; import net.pterodactylus.sone.web.ajax.CreatePostAjaxPage; @@ -101,7 +97,6 @@ import freenet.clients.http.ToadletContext; import com.codahale.metrics.*; import com.google.common.base.Optional; -import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.Subscribe; import com.google.inject.Inject; @@ -131,9 +126,6 @@ public class WebInterface implements SessionProvider { private final TemplateContextFactory templateContextFactory; private final TemplateRenderer templateRenderer; - /** The Sone text parser. */ - private final SoneTextParser soneTextParser; - /** The parser filter. */ private final ParserFilter parserFilter; private final ShortenFilter shortenFilter; @@ -164,9 +156,6 @@ public class WebInterface implements SessionProvider { /** The invisible “local reply” notification. */ private final ListNotification localReplyNotification; - /** The “you have been mentioned” notification. */ - private final ListNotification mentionNotification; - /** Notifications for sone inserts. */ private final Map soneInsertNotifications = new HashMap<>(); @@ -200,7 +189,6 @@ public class WebInterface implements SessionProvider { this.newPostNotification = newPostNotification; this.localPostNotification = localPostNotification; formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword(); - soneTextParser = new SoneTextParser(getCore(), getCore()); this.templateContextFactory = templateContextFactory; templateContextFactory.addTemplateObject("webInterface", this); @@ -212,9 +200,6 @@ public class WebInterface implements SessionProvider { Template localReplyNotificationTemplate = loaders.loadTemplate("/templates/notify/newReplyNotification.html"); localReplyNotification = new ListNotification<>("local-reply-notification", "replies", localReplyNotificationTemplate, false); - - Template mentionNotificationTemplate = loaders.loadTemplate("/templates/notify/mentionNotification.html"); - mentionNotification = new ListNotification<>("mention-notification", "posts", mentionNotificationTemplate, false); } // @@ -506,26 +491,6 @@ public class WebInterface implements SessionProvider { } /** - * Returns all {@link Sone#isLocal() local Sone}s that are referenced by - * {@link SonePart}s in the given text (after parsing it using - * {@link SoneTextParser}). - * - * @param text - * The text to parse - * @return All mentioned local Sones - */ - private Collection getMentionedSones(String text) { - /* we need no context to find mentioned Sones. */ - Set mentionedSones = new HashSet<>(); - for (Part part : soneTextParser.parse(text, null)) { - if (part instanceof SonePart) { - mentionedSones.add(((SonePart) part).getSone()); - } - } - return Collections2.filter(mentionedSones, Sone.LOCAL_SONE_FILTER); - } - - /** * Returns the Sone insert notification for the given Sone. If no * notification for the given Sone exists, a new notification is created and * cached. @@ -546,46 +511,11 @@ public class WebInterface implements SessionProvider { } } - private boolean localSoneMentionedInNewPostOrReply(Post post) { - if (!post.getSone().isLocal()) { - if (!getMentionedSones(post.getText()).isEmpty() && !post.isKnown()) { - return true; - } - } - for (PostReply postReply : getCore().getReplies(post.getId())) { - if (postReply.getSone().isLocal()) { - continue; - } - if (!getMentionedSones(postReply.getText()).isEmpty() && !postReply.isKnown()) { - return true; - } - } - return false; - } - // // EVENT HANDLERS // /** - * Notifies the web interface that a new {@link Post} was found. - * - * @param newPostFoundEvent - * The event - */ - @Subscribe - public void newPostFound(NewPostFoundEvent newPostFoundEvent) { - Post post = newPostFoundEvent.getPost(); - boolean isLocal = post.getSone().isLocal(); - if (!hasFirstStartNotification()) { - if (!getMentionedSones(post.getText()).isEmpty() && !isLocal) { - mentionNotification.add(post); - notificationManager.addNotification(mentionNotification); - } - } - } - - /** * Notifies the web interface that a new {@link PostReply} was found. * * @param newPostReplyFoundEvent @@ -602,10 +532,6 @@ public class WebInterface implements SessionProvider { } if (!hasFirstStartNotification()) { notificationManager.addNotification(isLocal ? localReplyNotification : newReplyNotification); - if (reply.getPost().isPresent() && localSoneMentionedInNewPostOrReply(reply.getPost().get())) { - mentionNotification.add(reply.getPost().get()); - notificationManager.addNotification(mentionNotification); - } } else { getCore().markReplyKnown(reply); } @@ -628,9 +554,6 @@ public class WebInterface implements SessionProvider { private void removePost(Post post) { newPostNotification.remove(post); - if (!localSoneMentionedInNewPostOrReply(post)) { - mentionNotification.remove(post); - } } @Subscribe @@ -641,9 +564,6 @@ public class WebInterface implements SessionProvider { private void removeReply(PostReply reply) { newReplyNotification.remove(reply); localReplyNotification.remove(reply); - if (reply.getPost().isPresent() && !localSoneMentionedInNewPostOrReply(reply.getPost().get())) { - mentionNotification.remove(reply.getPost().get()); - } } /** diff --git a/src/main/kotlin/net/pterodactylus/sone/web/notification/NotificationHandler.kt b/src/main/kotlin/net/pterodactylus/sone/web/notification/NotificationHandler.kt index cc2a2b3..aba74ae 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/notification/NotificationHandler.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/notification/NotificationHandler.kt @@ -39,5 +39,6 @@ class NotificationHandler @Inject constructor( startupHandler: StartupHandler, webOfTrustPinger: WebOfTrustPinger, webOfTrustHandler: WebOfTrustHandler, - soneMentionDetector: SoneMentionDetector + soneMentionDetector: SoneMentionDetector, + soneMentionedHandler: SoneMentionedHandler ) diff --git a/src/main/kotlin/net/pterodactylus/sone/web/notification/NotificationHandlerModule.kt b/src/main/kotlin/net/pterodactylus/sone/web/notification/NotificationHandlerModule.kt index 96a7cdf..cfe5db3 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/notification/NotificationHandlerModule.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/notification/NotificationHandlerModule.kt @@ -52,6 +52,7 @@ class NotificationHandlerModule : AbstractModule() { bind().asSingleton() bind().asSingleton() bind().asSingleton() + bind().asSingleton() } @Provides @@ -146,6 +147,12 @@ class NotificationHandlerModule : AbstractModule() { fun getWebOfTrustReschedule(@Named("notification") ticker: ScheduledExecutorService) = Consumer { ticker.schedule(it, 15, SECONDS) } + @Provides + @Singleton + @Named("soneMentioned") + fun getSoneMentionedNotification(loaders: Loaders) = + ListNotification("mention-notification", "posts", loaders.loadTemplate("/templates/notify/mentionNotification.html"), dismissable = false) + private inline fun bind(): AnnotatedBindingBuilder = bind(T::class.java) private fun ScopedBindingBuilder.asSingleton() = `in`(Singleton::class.java) diff --git a/src/main/kotlin/net/pterodactylus/sone/web/notification/SoneMentionedHandler.kt b/src/main/kotlin/net/pterodactylus/sone/web/notification/SoneMentionedHandler.kt new file mode 100644 index 0000000..a03e490 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/notification/SoneMentionedHandler.kt @@ -0,0 +1,47 @@ +/** + * Sone - SoneMentionedHandler.kt - Copyright © 2020 David ‘Bombe’ Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.web.notification + +import com.google.common.eventbus.* +import net.pterodactylus.sone.core.event.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.notify.* +import net.pterodactylus.util.notify.* +import javax.inject.* + +/** + * Handler for the [MentionOfLocalSoneFoundEvent] and + * [MentionOfLocalSoneRemovedEvent] events that add the corresponding + * notification to the notification manager. + */ +class SoneMentionedHandler @Inject constructor(private val notificationManager: NotificationManager, @Named("soneMentioned") private val notification: ListNotification) { + + @Subscribe + fun mentionOfLocalSoneFound(event: MentionOfLocalSoneFoundEvent) { + if (!notificationManager.hasFirstStartNotification()) { + notification.add(event.post) + notificationManager.addNotification(notification) + } + } + + @Subscribe + fun mentionOfLocalSoneRemoved(event: MentionOfLocalSoneRemovedEvent) { + notification.remove(event.post) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/notification/NotificationHandlerModuleTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/notification/NotificationHandlerModuleTest.kt index 2606040..497ae1d 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/notification/NotificationHandlerModuleTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/notification/NotificationHandlerModuleTest.kt @@ -463,4 +463,32 @@ class NotificationHandlerModuleTest { assertThat(injector.getInstance(), notNullValue()) } + @Test + fun `sone-mentioned notification is created as singleton`() { + injector.verifySingletonInstance>(named("soneMentioned")) + } + + @Test + fun `sone-mentioned notification has correct ID`() { + assertThat(injector.getInstance>(named("soneMentioned")).id, equalTo("mention-notification")) + } + + @Test + fun `sone-mentioned notification is not dismissable`() { + assertThat(injector.getInstance>(named("soneMentioned")).isDismissable, equalTo(false)) + } + + @Test + fun `sone-mentioned notification loads correct template`() { + loaders.templates += "/templates/notify/mentionNotification.html" to "<% posts>".asTemplate() + val notification = injector.getInstance>(named("soneMentioned")) + val posts = listOf(EmptyPost("1"), EmptyPost("2")).onEach(notification::add) + assertThat(notification.render(), equalTo(posts.toString())) + } + + @Test + fun `sone-mentioned handler is created as singleton`() { + injector.verifySingletonInstance() + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/notification/SoneMentionedHandlerTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/notification/SoneMentionedHandlerTest.kt new file mode 100644 index 0000000..4e91aa5 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/notification/SoneMentionedHandlerTest.kt @@ -0,0 +1,87 @@ +/** + * Sone - SoneMentionedHandlerTest.kt - Copyright © 2020 David ‘Bombe’ Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.web.notification + +import com.google.common.eventbus.* +import net.pterodactylus.sone.core.event.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Post.* +import net.pterodactylus.sone.notify.* +import net.pterodactylus.util.notify.* +import net.pterodactylus.util.template.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import kotlin.test.* + +/** + * Unit test for [SoneMentionedHandler]. + */ +@Suppress("UnstableApiUsage") +class SoneMentionedHandlerTest { + + private val notificationManager = NotificationManager() + private val notification = ListNotification("", "", Template()) + private val eventBus = EventBus() + + init { + eventBus.register(SoneMentionedHandler(notificationManager, notification)) + } + + @Test + fun `handler adds notification to manager on event`() { + eventBus.post(MentionOfLocalSoneFoundEvent(post)) + assertThat(notificationManager.notifications, contains(notification)) + } + + @Test + fun `handler adds post to notification on event`() { + eventBus.post(MentionOfLocalSoneFoundEvent(post)) + assertThat(notification.elements, contains(post)) + } + + @Test + fun `handler does not add notification during first start`() { + notificationManager.firstStart() + eventBus.post(MentionOfLocalSoneFoundEvent(post)) + assertThat(notificationManager.notifications, not(hasItem(notification))) + } + + @Test + fun `handler does not add post to notification during first start`() { + notificationManager.firstStart() + eventBus.post(MentionOfLocalSoneFoundEvent(post)) + assertThat(notification.elements, not(hasItem(post))) + } + + @Test + fun `handler removes post from notification`() { + notification.add(post) + eventBus.post(MentionOfLocalSoneRemovedEvent(post)) + assertThat(notification.elements, not(hasItem(post))) + } + + @Test + fun `handler removes notification from manager`() { + notificationManager.addNotification(notification) + eventBus.post(MentionOfLocalSoneRemovedEvent(post)) + assertThat(notificationManager.notifications, not(hasItem(notification))) + } + +} + +private val post = EmptyPost("") -- 2.7.4