🚚 Move kotlin files to correct source path
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Sun, 9 Feb 2020 13:03:41 +0000 (14:03 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Sun, 9 Feb 2020 19:11:06 +0000 (20:11 +0100)
14 files changed:
src/main/java/net/pterodactylus/sone/core/PreferenceChangedEvent.kt [deleted file]
src/main/java/net/pterodactylus/sone/core/PreferencesLoader.kt [deleted file]
src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.kt [deleted file]
src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetector.kt [deleted file]
src/main/java/net/pterodactylus/sone/main/SonePlugin.kt [deleted file]
src/main/java/net/pterodactylus/sone/web/AllPages.kt [deleted file]
src/main/kotlin/net/pterodactylus/sone/core/PreferenceChangedEvent.kt [new file with mode: 0644]
src/main/kotlin/net/pterodactylus/sone/core/PreferencesLoader.kt [new file with mode: 0644]
src/main/kotlin/net/pterodactylus/sone/database/memory/MemoryDatabase.kt [new file with mode: 0644]
src/main/kotlin/net/pterodactylus/sone/freenet/wot/IdentityChangeDetector.kt [new file with mode: 0644]
src/main/kotlin/net/pterodactylus/sone/main/SonePlugin.kt [new file with mode: 0644]
src/main/kotlin/net/pterodactylus/sone/web/AllPages.kt [new file with mode: 0644]
src/test/java/net/pterodactylus/sone/freenet/wot/IdentityManagerTest.kt [deleted file]
src/test/kotlin/net/pterodactylus/sone/freenet/wot/IdentityManagerTest.kt [new file with mode: 0644]

diff --git a/src/main/java/net/pterodactylus/sone/core/PreferenceChangedEvent.kt b/src/main/java/net/pterodactylus/sone/core/PreferenceChangedEvent.kt
deleted file mode 100644 (file)
index 2ebb62d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-package net.pterodactylus.sone.core
-
-data class PreferenceChangedEvent(val preferenceName: String, val newValue: Any)
diff --git a/src/main/java/net/pterodactylus/sone/core/PreferencesLoader.kt b/src/main/java/net/pterodactylus/sone/core/PreferencesLoader.kt
deleted file mode 100644 (file)
index 32c35cb..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-package net.pterodactylus.sone.core
-
-import net.pterodactylus.sone.fcp.FcpInterface.*
-import net.pterodactylus.util.config.*
-
-/**
- * Loads preferences stored in a [Configuration] into a [Preferences] object.
- */
-class PreferencesLoader(private val preferences: Preferences) {
-
-       fun loadFrom(configuration: Configuration) {
-               loadInsertionDelay(configuration)
-               loadPostsPerPage(configuration)
-               loadImagesPerPage(configuration)
-               loadCharactersPerPost(configuration)
-               loadPostCutOffLength(configuration)
-               loadRequireFullAccess(configuration)
-               loadFcpInterfaceActive(configuration)
-               loadFcpFullAccessRequired(configuration)
-       }
-
-       private fun loadInsertionDelay(configuration: Configuration) {
-               preferences.newInsertionDelay = configuration.getIntValue("Option/InsertionDelay").getValue(null)
-       }
-
-       private fun loadPostsPerPage(configuration: Configuration) {
-               preferences.newPostsPerPage = configuration.getIntValue("Option/PostsPerPage").getValue(null)
-       }
-
-       private fun loadImagesPerPage(configuration: Configuration) {
-               preferences.newImagesPerPage = configuration.getIntValue("Option/ImagesPerPage").getValue(null)
-       }
-
-       private fun loadCharactersPerPost(configuration: Configuration) {
-               preferences.newCharactersPerPost = configuration.getIntValue("Option/CharactersPerPost").getValue(null)
-       }
-
-       private fun loadPostCutOffLength(configuration: Configuration) {
-               try {
-                       preferences.newPostCutOffLength = configuration.getIntValue("Option/PostCutOffLength").getValue(null)
-               } catch (iae1: IllegalArgumentException) { /* previous versions allowed -1, ignore and use default. */
-               }
-       }
-
-       private fun loadRequireFullAccess(configuration: Configuration) {
-               preferences.newRequireFullAccess = configuration.getBooleanValue("Option/RequireFullAccess").getValue(null)
-       }
-
-       private fun loadFcpInterfaceActive(configuration: Configuration) {
-               preferences.newFcpInterfaceActive = configuration.getBooleanValue("Option/ActivateFcpInterface").getValue(null)
-       }
-
-       private fun loadFcpFullAccessRequired(configuration: Configuration) {
-               val fullAccessRequiredInteger = configuration.getIntValue("Option/FcpFullAccessRequired").getValue(null)
-               preferences.newFcpFullAccessRequired = fullAccessRequiredInteger?.let { FullAccessRequired.values()[it] }
-       }
-
-}
diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.kt b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.kt
deleted file mode 100644 (file)
index 8722873..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Sone - MemoryDatabase.kt - Copyright Â© 2013–2020 David 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.database.memory
-
-import com.google.common.base.Preconditions.checkNotNull
-import com.google.common.collect.HashMultimap
-import com.google.common.collect.Multimap
-import com.google.common.collect.TreeMultimap
-import com.google.common.util.concurrent.*
-import com.google.inject.Inject
-import com.google.inject.Singleton
-import net.pterodactylus.sone.data.Album
-import net.pterodactylus.sone.data.Image
-import net.pterodactylus.sone.data.Post
-import net.pterodactylus.sone.data.PostReply
-import net.pterodactylus.sone.data.Reply.TIME_COMPARATOR
-import net.pterodactylus.sone.data.Sone
-import net.pterodactylus.sone.data.Sone.toAllAlbums
-import net.pterodactylus.sone.data.Sone.toAllImages
-import net.pterodactylus.sone.data.impl.AlbumBuilderImpl
-import net.pterodactylus.sone.data.impl.ImageBuilderImpl
-import net.pterodactylus.sone.database.AlbumBuilder
-import net.pterodactylus.sone.database.Database
-import net.pterodactylus.sone.database.DatabaseException
-import net.pterodactylus.sone.database.ImageBuilder
-import net.pterodactylus.sone.database.PostBuilder
-import net.pterodactylus.sone.database.PostDatabase
-import net.pterodactylus.sone.database.PostReplyBuilder
-import net.pterodactylus.sone.utils.*
-import net.pterodactylus.util.config.Configuration
-import net.pterodactylus.util.config.ConfigurationException
-import java.util.concurrent.locks.ReentrantReadWriteLock
-import kotlin.concurrent.withLock
-
-/**
- * Memory-based [PostDatabase] implementation.
- */
-@Singleton
-class MemoryDatabase @Inject constructor(private val configuration: Configuration) : AbstractService(), Database {
-
-       private val lock = ReentrantReadWriteLock()
-       private val readLock by lazy { lock.readLock()!! }
-       private val writeLock by lazy { lock.writeLock()!! }
-       private val configurationLoader = ConfigurationLoader(configuration)
-       private val allSones = mutableMapOf<String, Sone>()
-       private val allPosts = mutableMapOf<String, Post>()
-       private val sonePosts: Multimap<String, Post> = HashMultimap.create<String, Post>()
-       private val knownPosts = mutableSetOf<String>()
-       private val allPostReplies = mutableMapOf<String, PostReply>()
-       private val sonePostReplies: Multimap<String, PostReply> = TreeMultimap.create<String, PostReply>(Comparator { leftString, rightString -> leftString.compareTo(rightString) }, TIME_COMPARATOR)
-       private val knownPostReplies = mutableSetOf<String>()
-       private val allAlbums = mutableMapOf<String, Album>()
-       private val soneAlbums: Multimap<String, Album> = HashMultimap.create<String, Album>()
-       private val allImages = mutableMapOf<String, Image>()
-       private val soneImages: Multimap<String, Image> = HashMultimap.create<String, Image>()
-       private val memoryBookmarkDatabase = MemoryBookmarkDatabase(this, configurationLoader)
-       private val memoryFriendDatabase = MemoryFriendDatabase(configurationLoader)
-       private val saveRateLimiter: RateLimiter = RateLimiter.create(1.0)
-       private val saveKnownPostsRateLimiter: RateLimiter = RateLimiter.create(1.0)
-       private val saveKnownPostRepliesRateLimiter: RateLimiter = RateLimiter.create(1.0)
-
-       override val soneLoader get() = this::getSone
-
-       override val sones get() = readLock.withLock { allSones.values.toSet() }
-
-       override val localSones get() = readLock.withLock { allSones.values.filter(Sone::isLocal) }
-
-       override val remoteSones get() = readLock.withLock { allSones.values.filterNot(Sone::isLocal) }
-
-       override val bookmarkedPosts get() = memoryBookmarkDatabase.bookmarkedPosts
-
-       override fun save() {
-               if (saveRateLimiter.tryAcquire()) {
-                       saveKnownPosts()
-                       saveKnownPostReplies()
-               }
-       }
-
-       override fun doStart() {
-               memoryBookmarkDatabase.start()
-               loadKnownPosts()
-               loadKnownPostReplies()
-               notifyStarted()
-       }
-
-       override fun doStop() {
-               try {
-                       memoryBookmarkDatabase.stop()
-                       save()
-                       notifyStopped()
-               } catch (de1: DatabaseException) {
-                       notifyFailed(de1)
-               }
-       }
-
-       override fun newSoneBuilder() = MemorySoneBuilder(this)
-
-       override fun storeSone(sone: Sone) {
-               writeLock.withLock {
-                       removeSone(sone)
-
-                       allSones[sone.id] = sone
-                       sonePosts.putAll(sone.id, sone.posts)
-                       for (post in sone.posts) {
-                               allPosts[post.id] = post
-                       }
-                       sonePostReplies.putAll(sone.id, sone.replies)
-                       for (postReply in sone.replies) {
-                               allPostReplies[postReply.id] = postReply
-                       }
-                       soneAlbums.putAll(sone.id, toAllAlbums.apply(sone)!!)
-                       for (album in toAllAlbums.apply(sone)!!) {
-                               allAlbums[album.id] = album
-                       }
-                       soneImages.putAll(sone.id, toAllImages.apply(sone)!!)
-                       for (image in toAllImages.apply(sone)!!) {
-                               allImages[image.id] = image
-                       }
-               }
-       }
-
-       override fun removeSone(sone: Sone) {
-               writeLock.withLock {
-                       allSones.remove(sone.id)
-                       val removedPosts = sonePosts.removeAll(sone.id)
-                       for (removedPost in removedPosts) {
-                               allPosts.remove(removedPost.id)
-                       }
-                       val removedPostReplies = sonePostReplies.removeAll(sone.id)
-                       for (removedPostReply in removedPostReplies) {
-                               allPostReplies.remove(removedPostReply.id)
-                       }
-                       val removedAlbums = soneAlbums.removeAll(sone.id)
-                       for (removedAlbum in removedAlbums) {
-                               allAlbums.remove(removedAlbum.id)
-                       }
-                       val removedImages = soneImages.removeAll(sone.id)
-                       for (removedImage in removedImages) {
-                               allImages.remove(removedImage.id)
-                       }
-               }
-       }
-
-       override fun getSone(soneId: String) = readLock.withLock { allSones[soneId] }
-
-       override fun getFriends(localSone: Sone): Collection<String> =
-                       if (!localSone.isLocal) {
-                               emptySet()
-                       } else {
-                               memoryFriendDatabase.getFriends(localSone.id)
-                       }
-
-       override fun isFriend(localSone: Sone, friendSoneId: String) =
-                       if (!localSone.isLocal) {
-                               false
-                       } else {
-                               memoryFriendDatabase.isFriend(localSone.id, friendSoneId)
-                       }
-
-       override fun addFriend(localSone: Sone, friendSoneId: String) {
-               if (!localSone.isLocal) {
-                       return
-               }
-               memoryFriendDatabase.addFriend(localSone.id, friendSoneId)
-       }
-
-       override fun removeFriend(localSone: Sone, friendSoneId: String) {
-               if (!localSone.isLocal) {
-                       return
-               }
-               memoryFriendDatabase.removeFriend(localSone.id, friendSoneId)
-       }
-
-       override fun getFollowingTime(friendSoneId: String) =
-                       memoryFriendDatabase.getFollowingTime(friendSoneId)
-
-       override fun getPost(postId: String) =
-                       readLock.withLock { allPosts[postId] }
-
-       override fun getPosts(soneId: String): Collection<Post> =
-                       sonePosts[soneId].toSet()
-
-       override fun getDirectedPosts(recipientId: String) =
-                       readLock.withLock {
-                               allPosts.values.filter {
-                                       it.recipientId.orNull() == recipientId
-                               }
-                       }
-
-       override fun newPostBuilder(): PostBuilder = MemoryPostBuilder(this, this)
-
-       override fun storePost(post: Post) {
-               checkNotNull(post, "post must not be null")
-               writeLock.withLock {
-                       allPosts[post.id] = post
-                       sonePosts[post.sone.id].add(post)
-               }
-       }
-
-       override fun removePost(post: Post) {
-               checkNotNull(post, "post must not be null")
-               writeLock.withLock {
-                       allPosts.remove(post.id)
-                       sonePosts[post.sone.id].remove(post)
-                       post.sone.removePost(post)
-               }
-       }
-
-       override fun getPostReply(id: String) = readLock.withLock { allPostReplies[id] }
-
-       override fun getReplies(postId: String) =
-                       readLock.withLock {
-                               allPostReplies.values
-                                               .filter { it.postId == postId }
-                                               .sortedWith(TIME_COMPARATOR)
-                       }
-
-       override fun newPostReplyBuilder(): PostReplyBuilder =
-                       MemoryPostReplyBuilder(this, this)
-
-       override fun storePostReply(postReply: PostReply) =
-                       writeLock.withLock {
-                               allPostReplies[postReply.id] = postReply
-                       }
-
-       override fun removePostReply(postReply: PostReply) =
-                       writeLock.withLock {
-                               allPostReplies.remove(postReply.id)
-                       }.unit
-
-       override fun getAlbum(albumId: String) = readLock.withLock { allAlbums[albumId] }
-
-       override fun newAlbumBuilder(): AlbumBuilder = AlbumBuilderImpl()
-
-       override fun storeAlbum(album: Album) =
-                       writeLock.withLock {
-                               allAlbums[album.id] = album
-                               soneAlbums.put(album.sone.id, album)
-                       }.unit
-
-       override fun removeAlbum(album: Album) =
-                       writeLock.withLock {
-                               allAlbums.remove(album.id)
-                               soneAlbums.remove(album.sone.id, album)
-                       }.unit
-
-       override fun getImage(imageId: String) = readLock.withLock { allImages[imageId] }
-
-       override fun newImageBuilder(): ImageBuilder = ImageBuilderImpl()
-
-       override fun storeImage(image: Image): Unit =
-                       writeLock.withLock {
-                               allImages[image.id] = image
-                               soneImages.put(image.sone.id, image)
-                       }
-
-       override fun removeImage(image: Image): Unit =
-                       writeLock.withLock {
-                               allImages.remove(image.id)
-                               soneImages.remove(image.sone.id, image)
-                       }
-
-       override fun bookmarkPost(post: Post) =
-                       memoryBookmarkDatabase.bookmarkPost(post)
-
-       override fun unbookmarkPost(post: Post) =
-                       memoryBookmarkDatabase.unbookmarkPost(post)
-
-       override fun isPostBookmarked(post: Post) =
-                       memoryBookmarkDatabase.isPostBookmarked(post)
-
-       protected fun isPostKnown(post: Post) = readLock.withLock { post.id in knownPosts }
-
-       fun setPostKnown(post: Post, known: Boolean): Unit =
-                       writeLock.withLock {
-                               if (known)
-                                       knownPosts.add(post.id)
-                               else
-                                       knownPosts.remove(post.id)
-                               saveKnownPosts()
-                       }
-
-       protected fun isPostReplyKnown(postReply: PostReply) = readLock.withLock { postReply.id in knownPostReplies }
-
-       fun setPostReplyKnown(postReply: PostReply, known: Boolean): Unit =
-                       writeLock.withLock {
-                               if (known)
-                                       knownPostReplies.add(postReply.id)
-                               else
-                                       knownPostReplies.remove(postReply.id)
-                               saveKnownPostReplies()
-                       }
-
-       private fun loadKnownPosts() =
-                       configurationLoader.loadKnownPosts()
-                                       .let {
-                                               writeLock.withLock {
-                                                       knownPosts.clear()
-                                                       knownPosts.addAll(it)
-                                               }
-                                       }
-
-       private fun saveKnownPosts() =
-                       saveKnownPostsRateLimiter.tryAcquire().ifTrue {
-                               try {
-                                       readLock.withLock {
-                                               knownPosts.forEachIndexed { index, knownPostId ->
-                                                       configuration.getStringValue("KnownPosts/$index/ID").value = knownPostId
-                                               }
-                                               configuration.getStringValue("KnownPosts/${knownPosts.size}/ID").value = null
-                                       }
-                               } catch (ce1: ConfigurationException) {
-                                       throw DatabaseException("Could not save database.", ce1)
-                               }
-                       }
-
-       private fun loadKnownPostReplies(): Unit =
-                       configurationLoader.loadKnownPostReplies().let { knownPostReplies ->
-                               writeLock.withLock {
-                                       this.knownPostReplies.clear()
-                                       this.knownPostReplies.addAll(knownPostReplies)
-                               }
-                       }
-
-       private fun saveKnownPostReplies() =
-                       saveKnownPostRepliesRateLimiter.tryAcquire().ifTrue {
-                               try {
-                                       readLock.withLock {
-                                               knownPostReplies.forEachIndexed { index, knownPostReply ->
-                                                       configuration.getStringValue("KnownReplies/$index/ID").value = knownPostReply
-                                               }
-                                               configuration.getStringValue("KnownReplies/${knownPostReplies.size}/ID").value = null
-                                       }
-                               } catch (ce1: ConfigurationException) {
-                                       throw DatabaseException("Could not save database.", ce1)
-                               }
-                       }
-
-}
diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetector.kt b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetector.kt
deleted file mode 100644 (file)
index ffcafb3..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Sone - IdentityChangeDetector.kt - Copyright Â© 2013–2020 David 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.freenet.wot
-
-/**
- * Detects changes between two lists of [Identity]s. The detector can find
- * added and removed identities, and for identities that exist in both list
- * their contexts and properties are checked for added, removed, or (in case of
- * properties) changed values.
- */
-class IdentityChangeDetector(oldIdentities: Collection<Identity>) {
-
-       private val oldIdentities: Map<String, Identity> = oldIdentities.associateBy { it.id }
-       var onNewIdentity: IdentityProcessor? = null
-       var onRemovedIdentity: IdentityProcessor? = null
-       var onChangedIdentity: IdentityProcessor? = null
-       var onUnchangedIdentity: IdentityProcessor? = null
-
-       fun detectChanges(newIdentities: Collection<Identity>) {
-               onRemovedIdentity.notify(oldIdentities.values.filter { it !in newIdentities })
-               onNewIdentity.notify(newIdentities.filter { it !in oldIdentities.values })
-               onChangedIdentity.notify(newIdentities.filter { it.id in oldIdentities }.filter { identityHasChanged(oldIdentities[it.id]!!, it) })
-               onUnchangedIdentity.notify(newIdentities.filter { it.id in oldIdentities }.filterNot { identityHasChanged(oldIdentities[it.id]!!, it) })
-       }
-
-       private fun identityHasChanged(oldIdentity: Identity, newIdentity: Identity?) =
-                       identityHasNewContexts(oldIdentity, newIdentity!!)
-                                       || identityHasRemovedContexts(oldIdentity, newIdentity)
-                                       || identityHasNewProperties(oldIdentity, newIdentity)
-                                       || identityHasRemovedProperties(oldIdentity, newIdentity)
-                                       || identityHasChangedProperties(oldIdentity, newIdentity)
-
-       private fun identityHasNewContexts(oldIdentity: Identity, newIdentity: Identity) =
-                       newIdentity.contexts.any { it !in oldIdentity.contexts }
-
-       private fun identityHasRemovedContexts(oldIdentity: Identity, newIdentity: Identity) =
-                       oldIdentity.contexts.any { it !in newIdentity.contexts }
-
-       private fun identityHasNewProperties(oldIdentity: Identity, newIdentity: Identity) =
-                       newIdentity.properties.keys.any { it !in oldIdentity.properties }
-
-       private fun identityHasRemovedProperties(oldIdentity: Identity, newIdentity: Identity) =
-                       oldIdentity.properties.keys.any { it !in newIdentity.properties }
-
-       private fun identityHasChangedProperties(oldIdentity: Identity, newIdentity: Identity) =
-                       oldIdentity.properties.entries.any { newIdentity.properties[it.key] != it.value }
-
-}
-
-typealias IdentityProcessor = (Identity) -> Unit
-
-private fun IdentityProcessor?.notify(identities: Iterable<Identity>) =
-               this?.let { identities.forEach(this::invoke) }
diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.kt b/src/main/java/net/pterodactylus/sone/main/SonePlugin.kt
deleted file mode 100644 (file)
index 5e0b2c1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.pterodactylus.sone.main
-
-data class PluginVersion(val version: String)
-
-data class PluginYear(val year: Int)
-
-data class PluginHomepage(val homepage: String)
diff --git a/src/main/java/net/pterodactylus/sone/web/AllPages.kt b/src/main/java/net/pterodactylus/sone/web/AllPages.kt
deleted file mode 100644 (file)
index c538f0e..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-package net.pterodactylus.sone.web
-
-import net.pterodactylus.sone.web.pages.*
-import javax.inject.Inject
-
-/**
- * Container for all web pages. This uses field injection because there are way too many pages
- * to sensibly use constructor injection.
- */
-class AllPages {
-
-       @Inject lateinit var aboutPage: AboutPage
-       @Inject lateinit var bookmarkPage: BookmarkPage
-       @Inject lateinit var bookmarksPage: BookmarksPage
-       @Inject lateinit var createAlbumPage: CreateAlbumPage
-       @Inject lateinit var createPostPage: CreatePostPage
-       @Inject lateinit var createReplyPage: CreateReplyPage
-       @Inject lateinit var createSonePage: CreateSonePage
-       @Inject lateinit var deleteAlbumPage: DeleteAlbumPage
-       @Inject lateinit var deleteImagePage: DeleteImagePage
-       @Inject lateinit var deletePostPage: DeletePostPage
-       @Inject lateinit var deleteProfileFieldPage: DeleteProfileFieldPage
-       @Inject lateinit var deleteReplyPage: DeleteReplyPage
-       @Inject lateinit var deleteSonePage: DeleteSonePage
-       @Inject lateinit var dismissNotificationPage: DismissNotificationPage
-       @Inject lateinit var editAlbumPage: EditAlbumPage
-       @Inject lateinit var editImagePage: EditImagePage
-       @Inject lateinit var editProfileFieldPage: EditProfileFieldPage
-       @Inject lateinit var editProfilePage: EditProfilePage
-       @Inject lateinit var followSonePage: FollowSonePage
-       @Inject lateinit var getImagePage: GetImagePage
-       @Inject lateinit var imageBrowserPage: ImageBrowserPage
-       @Inject lateinit var indexPage: IndexPage
-       @Inject lateinit var knownSonesPage: KnownSonesPage
-       @Inject lateinit var likePage: LikePage
-       @Inject lateinit var lockSonePage: LockSonePage
-       @Inject lateinit var loginPage: LoginPage
-       @Inject lateinit var logoutPage: LogoutPage
-       @Inject lateinit var markAsKnownPage: MarkAsKnownPage
-       @Inject lateinit var newPage: NewPage
-       @Inject lateinit var optionsPage: OptionsPage
-       @Inject lateinit var rescuePage: RescuePage
-       @Inject lateinit var searchPage: SearchPage
-       @Inject lateinit var unbookmarkPage: UnbookmarkPage
-       @Inject lateinit var unfollowSonePage: UnfollowSonePage
-       @Inject lateinit var unlikePage: UnlikePage
-       @Inject lateinit var unlockSonePage: UnlockSonePage
-       @Inject lateinit var uploadImagePage: UploadImagePage
-       @Inject lateinit var viewPostPage: ViewPostPage
-       @Inject lateinit var viewSonePage: ViewSonePage
-
-}
diff --git a/src/main/kotlin/net/pterodactylus/sone/core/PreferenceChangedEvent.kt b/src/main/kotlin/net/pterodactylus/sone/core/PreferenceChangedEvent.kt
new file mode 100644 (file)
index 0000000..2ebb62d
--- /dev/null
@@ -0,0 +1,3 @@
+package net.pterodactylus.sone.core
+
+data class PreferenceChangedEvent(val preferenceName: String, val newValue: Any)
diff --git a/src/main/kotlin/net/pterodactylus/sone/core/PreferencesLoader.kt b/src/main/kotlin/net/pterodactylus/sone/core/PreferencesLoader.kt
new file mode 100644 (file)
index 0000000..32c35cb
--- /dev/null
@@ -0,0 +1,58 @@
+package net.pterodactylus.sone.core
+
+import net.pterodactylus.sone.fcp.FcpInterface.*
+import net.pterodactylus.util.config.*
+
+/**
+ * Loads preferences stored in a [Configuration] into a [Preferences] object.
+ */
+class PreferencesLoader(private val preferences: Preferences) {
+
+       fun loadFrom(configuration: Configuration) {
+               loadInsertionDelay(configuration)
+               loadPostsPerPage(configuration)
+               loadImagesPerPage(configuration)
+               loadCharactersPerPost(configuration)
+               loadPostCutOffLength(configuration)
+               loadRequireFullAccess(configuration)
+               loadFcpInterfaceActive(configuration)
+               loadFcpFullAccessRequired(configuration)
+       }
+
+       private fun loadInsertionDelay(configuration: Configuration) {
+               preferences.newInsertionDelay = configuration.getIntValue("Option/InsertionDelay").getValue(null)
+       }
+
+       private fun loadPostsPerPage(configuration: Configuration) {
+               preferences.newPostsPerPage = configuration.getIntValue("Option/PostsPerPage").getValue(null)
+       }
+
+       private fun loadImagesPerPage(configuration: Configuration) {
+               preferences.newImagesPerPage = configuration.getIntValue("Option/ImagesPerPage").getValue(null)
+       }
+
+       private fun loadCharactersPerPost(configuration: Configuration) {
+               preferences.newCharactersPerPost = configuration.getIntValue("Option/CharactersPerPost").getValue(null)
+       }
+
+       private fun loadPostCutOffLength(configuration: Configuration) {
+               try {
+                       preferences.newPostCutOffLength = configuration.getIntValue("Option/PostCutOffLength").getValue(null)
+               } catch (iae1: IllegalArgumentException) { /* previous versions allowed -1, ignore and use default. */
+               }
+       }
+
+       private fun loadRequireFullAccess(configuration: Configuration) {
+               preferences.newRequireFullAccess = configuration.getBooleanValue("Option/RequireFullAccess").getValue(null)
+       }
+
+       private fun loadFcpInterfaceActive(configuration: Configuration) {
+               preferences.newFcpInterfaceActive = configuration.getBooleanValue("Option/ActivateFcpInterface").getValue(null)
+       }
+
+       private fun loadFcpFullAccessRequired(configuration: Configuration) {
+               val fullAccessRequiredInteger = configuration.getIntValue("Option/FcpFullAccessRequired").getValue(null)
+               preferences.newFcpFullAccessRequired = fullAccessRequiredInteger?.let { FullAccessRequired.values()[it] }
+       }
+
+}
diff --git a/src/main/kotlin/net/pterodactylus/sone/database/memory/MemoryDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/memory/MemoryDatabase.kt
new file mode 100644 (file)
index 0000000..8722873
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Sone - MemoryDatabase.kt - Copyright Â© 2013–2020 David 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.database.memory
+
+import com.google.common.base.Preconditions.checkNotNull
+import com.google.common.collect.HashMultimap
+import com.google.common.collect.Multimap
+import com.google.common.collect.TreeMultimap
+import com.google.common.util.concurrent.*
+import com.google.inject.Inject
+import com.google.inject.Singleton
+import net.pterodactylus.sone.data.Album
+import net.pterodactylus.sone.data.Image
+import net.pterodactylus.sone.data.Post
+import net.pterodactylus.sone.data.PostReply
+import net.pterodactylus.sone.data.Reply.TIME_COMPARATOR
+import net.pterodactylus.sone.data.Sone
+import net.pterodactylus.sone.data.Sone.toAllAlbums
+import net.pterodactylus.sone.data.Sone.toAllImages
+import net.pterodactylus.sone.data.impl.AlbumBuilderImpl
+import net.pterodactylus.sone.data.impl.ImageBuilderImpl
+import net.pterodactylus.sone.database.AlbumBuilder
+import net.pterodactylus.sone.database.Database
+import net.pterodactylus.sone.database.DatabaseException
+import net.pterodactylus.sone.database.ImageBuilder
+import net.pterodactylus.sone.database.PostBuilder
+import net.pterodactylus.sone.database.PostDatabase
+import net.pterodactylus.sone.database.PostReplyBuilder
+import net.pterodactylus.sone.utils.*
+import net.pterodactylus.util.config.Configuration
+import net.pterodactylus.util.config.ConfigurationException
+import java.util.concurrent.locks.ReentrantReadWriteLock
+import kotlin.concurrent.withLock
+
+/**
+ * Memory-based [PostDatabase] implementation.
+ */
+@Singleton
+class MemoryDatabase @Inject constructor(private val configuration: Configuration) : AbstractService(), Database {
+
+       private val lock = ReentrantReadWriteLock()
+       private val readLock by lazy { lock.readLock()!! }
+       private val writeLock by lazy { lock.writeLock()!! }
+       private val configurationLoader = ConfigurationLoader(configuration)
+       private val allSones = mutableMapOf<String, Sone>()
+       private val allPosts = mutableMapOf<String, Post>()
+       private val sonePosts: Multimap<String, Post> = HashMultimap.create<String, Post>()
+       private val knownPosts = mutableSetOf<String>()
+       private val allPostReplies = mutableMapOf<String, PostReply>()
+       private val sonePostReplies: Multimap<String, PostReply> = TreeMultimap.create<String, PostReply>(Comparator { leftString, rightString -> leftString.compareTo(rightString) }, TIME_COMPARATOR)
+       private val knownPostReplies = mutableSetOf<String>()
+       private val allAlbums = mutableMapOf<String, Album>()
+       private val soneAlbums: Multimap<String, Album> = HashMultimap.create<String, Album>()
+       private val allImages = mutableMapOf<String, Image>()
+       private val soneImages: Multimap<String, Image> = HashMultimap.create<String, Image>()
+       private val memoryBookmarkDatabase = MemoryBookmarkDatabase(this, configurationLoader)
+       private val memoryFriendDatabase = MemoryFriendDatabase(configurationLoader)
+       private val saveRateLimiter: RateLimiter = RateLimiter.create(1.0)
+       private val saveKnownPostsRateLimiter: RateLimiter = RateLimiter.create(1.0)
+       private val saveKnownPostRepliesRateLimiter: RateLimiter = RateLimiter.create(1.0)
+
+       override val soneLoader get() = this::getSone
+
+       override val sones get() = readLock.withLock { allSones.values.toSet() }
+
+       override val localSones get() = readLock.withLock { allSones.values.filter(Sone::isLocal) }
+
+       override val remoteSones get() = readLock.withLock { allSones.values.filterNot(Sone::isLocal) }
+
+       override val bookmarkedPosts get() = memoryBookmarkDatabase.bookmarkedPosts
+
+       override fun save() {
+               if (saveRateLimiter.tryAcquire()) {
+                       saveKnownPosts()
+                       saveKnownPostReplies()
+               }
+       }
+
+       override fun doStart() {
+               memoryBookmarkDatabase.start()
+               loadKnownPosts()
+               loadKnownPostReplies()
+               notifyStarted()
+       }
+
+       override fun doStop() {
+               try {
+                       memoryBookmarkDatabase.stop()
+                       save()
+                       notifyStopped()
+               } catch (de1: DatabaseException) {
+                       notifyFailed(de1)
+               }
+       }
+
+       override fun newSoneBuilder() = MemorySoneBuilder(this)
+
+       override fun storeSone(sone: Sone) {
+               writeLock.withLock {
+                       removeSone(sone)
+
+                       allSones[sone.id] = sone
+                       sonePosts.putAll(sone.id, sone.posts)
+                       for (post in sone.posts) {
+                               allPosts[post.id] = post
+                       }
+                       sonePostReplies.putAll(sone.id, sone.replies)
+                       for (postReply in sone.replies) {
+                               allPostReplies[postReply.id] = postReply
+                       }
+                       soneAlbums.putAll(sone.id, toAllAlbums.apply(sone)!!)
+                       for (album in toAllAlbums.apply(sone)!!) {
+                               allAlbums[album.id] = album
+                       }
+                       soneImages.putAll(sone.id, toAllImages.apply(sone)!!)
+                       for (image in toAllImages.apply(sone)!!) {
+                               allImages[image.id] = image
+                       }
+               }
+       }
+
+       override fun removeSone(sone: Sone) {
+               writeLock.withLock {
+                       allSones.remove(sone.id)
+                       val removedPosts = sonePosts.removeAll(sone.id)
+                       for (removedPost in removedPosts) {
+                               allPosts.remove(removedPost.id)
+                       }
+                       val removedPostReplies = sonePostReplies.removeAll(sone.id)
+                       for (removedPostReply in removedPostReplies) {
+                               allPostReplies.remove(removedPostReply.id)
+                       }
+                       val removedAlbums = soneAlbums.removeAll(sone.id)
+                       for (removedAlbum in removedAlbums) {
+                               allAlbums.remove(removedAlbum.id)
+                       }
+                       val removedImages = soneImages.removeAll(sone.id)
+                       for (removedImage in removedImages) {
+                               allImages.remove(removedImage.id)
+                       }
+               }
+       }
+
+       override fun getSone(soneId: String) = readLock.withLock { allSones[soneId] }
+
+       override fun getFriends(localSone: Sone): Collection<String> =
+                       if (!localSone.isLocal) {
+                               emptySet()
+                       } else {
+                               memoryFriendDatabase.getFriends(localSone.id)
+                       }
+
+       override fun isFriend(localSone: Sone, friendSoneId: String) =
+                       if (!localSone.isLocal) {
+                               false
+                       } else {
+                               memoryFriendDatabase.isFriend(localSone.id, friendSoneId)
+                       }
+
+       override fun addFriend(localSone: Sone, friendSoneId: String) {
+               if (!localSone.isLocal) {
+                       return
+               }
+               memoryFriendDatabase.addFriend(localSone.id, friendSoneId)
+       }
+
+       override fun removeFriend(localSone: Sone, friendSoneId: String) {
+               if (!localSone.isLocal) {
+                       return
+               }
+               memoryFriendDatabase.removeFriend(localSone.id, friendSoneId)
+       }
+
+       override fun getFollowingTime(friendSoneId: String) =
+                       memoryFriendDatabase.getFollowingTime(friendSoneId)
+
+       override fun getPost(postId: String) =
+                       readLock.withLock { allPosts[postId] }
+
+       override fun getPosts(soneId: String): Collection<Post> =
+                       sonePosts[soneId].toSet()
+
+       override fun getDirectedPosts(recipientId: String) =
+                       readLock.withLock {
+                               allPosts.values.filter {
+                                       it.recipientId.orNull() == recipientId
+                               }
+                       }
+
+       override fun newPostBuilder(): PostBuilder = MemoryPostBuilder(this, this)
+
+       override fun storePost(post: Post) {
+               checkNotNull(post, "post must not be null")
+               writeLock.withLock {
+                       allPosts[post.id] = post
+                       sonePosts[post.sone.id].add(post)
+               }
+       }
+
+       override fun removePost(post: Post) {
+               checkNotNull(post, "post must not be null")
+               writeLock.withLock {
+                       allPosts.remove(post.id)
+                       sonePosts[post.sone.id].remove(post)
+                       post.sone.removePost(post)
+               }
+       }
+
+       override fun getPostReply(id: String) = readLock.withLock { allPostReplies[id] }
+
+       override fun getReplies(postId: String) =
+                       readLock.withLock {
+                               allPostReplies.values
+                                               .filter { it.postId == postId }
+                                               .sortedWith(TIME_COMPARATOR)
+                       }
+
+       override fun newPostReplyBuilder(): PostReplyBuilder =
+                       MemoryPostReplyBuilder(this, this)
+
+       override fun storePostReply(postReply: PostReply) =
+                       writeLock.withLock {
+                               allPostReplies[postReply.id] = postReply
+                       }
+
+       override fun removePostReply(postReply: PostReply) =
+                       writeLock.withLock {
+                               allPostReplies.remove(postReply.id)
+                       }.unit
+
+       override fun getAlbum(albumId: String) = readLock.withLock { allAlbums[albumId] }
+
+       override fun newAlbumBuilder(): AlbumBuilder = AlbumBuilderImpl()
+
+       override fun storeAlbum(album: Album) =
+                       writeLock.withLock {
+                               allAlbums[album.id] = album
+                               soneAlbums.put(album.sone.id, album)
+                       }.unit
+
+       override fun removeAlbum(album: Album) =
+                       writeLock.withLock {
+                               allAlbums.remove(album.id)
+                               soneAlbums.remove(album.sone.id, album)
+                       }.unit
+
+       override fun getImage(imageId: String) = readLock.withLock { allImages[imageId] }
+
+       override fun newImageBuilder(): ImageBuilder = ImageBuilderImpl()
+
+       override fun storeImage(image: Image): Unit =
+                       writeLock.withLock {
+                               allImages[image.id] = image
+                               soneImages.put(image.sone.id, image)
+                       }
+
+       override fun removeImage(image: Image): Unit =
+                       writeLock.withLock {
+                               allImages.remove(image.id)
+                               soneImages.remove(image.sone.id, image)
+                       }
+
+       override fun bookmarkPost(post: Post) =
+                       memoryBookmarkDatabase.bookmarkPost(post)
+
+       override fun unbookmarkPost(post: Post) =
+                       memoryBookmarkDatabase.unbookmarkPost(post)
+
+       override fun isPostBookmarked(post: Post) =
+                       memoryBookmarkDatabase.isPostBookmarked(post)
+
+       protected fun isPostKnown(post: Post) = readLock.withLock { post.id in knownPosts }
+
+       fun setPostKnown(post: Post, known: Boolean): Unit =
+                       writeLock.withLock {
+                               if (known)
+                                       knownPosts.add(post.id)
+                               else
+                                       knownPosts.remove(post.id)
+                               saveKnownPosts()
+                       }
+
+       protected fun isPostReplyKnown(postReply: PostReply) = readLock.withLock { postReply.id in knownPostReplies }
+
+       fun setPostReplyKnown(postReply: PostReply, known: Boolean): Unit =
+                       writeLock.withLock {
+                               if (known)
+                                       knownPostReplies.add(postReply.id)
+                               else
+                                       knownPostReplies.remove(postReply.id)
+                               saveKnownPostReplies()
+                       }
+
+       private fun loadKnownPosts() =
+                       configurationLoader.loadKnownPosts()
+                                       .let {
+                                               writeLock.withLock {
+                                                       knownPosts.clear()
+                                                       knownPosts.addAll(it)
+                                               }
+                                       }
+
+       private fun saveKnownPosts() =
+                       saveKnownPostsRateLimiter.tryAcquire().ifTrue {
+                               try {
+                                       readLock.withLock {
+                                               knownPosts.forEachIndexed { index, knownPostId ->
+                                                       configuration.getStringValue("KnownPosts/$index/ID").value = knownPostId
+                                               }
+                                               configuration.getStringValue("KnownPosts/${knownPosts.size}/ID").value = null
+                                       }
+                               } catch (ce1: ConfigurationException) {
+                                       throw DatabaseException("Could not save database.", ce1)
+                               }
+                       }
+
+       private fun loadKnownPostReplies(): Unit =
+                       configurationLoader.loadKnownPostReplies().let { knownPostReplies ->
+                               writeLock.withLock {
+                                       this.knownPostReplies.clear()
+                                       this.knownPostReplies.addAll(knownPostReplies)
+                               }
+                       }
+
+       private fun saveKnownPostReplies() =
+                       saveKnownPostRepliesRateLimiter.tryAcquire().ifTrue {
+                               try {
+                                       readLock.withLock {
+                                               knownPostReplies.forEachIndexed { index, knownPostReply ->
+                                                       configuration.getStringValue("KnownReplies/$index/ID").value = knownPostReply
+                                               }
+                                               configuration.getStringValue("KnownReplies/${knownPostReplies.size}/ID").value = null
+                                       }
+                               } catch (ce1: ConfigurationException) {
+                                       throw DatabaseException("Could not save database.", ce1)
+                               }
+                       }
+
+}
diff --git a/src/main/kotlin/net/pterodactylus/sone/freenet/wot/IdentityChangeDetector.kt b/src/main/kotlin/net/pterodactylus/sone/freenet/wot/IdentityChangeDetector.kt
new file mode 100644 (file)
index 0000000..ffcafb3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Sone - IdentityChangeDetector.kt - Copyright Â© 2013–2020 David 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.freenet.wot
+
+/**
+ * Detects changes between two lists of [Identity]s. The detector can find
+ * added and removed identities, and for identities that exist in both list
+ * their contexts and properties are checked for added, removed, or (in case of
+ * properties) changed values.
+ */
+class IdentityChangeDetector(oldIdentities: Collection<Identity>) {
+
+       private val oldIdentities: Map<String, Identity> = oldIdentities.associateBy { it.id }
+       var onNewIdentity: IdentityProcessor? = null
+       var onRemovedIdentity: IdentityProcessor? = null
+       var onChangedIdentity: IdentityProcessor? = null
+       var onUnchangedIdentity: IdentityProcessor? = null
+
+       fun detectChanges(newIdentities: Collection<Identity>) {
+               onRemovedIdentity.notify(oldIdentities.values.filter { it !in newIdentities })
+               onNewIdentity.notify(newIdentities.filter { it !in oldIdentities.values })
+               onChangedIdentity.notify(newIdentities.filter { it.id in oldIdentities }.filter { identityHasChanged(oldIdentities[it.id]!!, it) })
+               onUnchangedIdentity.notify(newIdentities.filter { it.id in oldIdentities }.filterNot { identityHasChanged(oldIdentities[it.id]!!, it) })
+       }
+
+       private fun identityHasChanged(oldIdentity: Identity, newIdentity: Identity?) =
+                       identityHasNewContexts(oldIdentity, newIdentity!!)
+                                       || identityHasRemovedContexts(oldIdentity, newIdentity)
+                                       || identityHasNewProperties(oldIdentity, newIdentity)
+                                       || identityHasRemovedProperties(oldIdentity, newIdentity)
+                                       || identityHasChangedProperties(oldIdentity, newIdentity)
+
+       private fun identityHasNewContexts(oldIdentity: Identity, newIdentity: Identity) =
+                       newIdentity.contexts.any { it !in oldIdentity.contexts }
+
+       private fun identityHasRemovedContexts(oldIdentity: Identity, newIdentity: Identity) =
+                       oldIdentity.contexts.any { it !in newIdentity.contexts }
+
+       private fun identityHasNewProperties(oldIdentity: Identity, newIdentity: Identity) =
+                       newIdentity.properties.keys.any { it !in oldIdentity.properties }
+
+       private fun identityHasRemovedProperties(oldIdentity: Identity, newIdentity: Identity) =
+                       oldIdentity.properties.keys.any { it !in newIdentity.properties }
+
+       private fun identityHasChangedProperties(oldIdentity: Identity, newIdentity: Identity) =
+                       oldIdentity.properties.entries.any { newIdentity.properties[it.key] != it.value }
+
+}
+
+typealias IdentityProcessor = (Identity) -> Unit
+
+private fun IdentityProcessor?.notify(identities: Iterable<Identity>) =
+               this?.let { identities.forEach(this::invoke) }
diff --git a/src/main/kotlin/net/pterodactylus/sone/main/SonePlugin.kt b/src/main/kotlin/net/pterodactylus/sone/main/SonePlugin.kt
new file mode 100644 (file)
index 0000000..5e0b2c1
--- /dev/null
@@ -0,0 +1,7 @@
+package net.pterodactylus.sone.main
+
+data class PluginVersion(val version: String)
+
+data class PluginYear(val year: Int)
+
+data class PluginHomepage(val homepage: String)
diff --git a/src/main/kotlin/net/pterodactylus/sone/web/AllPages.kt b/src/main/kotlin/net/pterodactylus/sone/web/AllPages.kt
new file mode 100644 (file)
index 0000000..c538f0e
--- /dev/null
@@ -0,0 +1,52 @@
+package net.pterodactylus.sone.web
+
+import net.pterodactylus.sone.web.pages.*
+import javax.inject.Inject
+
+/**
+ * Container for all web pages. This uses field injection because there are way too many pages
+ * to sensibly use constructor injection.
+ */
+class AllPages {
+
+       @Inject lateinit var aboutPage: AboutPage
+       @Inject lateinit var bookmarkPage: BookmarkPage
+       @Inject lateinit var bookmarksPage: BookmarksPage
+       @Inject lateinit var createAlbumPage: CreateAlbumPage
+       @Inject lateinit var createPostPage: CreatePostPage
+       @Inject lateinit var createReplyPage: CreateReplyPage
+       @Inject lateinit var createSonePage: CreateSonePage
+       @Inject lateinit var deleteAlbumPage: DeleteAlbumPage
+       @Inject lateinit var deleteImagePage: DeleteImagePage
+       @Inject lateinit var deletePostPage: DeletePostPage
+       @Inject lateinit var deleteProfileFieldPage: DeleteProfileFieldPage
+       @Inject lateinit var deleteReplyPage: DeleteReplyPage
+       @Inject lateinit var deleteSonePage: DeleteSonePage
+       @Inject lateinit var dismissNotificationPage: DismissNotificationPage
+       @Inject lateinit var editAlbumPage: EditAlbumPage
+       @Inject lateinit var editImagePage: EditImagePage
+       @Inject lateinit var editProfileFieldPage: EditProfileFieldPage
+       @Inject lateinit var editProfilePage: EditProfilePage
+       @Inject lateinit var followSonePage: FollowSonePage
+       @Inject lateinit var getImagePage: GetImagePage
+       @Inject lateinit var imageBrowserPage: ImageBrowserPage
+       @Inject lateinit var indexPage: IndexPage
+       @Inject lateinit var knownSonesPage: KnownSonesPage
+       @Inject lateinit var likePage: LikePage
+       @Inject lateinit var lockSonePage: LockSonePage
+       @Inject lateinit var loginPage: LoginPage
+       @Inject lateinit var logoutPage: LogoutPage
+       @Inject lateinit var markAsKnownPage: MarkAsKnownPage
+       @Inject lateinit var newPage: NewPage
+       @Inject lateinit var optionsPage: OptionsPage
+       @Inject lateinit var rescuePage: RescuePage
+       @Inject lateinit var searchPage: SearchPage
+       @Inject lateinit var unbookmarkPage: UnbookmarkPage
+       @Inject lateinit var unfollowSonePage: UnfollowSonePage
+       @Inject lateinit var unlikePage: UnlikePage
+       @Inject lateinit var unlockSonePage: UnlockSonePage
+       @Inject lateinit var uploadImagePage: UploadImagePage
+       @Inject lateinit var viewPostPage: ViewPostPage
+       @Inject lateinit var viewSonePage: ViewSonePage
+
+}
diff --git a/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityManagerTest.kt b/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityManagerTest.kt
deleted file mode 100644 (file)
index 3768efd..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-package net.pterodactylus.sone.freenet.wot
-
-import com.google.common.eventbus.*
-import net.pterodactylus.sone.freenet.plugin.*
-import net.pterodactylus.sone.test.*
-import org.hamcrest.MatcherAssert.*
-import org.hamcrest.Matchers.*
-import org.junit.*
-import org.mockito.Mockito.*
-
-/**
- * Unit test for [IdentityManagerImpl].
- */
-class IdentityManagerTest {
-
-       private val eventBus = mock<EventBus>()
-       private val webOfTrustConnector = mock<WebOfTrustConnector>()
-       private val identityManager = IdentityManagerImpl(eventBus, webOfTrustConnector, IdentityLoader(webOfTrustConnector, Context("Test")))
-
-       @Test
-       fun identityManagerPingsWotConnector() {
-               assertThat(identityManager.isConnected, equalTo(true))
-               verify(webOfTrustConnector).ping()
-       }
-
-       @Test
-       fun disconnectedWotConnectorIsRecognized() {
-               doThrow(PluginException::class.java).whenever(webOfTrustConnector).ping()
-               assertThat(identityManager.isConnected, equalTo(false))
-               verify(webOfTrustConnector).ping()
-       }
-
-}
diff --git a/src/test/kotlin/net/pterodactylus/sone/freenet/wot/IdentityManagerTest.kt b/src/test/kotlin/net/pterodactylus/sone/freenet/wot/IdentityManagerTest.kt
new file mode 100644 (file)
index 0000000..3768efd
--- /dev/null
@@ -0,0 +1,33 @@
+package net.pterodactylus.sone.freenet.wot
+
+import com.google.common.eventbus.*
+import net.pterodactylus.sone.freenet.plugin.*
+import net.pterodactylus.sone.test.*
+import org.hamcrest.MatcherAssert.*
+import org.hamcrest.Matchers.*
+import org.junit.*
+import org.mockito.Mockito.*
+
+/**
+ * Unit test for [IdentityManagerImpl].
+ */
+class IdentityManagerTest {
+
+       private val eventBus = mock<EventBus>()
+       private val webOfTrustConnector = mock<WebOfTrustConnector>()
+       private val identityManager = IdentityManagerImpl(eventBus, webOfTrustConnector, IdentityLoader(webOfTrustConnector, Context("Test")))
+
+       @Test
+       fun identityManagerPingsWotConnector() {
+               assertThat(identityManager.isConnected, equalTo(true))
+               verify(webOfTrustConnector).ping()
+       }
+
+       @Test
+       fun disconnectedWotConnectorIsRecognized() {
+               doThrow(PluginException::class.java).whenever(webOfTrustConnector).ping()
+               assertThat(identityManager.isConnected, equalTo(false))
+               verify(webOfTrustConnector).ping()
+       }
+
+}