🚧 Add new Sone handler to notifications
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 29 Nov 2019 21:11:55 +0000 (22:11 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 11 Dec 2019 15:58:46 +0000 (16:58 +0100)
src/main/java/net/pterodactylus/sone/web/WebInterface.java
src/main/kotlin/net/pterodactylus/sone/web/notification/NewSoneHandler.kt
src/main/kotlin/net/pterodactylus/sone/web/notification/NotificationHandler.kt
src/test/kotlin/net/pterodactylus/sone/test/Matchers.kt
src/test/kotlin/net/pterodactylus/sone/web/notification/NewSoneHandlerTest.kt
src/test/kotlin/net/pterodactylus/sone/web/notification/NotificationHandlerTest.kt

index bcc7a11..58c9d19 100644 (file)
@@ -157,9 +157,6 @@ public class WebInterface implements SessionProvider {
        private final MetricRegistry metricRegistry;
        private final Translation translation;
 
-       /** The “new Sone” notification. */
-       private final ListNotification<Sone> newSoneNotification;
-
        /** The “new post” notification. */
        private final ListNotification<Post> newPostNotification;
 
@@ -233,9 +230,6 @@ public class WebInterface implements SessionProvider {
                templateContextFactory.addTemplateObject("formPassword", formPassword);
 
                /* create notifications. */
-               Template newSoneNotificationTemplate = loaders.loadTemplate("/templates/notify/newSoneNotification.html");
-               newSoneNotification = new ListNotification<>("new-sone-notification", "sones", newSoneNotificationTemplate, false);
-
                Template newPostNotificationTemplate = loaders.loadTemplate("/templates/notify/newPostNotification.html");
                newPostNotification = new ListNotification<>("new-post-notification", "posts", newPostNotificationTemplate, false);
 
@@ -690,20 +684,6 @@ public class WebInterface implements SessionProvider {
        //
 
        /**
-        * Notifies the web interface that a new {@link Sone} was found.
-        *
-        * @param newSoneFoundEvent
-        *            The event
-        */
-       @Subscribe
-       public void newSoneFound(NewSoneFoundEvent newSoneFoundEvent) {
-               newSoneNotification.add(newSoneFoundEvent.getSone());
-               if (!hasFirstStartNotification()) {
-                       notificationManager.addNotification(newSoneNotification);
-               }
-       }
-
-       /**
         * Notifies the web interface that a new {@link Post} was found.
         *
         * @param newPostFoundEvent
@@ -755,17 +735,6 @@ public class WebInterface implements SessionProvider {
                }
        }
 
-       /**
-        * Notifies the web interface that a {@link Sone} was marked as known.
-        *
-        * @param markSoneKnownEvent
-        *            The event
-        */
-       @Subscribe
-       public void markSoneKnown(MarkSoneKnownEvent markSoneKnownEvent) {
-               newSoneNotification.remove(markSoneKnownEvent.getSone());
-       }
-
        @Subscribe
        public void markPostKnown(MarkPostKnownEvent markPostKnownEvent) {
                removePost(markPostKnownEvent.getPost());
@@ -777,11 +746,6 @@ public class WebInterface implements SessionProvider {
        }
 
        @Subscribe
-       public void soneRemoved(SoneRemovedEvent soneRemovedEvent) {
-               newSoneNotification.remove(soneRemovedEvent.getSone());
-       }
-
-       @Subscribe
        public void postRemoved(PostRemovedEvent postRemovedEvent) {
                removePost(postRemovedEvent.getPost());
        }
index 9ac6c28..83be6fd 100644 (file)
@@ -29,7 +29,7 @@ import net.pterodactylus.util.template.*
  */
 class NewSoneHandler(private val notificationManager: NotificationManager, template: Template) {
 
-       private val notification = ListNotification<Sone>("new-sone-notification", "", template)
+       private val notification = ListNotification<Sone>("new-sone-notification", "sones", template, dismissable = false)
 
        @Subscribe
        fun newSoneFound(newSoneFoundEvent: NewSoneFoundEvent) {
@@ -39,6 +39,16 @@ class NewSoneHandler(private val notificationManager: NotificationManager, templ
                }
        }
 
+       @Subscribe
+       fun markedSoneKnown(markSoneKnownEvent: MarkSoneKnownEvent) {
+               notification.remove(markSoneKnownEvent.sone)
+       }
+
+       @Subscribe
+       fun soneRemoved(soneRemovedEvent: SoneRemovedEvent) {
+               notification.remove(soneRemovedEvent.sone)
+       }
+
 }
 
 private fun NotificationManager.hasNotification(id: String) =
index 7f81f9a..37df1ac 100644 (file)
@@ -29,8 +29,11 @@ import javax.inject.*
 class NotificationHandler @Inject constructor(private val eventBus: EventBus, private val loaders: Loaders, private val notificationManager: NotificationManager) {
 
        fun start() {
-               SoneLockedOnStartupHandler(notificationManager, loaders.loadTemplate("/templates/notify/soneLockedOnStartupNotification.html"))
-                               .also(eventBus::register)
+               register { SoneLockedOnStartupHandler(it, loaders.loadTemplate("/templates/notify/soneLockedOnStartupNotification.html")) }
+               register { NewSoneHandler(it, loaders.loadTemplate("/templates/notify/newSoneNotification.html")) }
        }
 
+       private fun register(handler: (NotificationManager) -> Any) =
+                       handler(notificationManager).also(eventBus::register)
+
 }
index 7fc9428..85ed9e7 100644 (file)
@@ -5,8 +5,27 @@ import net.pterodactylus.sone.freenet.wot.*
 import net.pterodactylus.sone.utils.*
 import net.pterodactylus.util.web.*
 import org.hamcrest.*
+import org.hamcrest.Matchers
 import org.hamcrest.Matchers.*
 
+/**
+ * Returns a [hamcrest matcher][Matcher] constructed from the given predicate.
+ */
+fun <T> matches(description: String? = null, predicate: (T) -> Boolean) = object : TypeSafeDiagnosingMatcher<T>() {
+
+       override fun matchesSafely(item: T, mismatchDescription: Description) =
+                       predicate(item).onFalse {
+                               mismatchDescription.appendValue(item).appendText(" did not match predicate")
+                       }
+
+       override fun describeTo(description: Description) {
+               description.appendText("matches predicate ").appendValue(predicate)
+       }
+
+}.let { matcher ->
+       description?.let { describedAs(description, matcher) } ?: matcher
+}
+
 fun hasHeader(name: String, value: String) = object : TypeSafeDiagnosingMatcher<Header>() {
        override fun matchesSafely(item: Header, mismatchDescription: Description) =
                        compare(item.name, { it.equals(name, ignoreCase = true) }) { mismatchDescription.appendText("name is ").appendValue(it) }
index 0f7b182..951de28 100644 (file)
@@ -21,8 +21,9 @@ import com.google.common.eventbus.*
 import net.pterodactylus.sone.core.event.*
 import net.pterodactylus.sone.data.impl.*
 import net.pterodactylus.sone.notify.*
+import net.pterodactylus.sone.test.*
+import net.pterodactylus.sone.utils.*
 import net.pterodactylus.util.notify.*
-import net.pterodactylus.util.template.*
 import org.hamcrest.MatcherAssert.*
 import org.hamcrest.Matchers.*
 import java.io.*
@@ -33,7 +34,7 @@ class NewSoneHandlerTest {
        @Suppress("UnstableApiUsage")
        private val eventBus = EventBus()
        private val notificationManager = NotificationManager()
-       private val handler = NewSoneHandler(notificationManager, Template())
+       private val handler = NewSoneHandler(notificationManager, "<% sones>".asTemplate())
 
        init {
                eventBus.register(handler)
@@ -54,6 +55,20 @@ class NewSoneHandlerTest {
        }
 
        @Test
+       fun `handler sets correct key for sones`() {
+               eventBus.post(NewSoneFoundEvent(sone))
+               val notification = notificationManager.notifications.single() as ListNotification<*>
+               assertThat(notification.render(), equalTo(listOf(sone).toString()))
+       }
+
+       @Test
+       fun `handler creates non-dismissable notification`() {
+               eventBus.post(NewSoneFoundEvent(sone))
+               val notification = notificationManager.notifications.single() as ListNotification<*>
+               assertThat(notification, matches("is not dismissable") { !it.isDismissable })
+       }
+
+       @Test
        fun `handler does not add notification on new sone event if first-start notification is present`() {
                notificationManager.addNotification(object : AbstractNotification("first-start-notification") {
                        override fun render(writer: Writer) = Unit
@@ -63,6 +78,22 @@ class NewSoneHandlerTest {
                assertThat(notification.id, equalTo("first-start-notification"))
        }
 
+       @Test
+       fun `handler removes sone from notification if sone is marked as known`() {
+               eventBus.post(NewSoneFoundEvent(sone))
+               val notification = notificationManager.notifications.single() as ListNotification<*>
+               eventBus.post(MarkSoneKnownEvent(sone))
+               assertThat(notification.elements, emptyIterable())
+       }
+
+       @Test
+       fun `handler removes sone from notification if sone is removed`() {
+               eventBus.post(NewSoneFoundEvent(sone))
+               val notification = notificationManager.notifications.single() as ListNotification<*>
+               eventBus.post(SoneRemovedEvent(sone))
+               assertThat(notification.elements, emptyIterable())
+       }
+
 }
 
 private val sone = IdOnlySone("sone-id")
index d145038..a0ccb9d 100644 (file)
@@ -18,7 +18,6 @@
 package net.pterodactylus.sone.web.notification
 
 import com.google.common.eventbus.*
-import com.google.inject.*
 import com.google.inject.Guice.*
 import net.pterodactylus.sone.main.*
 import net.pterodactylus.sone.test.*
@@ -52,13 +51,25 @@ class NotificationHandlerTest {
        @Test
        fun `notification handler registers handler for sone-locked event`() {
                handler.start()
-               assertThat(eventBus.registeredObjects.any { it.javaClass == SoneLockedOnStartupHandler::class.java }, equalTo(true))
+               assertThat(eventBus.registeredObjects, hasItem<Any>(matches { it.javaClass == SoneLockedOnStartupHandler::class.java }))
        }
 
        @Test
        fun `notification handler loads sone-locked notification template`() {
                handler.start()
-               assertThat(loaders.requestedTemplatePaths.any { it == "/templates/notify/soneLockedOnStartupNotification.html" }, equalTo(true))
+               assertThat(loaders.requestedTemplatePaths, hasItem("/templates/notify/soneLockedOnStartupNotification.html"))
+       }
+
+       @Test
+       fun `notification handler registers handler for new sone events`() {
+               handler.start()
+               assertThat(eventBus.registeredObjects, hasItem<Any>(matches { it.javaClass == NewSoneHandler::class.java }))
+       }
+
+       @Test
+       fun `notification handler loads new sone notification template`() {
+               handler.start()
+               assertThat(loaders.requestedTemplatePaths, hasItem("/templates/notify/newSoneNotification.html"))
        }
 
 }