--- /dev/null
+/**
+ * Sone - NotificationHandler.kt - Copyright © 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.web.notification
+
+import com.google.common.eventbus.*
+import net.pterodactylus.sone.main.*
+import net.pterodactylus.util.notify.*
+import javax.inject.*
+
+/**
+ * Handler for notifications that can create notifications and register them with an event bus.
+ */
+@Suppress("UnstableApiUsage")
+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)
+ }
+
+}
Notification.SoneIsInserting.Text=Ihre Sone sone://{0} wird jetzt hoch geladen.
Notification.SoneIsInserted.Text=Ihre Sone sone://{0} wurde in {1,number} {1,choice,0#Sekunden|1#Sekunde|1<Sekunden} hoch geladen.
Notification.SoneInsertAborted.Text=Ihre Sone sone://{0} konnte nicht hoch geladen werden.
+Notification.SoneLockedOnStartup.Text=Einige Sones wurden beim Starten gesperrt, weil sie keine Inhalte enthielten. Versionen vor v81 hatten einen Fehler, der Sones ohne Inhalte zur Folge hatte. Um zu verhindern, dass solchermaßen defekte Sones hoch geladen werden, wurden sie automatisch gesperrt. Bitte überprüfen Sie Ihre Sones, benutzen Sie den Sonerettungsmodus und entsperren Sie die Sones manuell, wenn Sie mit den Inhalten Ihrer Sones zufrieden sind. Die gesperrten Sones sind:
Notification.SoneIsInserting.Text=Your Sone sone://{0} is now being inserted.
Notification.SoneIsInserted.Text=Your Sone sone://{0} has been inserted in {1,number} {1,choice,0#seconds|1#second|1<seconds}.
Notification.SoneInsertAborted.Text=Your Sone sone://{0} could not be inserted.
+Notification.SoneLockedOnStartup.Text=Some Sones were locked on startup because they don’t contain anything. Versions prior to v81 had a bug that resulted in empty Sones. To prevent buggy Sones from being inserted they have been automatically locked. Please check your Sones, use the Rescue Mode if necessary, and unlock your Sones once you are satisfied with the results. Locked Sones are:
Notification.SoneIsInserting.Text=Tu Sone sone://{0} está siendo insertado.
Notification.SoneIsInserted.Text=Tu Sone sone://{0} ha sido insertado en {1,number} {1,choice,0#segundos|1#segundo|1<segundos}.
Notification.SoneInsertAborted.Text=Tu Sone sone://{0} no pudo ser insertado.
-# 55-61, 324–328, 360
+Notification.SoneLockedOnStartup.Text=Some Sones were locked on startup because they don’t contain anything. Versions prior to v81 had a bug that resulted in empty Sones. To prevent buggy Sones from being inserted they have been automatically locked. Please check your Sones, use the Rescue Mode if necessary, and unlock your Sones once you are satisfied with the results. Locked Sones are:
+# 55-61, 324–328, 360, 464
Notification.SoneIsInserting.Text=Votre Sone sone://{0} va maintenant être inséré.
Notification.SoneIsInserted.Text=votre Sone sone://{0} a été inséré dans {1,number} {1,choice,0#seconds|1#second|1<seconds}.
Notification.SoneInsertAborted.Text=Votre Sone sone://{0} ne peut pas être inséré.
-# 55-61, 324–328, 360
+Notification.SoneLockedOnStartup.Text=Some Sones were locked on startup because they don’t contain anything. Versions prior to v81 had a bug that resulted in empty Sones. To prevent buggy Sones from being inserted they have been automatically locked. Please check your Sones, use the Rescue Mode if necessary, and unlock your Sones once you are satisfied with the results. Locked Sones are:
+# 55-61, 324–328, 360, 464
Notification.SoneIsInserting.Text=あなたのSone sone://{0}は現在インサート中です。
Notification.SoneIsInserted.Text=あなたのSone sone://{0}は{1,number}{1,choice,0#秒|1#秒|1<秒}でインサートされました。
Notification.SoneInsertAborted.Text=あなたのSone sone://{0}のインサートに失敗しました。
-# 55-51, 67, 103, 324–328, 360, 455
+Notification.SoneLockedOnStartup.Text=Some Sones were locked on startup because they don’t contain anything. Versions prior to v81 had a bug that resulted in empty Sones. To prevent buggy Sones from being inserted they have been automatically locked. Please check your Sones, use the Rescue Mode if necessary, and unlock your Sones once you are satisfied with the results. Locked Sones are:
+# 55-51, 67, 103, 324–328, 360, 455, 464
Notification.SoneIsInserting.Text=Your Sone sone://{0} is now being inserted.
Notification.SoneIsInserted.Text=Your Sone sone://{0} has been inserted in {1,number} {1,choice,0#seconds|1#second|1<seconds}.
Notification.SoneInsertAborted.Text=Your Sone sone://{0} could not be inserted.
-# 55-61, 67, 103, 123-124, 305-307, 309-311, 324–328, 360, 455, 461-463
+Notification.SoneLockedOnStartup.Text=Some Sones were locked on startup because they don’t contain anything. Versions prior to v81 had a bug that resulted in empty Sones. To prevent buggy Sones from being inserted they have been automatically locked. Please check your Sones, use the Rescue Mode if necessary, and unlock your Sones once you are satisfied with the results. Locked Sones are:
+# 55-61, 67, 103, 123-124, 305-307, 309-311, 324–328, 360, 455, 461-464
Notification.SoneIsInserting.Text=Twoje Sone sone://{0} jest w tej chili wysyłane.
Notification.SoneIsInserted.Text=Twoje sone://{0} zostało wysłane w {1,number} {1,choice,0#seconds|1#second|1<seconds}.
Notification.SoneInsertAborted.Text=Twoje Sone sone://{0} nie mogło zostać wysłane.
-# 55-61, 324–328, 360, 455
+Notification.SoneLockedOnStartup.Text=Some Sones were locked on startup because they don’t contain anything. Versions prior to v81 had a bug that resulted in empty Sones. To prevent buggy Sones from being inserted they have been automatically locked. Please check your Sones, use the Rescue Mode if necessary, and unlock your Sones once you are satisfied with the results. Locked Sones are:
+# 55-61, 324–328, 360, 455, 464
Notification.SoneIsInserting.Text=Your Sone sone://{0} is now being inserted.
Notification.SoneIsInserted.Text=Your Sone sone://{0} has been inserted in {1,number} {1,choice,0#seconds|1#second|1<seconds}.
Notification.SoneInsertAborted.Text=Your Sone sone://{0} could not be inserted.
-# 55-61, 67, 103, 123-124, 305-307, 309-311, 324–328, 360, 455, 461-463
+Notification.SoneLockedOnStartup.Text=Some Sones were locked on startup because they don’t contain anything. Versions prior to v81 had a bug that resulted in empty Sones. To prevent buggy Sones from being inserted they have been automatically locked. Please check your Sones, use the Rescue Mode if necessary, and unlock your Sones once you are satisfied with the results. Locked Sones are:
+# 55-61, 67, 103, 123-124, 305-307, 309-311, 324–328, 360, 455, 461-464
--- /dev/null
+<div class="text">
+ <%= Notification.SoneLockedOnStartup.Text|l10n|html>
+ <%foreach sones sone>
+ <a href="viewSone.html?sone=<% sone.id|html>" title="<% sone.requestUri|html>"><% sone.niceName|html></a><%notlast>,<%/notlast><%last>.<%/last>
+ <%/foreach>
+</div>
--- /dev/null
+/**
+ * Sone - NotificationHandlerTest.kt - Copyright © 2019 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 <http://www.gnu.org/licenses/>.
+ */
+
+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.*
+import net.pterodactylus.util.notify.*
+import net.pterodactylus.util.template.*
+import net.pterodactylus.util.web.*
+import org.hamcrest.MatcherAssert.*
+import org.hamcrest.Matchers.*
+import kotlin.test.*
+
+/**
+ * Unit test for [NotificationHandler].
+ */
+class NotificationHandlerTest {
+
+ private val eventBus = TestEventBus()
+ private val loaders = TestLoaders()
+ private val notificationManager = NotificationManager()
+ private val handler = NotificationHandler(eventBus, loaders, notificationManager)
+
+ @Test
+ fun `notification handler can be created by guice`() {
+ val injector = createInjector(
+ EventBus::class.isProvidedBy(eventBus),
+ NotificationManager::class.isProvidedBy(notificationManager),
+ Loaders::class.isProvidedBy(loaders)
+ )
+ assertThat(injector.getInstance<NotificationHandler>(), notNullValue())
+ }
+
+ @Test
+ fun `notification handler registers handler for sone-locked event`() {
+ handler.start()
+ assertThat(eventBus.registeredObjects.any { it.javaClass == SoneLockedOnStartupHandler::class.java }, equalTo(true))
+ }
+
+ @Test
+ fun `notification handler loads sone-locked notification template`() {
+ handler.start()
+ assertThat(loaders.requestedTemplatePaths.any { it == "/templates/notify/soneLockedOnStartupNotification.html" }, equalTo(true))
+ }
+
+}
+
+@Suppress("UnstableApiUsage")
+private class TestEventBus : EventBus() {
+ private val _registeredObjects = mutableListOf<Any>()
+ val registeredObjects: List<Any>
+ get() = _registeredObjects
+
+ override fun register(`object`: Any) {
+ super.register(`object`)
+ _registeredObjects += `object`
+ }
+
+}
+
+private class TestLoaders : Loaders {
+ val requestedTemplatePaths = mutableListOf<String>()
+
+ override fun loadTemplate(path: String) =
+ Template().also { requestedTemplatePaths += path }
+
+ override fun <REQ : Request> loadStaticPage(basePath: String, prefix: String, mimeType: String) = object : Page<REQ> {
+
+ override fun getPath() = ""
+ override fun isPrefixPage() = false
+ override fun handleRequest(request: REQ, response: Response) = response
+
+ }
+
+ override fun getTemplateProvider() = TemplateProvider { _, _ -> Template() }
+
+}